Prezi

Share this prezi

Who can edit:

Present Online

Send the link below via email or IM to invite your audience

Copy

Start the presentation

Start presenting

  • Invited audience will follow you as you navigate and present
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can view together your prezi
  • Learn more about this feature in the manual

Download prezi for:

Present offline on a PC or Mac.

  • Embedded YouTube videos need an active Internet connection to play.
  • Portable prezis are not editable.

Edit and present offline with Prezi Desktop

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

PacketFu by Example

A PacketFu primer, presented at SharkFest 2011
by Tod Beardsley on 13 June 2011

Comments (0)

Please log in to add your comment.

Report abuse

Prezi Transcript

Interface Goals Conversational Interface Inline Docs Interactive Sensible Defaults PacketFu::Utils.whoami? TCPPacket.new >> Utils.whoami? => {:iface=>"eth0", :pcapfile=>"/tmp/out.pcap", :eth_saddr=>"00:26:22:96:0f:07", :eth_src=>"\x00&\"\x96\x0F\a", :ip_saddr=>"192.168.11.70", :ip_src=>3232238406, :ip_src_bin=>"\xC0\xA8\vF", :eth_dst=>"\x00\x1C\x10\xCCW\x8A", :eth_daddr=>"00:1c:10:cc:57:8a"} packetfu-shell.rb $ rvmsudo irb -r packetfu-shell.rb >> pkt = TCPPacket.new => [..packet dissection output...] >> pkt.ip_saddr = "1.2.3.4" => "1.2.3.4" >> pkt.ip_daddr = "10.20.30.40" => "10.20.30.40" >> pkt.tcp_sport = 1025 => 1025 >> pkt.tcp_dport = 80 => 80 >> pkt.recalc => #<struct ...> Testing Strategies Tests as Examples with Test::Unit RSpec --format=documentation test$ rspec --format=documentation ethpacket_spec.rb PacketFu::EthPacket when read from a pcap file is a regular ethernet packet should be an EthPacket kind of packet should have a dest mac address should have a source mac address should have a payload in its first header size should == 78 an EthPacket's first header should be 64 bytes EthHeader struct members members should include :eth_dst members should include :eth_src members should include :eth_proto members should include :body isn't a regular Ethernet packet should not be an EthPacket Finished in 0.01863 seconds 11 examples, 0 failures def test_tcp_option t = TcpOption.new assert_equal("\x00", t.to_s) t = TcpOption.new(:kind => 2, :optlen => 4, :value => 1024) assert_equal("\x02\x04\x04\x00", t.to_s) t = TcpOption.new(:kind => 0xf0, :optlen => 6, :value => 1024) assert_equal("\xf0\x06\x00\x00\x04\x00", t.to_s) t = TcpOption.new(:kind => 0xf0, :optlen => 6, :value => "1024") assert_equal("\xf0\x061024", t.to_s) t = TcpOption.new(:kind => 0xf0, :optlen => 6, :value => nil) assert_equal("\xf0\x06", t.to_s) t = TcpOption.new(:kind => 0xf1, :optlen => 10, :value => "a1b2c3d4e5") assert_equal("\xf1\x0aa1b2c3d4e5", t.to_s) end Design Patterns Inheritance and Composition Delegation >> pkt.ip_saddr => "1.2.3.4" when /^([a-zA-Z0-9]+)_.+/ ptype = $1 if PacketFu.packet_prefixes.index(ptype) self.instance_variable_get("@#{ptype}_header").send(sym,*args, &block) else super end end Down the stack with method_missing() >> pkt.ip_header.methods.include? :ip_saddr => true >> pkt.ip_header.ip_saddr => "1.2.3.4" >> pkt.ip_color NoMethodError: undefined method `ip_color' for #<PacketFu::IPHeader...> Instance methods Uninstantiated classes and modules have methods, too >> ICMPPacket.layer => 3 >> ARPPacket.layer => 2 >> InvalidPacket.layer => 0 Get Started! TCPPacket < Packet @interface @headers @flavor #read() #clone #to_w() ...etc... #initialize() TCPPacket.can_parse?() #tcp_calc_sum ...etc... @eth_header @ip_header @tcp_header :eth_dst :eth_src :eth_proto :body :ip_v :ip_hl ...etc... :body :tcp_src :tcp_dst ...etc... :body :oui :nic :oui :nic :value :endian :width :default :b5 - :b0 :local :multicast :oui :n1 :n2 :n3 >> tcp_packet.headers.first.first.first[:oui].to_s(16) => "1c10" Goldilocks Introspection >> tcp_packet.inspect_style = :hex => :hex >> tcp_packet => Eth|IP|TCP 00 1c 10 cc 57 8a 00 26 22 96 0f 07 08 00 45 00 ....W..&".....E. 00 14 e7 85 00 00 20 06 ff ff c0 a8 0b 46 00 00 ...... ......F.. 00 00 f0 1a 00 00 c4 90 a3 ff 00 00 00 00 50 00 ..............P. 40 00 4b 5f 00 00 @.K_.. >> tcp_packet.inspect_style = :dissect => :dissect >> tcp_packet => --EthHeader------------------------------------------- eth_dst 00:1c:10:cc:57:8a PacketFu::EthMac eth_src 00:26:22:96:0f:07 PacketFu::EthMac eth_proto 0x0800 StructFu::Int16 --IPHeader-------------------------------------------- ip_v 4 Fixnum ip_hl 5 Fixnum ip_tos 0 StructFu::Int8 ip_len 20 StructFu::Int16 ip_id 0xe785 StructFu::Int16 ip_frag 0 StructFu::Int16 ip_ttl 32 StructFu::Int8 ip_proto 6 StructFu::Int8 ip_sum 0xffff StructFu::Int16 ip_src 192.168.11.70 PacketFu::Octets ip_dst 0.0.0.0 PacketFu::Octets --TCPHeader------------------------------------------- tcp_src 61466 StructFu::Int16 tcp_dst 0 StructFu::Int16 tcp_seq 0xc490a3ff StructFu::Int32 tcp_ack 0x00000000 StructFu::Int32 tcp_hlen 5 PacketFu::TcpHlen tcp_reserved 0 PacketFu::TcpReserved tcp_ecn 0 PacketFu::TcpEcn tcp_flags ...... PacketFu::TcpFlags tcp_win 16384 StructFu::Int16 tcp_sum 0x4b5f StructFu::Int16 tcp_urg 0 StructFu::Int16 tcp_opts PacketFu::TcpOptions >> (PacketFu.methods - Object.methods).sort => [:add_packet_class, :at_least?, :binarize_version, :classes, :force_binary, :inspect_style, :inspect_style=, :newer_than?, :older_than?, :packet_classes, :packet_prefixes, :pcaprub_loaded?, :pcaprub_platform_require, :remove_packet_class, :require_protos, :version] "Hey, I need a new packet." "Set the IP source address to 1.2.3.4." "Set the dest address to 10.20.30.40" "Set the TCP source port to 1025" "Set the TCP dest port to 80" "Recalculate the packet's checksum." Do not want Fun fact: actually pasting all this text into Prezi will crash Flash. Pass by Reference >> packet = PcapFile.read_packets("test/sample.pcap")[7] >> packet.proto => ["Eth", "IP", "TCP"] >> h_objs = packet.headers.map {|x| x.object_id} => [17557540, 17556784, 17554908] => packet.instance_variable_get("@ip_header") >> ( returns an IPHeader Struct object ) >> packet.instance_variable_get("@ip_header").object_id => 17556784 >> h_objs.include? _ => true >> packet.instance_variable_get("@ip_header").body.class => PacketFu::TCPHeader >> packet.instance_variable_get("@ip_header").body.object_id => 17554908 >> h_objs.include? _ => true >> packet.instance_variable_get("@eth_header").body.equal? packet.headers[1] => true Assignment might be tricky >> new_packet = packet >> new_packet.ip_saddr = "1.2.3.4" => "1.2.3.4" >> packet.ip_saddr => "1.2.3.4" >> new_packet = packet.dup >> new_packet.ip_saddr = "10.20.30.40" => "10.20.30.40" >> packet.ip_saddr => "10.20.30.40" >> new_packet = packet.clone >> new_packet.ip_saddr = "2.4.6.8" => "2.4.6.8" >> packet.ip_saddr => "10.20.30.40" Instantiation idioms # Post instantiation tcp1 = TCPPacket.new tcp1.eth_saddr = "00:11:22:33:44:55" tcp1.eth_daddr = "de:ad:be:ef:ca:fe" Rule of Thumb: If you're templating packets to throw on the wire, use shallow copies (dup). If you're going to save and reuse them, use deep copies (clone). # Passing in pre-configured headers: ip_header = IPHeader.new( :ip_src => "\x01\x02\x03\x04", :ip_dst => "\x05\x06\x07\x08") tcp5 = TCPPacket.new(:ip => ip_header) Capture.new My interface is 'eth0' Start capturing packets. For each packet, parse it, skip to the next one if it's from me, otherwise get some data about it and print the data to the screen. def sniff(iface) iface ||= "eth0" cap = Capture.new(:iface => iface, :start => true) cap.stream.each do |p| pkt = Packet.parse p if pkt.is_ip? next if pkt.ip_saddr == Utils.ifconfig[:ip_saddr] packet_info = [pkt.ip_saddr, pkt.ip_daddr, pkt.size, pkt.proto.last] puts "%-15s -> %-15s %-4d %s" % packet_info end end end >> Utils.ifconfig("vmnet8") => {:iface=>"vmnet8", :eth_saddr=>"00:50:56:c0:00:08", :eth_src=>"\x00PV\xC0\x00\b", :ip_saddr=>"192.168.145.1", :ip_src=>"\xC0\xA8\x91\x01", :ip4_obj=>#<IPAddr: IPv4:192.168.145.0/255.255.255.0>, :ip6_saddr=>"fe80::250:56ff:fec0:8/64", :ip6_obj=>#<IPAddr: IPv6:fe80:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:0000:0000:0000:0000>} PacketFu::Utils.ifconfig 145.58.33.95 -> 192.168.11.70 1514 TCP 212.233.158.76 -> 192.168.11.70 110 UDP 88.174.164.147 -> 192.168.11.70 110 UDP 145.58.33.95 -> 192.168.11.70 1514 TCP 145.58.33.95 -> 192.168.11.70 1514 TCP 145.58.33.95 -> 192.168.11.70 1514 TCP 145.58.33.95 -> 192.168.11.70 1514 TCP 8.8.8.8 -> 192.168.11.70 143 UDP 41.237.73.186 -> 192.168.11.70 60 TCP 145.58.33.95 -> 192.168.11.70 1514 TCP 145.58.33.95 -> 192.168.11.70 1514 TCP 8.8.8.8 -> 192.168.11.70 143 UDP 8.8.8.8 -> 192.168.11.70 128 UDP 8.8.8.8 -> 192.168.11.70 187 UDP 24.45.247.232 -> 192.168.11.70 70 TCP Development with RVM Gem installation $ gem install packetfu $ gem install pcaprub $ gem install packetfu --pre More stable: More recent: (or just use --development) Build from source svn checkout http://packetfu.googlecode.com/svn/trunk/packetfu git clone https://github.com/todb/packetfu.git $ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm) $ rvm install 1.8.7 $ rvm use 1.8.7 --default Using /home/todb/.rvm/gems/ruby-1.8.7-p334 $ rvm install 1.9.1-p378 $ rvm use 1.9.1-p378--default More information Channel #packetfu on Freenode IRC packetfu/examples (from source or your gemdir) E-mail me! Packet#to_w() >> p = IPPacket.new >> p.ip_id = 0xbabe >> p.ip_saddr = "10.20.30.40" >> p.ip_daddr = "10.1.2.3" >> p.payload = "Here's a packet. It's not much, but it's mine." >> p.recalc >> 3.times { p.to_w("eth0") } => 3 "sudo make me a packet" "Set some fields." "Recalculate the checksum." "Put it on the wire three times." PacketFu by Example <todb@planb-security.net> # Based on the host configuration: tcp2 = TCPPacket.new(:config => Utils.whoami?) tcp3 = TCPPacket.new(:config => Utils.ifconfig) tcp4 = TCPPacket.new(:config => {:ip_saddr => "1.2.3.4"}) # Manual # Borrowing another packet's headers: tcp6 = TCPPacket.new( :eth => tcp1.eth_header, :ip => tcp5.ip_header.clone) #rvm on Freenode
See the full transcript