Introducing 

Prezi AI.

Your new presentation assistant.

Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.

Loading…
Transcript

Interactive

Inline Docs

Sensible Defaults

>> 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>}

Conversational Interface

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

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_..

Inheritance and Composition

@eth_header

@ip_header

@tcp_header

:eth_dst

:eth_src

:eth_proto

:body

:oui

:nic

:b5 - :b0

:local

:multicast

:oui

>> tcp_packet.headers.first.first.first[:oui].to_s(16)

=> "1c10"

>> 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

>> 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...>

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

Instantiation idioms

Testing Strategies

Tests as Examples with Test::Unit

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

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

Gem installation

(or just use --development)

Development with RVM

More information

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).

Interface Goals

Get Started!

Design Patterns

packetfu-shell.rb

$ rvmsudo irb -r packetfu-shell.rb

TCPPacket < Packet

More stable:

:n1

:n2

:n3

:oui

:nic

:value

:endian

:width

:default

@interface

@headers

@flavor

:ip_v

:ip_hl

...etc...

:body

:tcp_src

:tcp_dst

...etc...

:body

$ gem install packetfu

$ gem install pcaprub

#read()

#clone

#to_w()

...etc...

#initialize()

TCPPacket.can_parse?()

#tcp_calc_sum

...etc...

More recent:

$ gem install packetfu --pre

Instance methods

Uninstantiated classes and modules have methods, too

Build from source

>> ICMPPacket.layer

=> 3

>> ARPPacket.layer

=> 2

>> InvalidPacket.layer

=> 0

>> (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]

svn checkout http://packetfu.googlecode.com/svn/trunk/packetfu

git clone https://github.com/todb/packetfu.git

Delegation

Down the stack with method_missing()

PacketFu::Utils.whoami?

>> 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"}

$ 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

PacketFu::Utils.ifconfig

#rvm on Freenode

TCPPacket.new

Channel #packetfu on Freenode IRC

>> 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 ...>

"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."

packetfu/examples (from source or your gemdir)

Capture.new

E-mail me!

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

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."

>> 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"

Do not want

Fun fact: actually pasting all this text into Prezi will crash Flash.

PacketFu

by

Example

# 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)

# Post instantiation

tcp1 = TCPPacket.new

tcp1.eth_saddr = "00:11:22:33:44:55"

tcp1.eth_daddr = "de:ad:be:ef:ca:fe"

# 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)

>> 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

<todb@planb-security.net>

Learn more about creating dynamic, engaging presentations with Prezi