packetfu 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/{README → README.rdoc} +2 -2
  2. metadata +58 -94
  3. data/INSTALL +0 -40
  4. data/LICENSE +0 -28
  5. data/examples/100kpackets.rb +0 -41
  6. data/examples/ackscan.rb +0 -38
  7. data/examples/arp.rb +0 -60
  8. data/examples/arphood.rb +0 -59
  9. data/examples/dissect_thinger.rb +0 -22
  10. data/examples/ethernet.rb +0 -10
  11. data/examples/examples.rb +0 -3
  12. data/examples/ids.rb +0 -4
  13. data/examples/idsv2.rb +0 -6
  14. data/examples/new-simple-stats.rb +0 -52
  15. data/examples/oui.txt +0 -84177
  16. data/examples/packetfu-shell.rb +0 -113
  17. data/examples/simple-sniffer.rb +0 -40
  18. data/examples/simple-stats.rb +0 -50
  19. data/examples/slammer.rb +0 -33
  20. data/examples/uniqpcap.rb +0 -15
  21. data/lib/packetfu.rb +0 -147
  22. data/lib/packetfu/capture.rb +0 -169
  23. data/lib/packetfu/config.rb +0 -58
  24. data/lib/packetfu/inject.rb +0 -65
  25. data/lib/packetfu/packet.rb +0 -533
  26. data/lib/packetfu/pcap.rb +0 -594
  27. data/lib/packetfu/protos/arp.rb +0 -268
  28. data/lib/packetfu/protos/eth.rb +0 -296
  29. data/lib/packetfu/protos/hsrp.rb +0 -206
  30. data/lib/packetfu/protos/icmp.rb +0 -179
  31. data/lib/packetfu/protos/invalid.rb +0 -55
  32. data/lib/packetfu/protos/ip.rb +0 -378
  33. data/lib/packetfu/protos/ipv6.rb +0 -250
  34. data/lib/packetfu/protos/tcp.rb +0 -1127
  35. data/lib/packetfu/protos/udp.rb +0 -240
  36. data/lib/packetfu/structfu.rb +0 -294
  37. data/lib/packetfu/utils.rb +0 -194
  38. data/lib/packetfu/version.rb +0 -50
  39. data/test/all_tests.rb +0 -41
  40. data/test/arp_test.pcap +0 -0
  41. data/test/eth_test.pcap +0 -0
  42. data/test/ethpacket_spec.rb +0 -74
  43. data/test/icmp_test.pcap +0 -0
  44. data/test/ip_test.pcap +0 -0
  45. data/test/packet_spec.rb +0 -73
  46. data/test/packet_subclasses_spec.rb +0 -13
  47. data/test/packetfu_spec.rb +0 -90
  48. data/test/ptest.rb +0 -16
  49. data/test/sample-ipv6.pcap +0 -0
  50. data/test/sample.pcap +0 -0
  51. data/test/sample2.pcap +0 -0
  52. data/test/sample_hsrp_pcapr.cap +0 -0
  53. data/test/structfu_spec.rb +0 -335
  54. data/test/tcp_spec.rb +0 -101
  55. data/test/tcp_test.pcap +0 -0
  56. data/test/test_arp.rb +0 -135
  57. data/test/test_eth.rb +0 -91
  58. data/test/test_hsrp.rb +0 -20
  59. data/test/test_icmp.rb +0 -54
  60. data/test/test_inject.rb +0 -31
  61. data/test/test_invalid.rb +0 -28
  62. data/test/test_ip.rb +0 -69
  63. data/test/test_ip6.rb +0 -68
  64. data/test/test_octets.rb +0 -37
  65. data/test/test_packet.rb +0 -174
  66. data/test/test_pcap.rb +0 -209
  67. data/test/test_structfu.rb +0 -112
  68. data/test/test_tcp.rb +0 -327
  69. data/test/test_udp.rb +0 -73
  70. data/test/udp_test.pcap +0 -0
  71. data/test/vlan-pcapr.cap +0 -0
@@ -1,194 +0,0 @@
1
- require 'singleton'
2
- module PacketFu
3
-
4
- # Utils is a collection of various and sundry network utilities that are useful for packet
5
- # manipulation.
6
- class Utils
7
-
8
- # Returns the MAC address of an IP address, or nil if it's not responsive to arp. Takes
9
- # a dotted-octect notation of the target IP address, as well as a number of parameters:
10
- #
11
- # === Parameters
12
- # :eth_saddr
13
- # Source MAC address. Defaults to "00:00:00:00:00:00".
14
- # :ip_saddr
15
- # Source IP address. Defaults to "0.0.0.0"
16
- # :flavor
17
- # The flavor of the ARP request. Defaults to :none.
18
- # :timeout
19
- # Timeout in seconds. Defaults to 3.
20
- #
21
- # === Example
22
- # PacketFu::Utils::arp("192.168.1.1") #=> "00:18:39:01:33:70"
23
- # PacketFu::Utils::arp("192.168.1.1", :timeout => 5, :flavor => :hp_deskjet)
24
- #
25
- # === Warning
26
- #
27
- # It goes without saying, spewing forged ARP packets on your network is a great way to really
28
- # irritate your co-workers.
29
- def self.arp(target_ip,args={})
30
- iface = args[:iface] || :eth0
31
- args[:config] ||= whoami?(:iface => iface)
32
- arp_pkt = PacketFu::ARPPacket.new(:flavor => (args[:flavor] || :none), :config => args[:config])
33
- arp_pkt.eth_daddr = "ff:ff:ff:ff:ff:ff"
34
- arp_pkt.arp_daddr_mac = "00:00:00:00:00:00"
35
- arp_pkt.arp_daddr_ip = target_ip
36
- # Stick the Capture object in its own thread.
37
- cap_thread = Thread.new do
38
- target_mac = nil
39
- cap = PacketFu::Capture.new(:iface => iface, :start => true,
40
- :filter => "arp src #{target_ip} and ether dst #{arp_pkt.eth_saddr}")
41
- arp_pkt.to_w(iface) # Shorthand for sending single packets to the default interface.
42
- timeout = 0
43
- while target_mac.nil? && timeout <= (args[:timeout] || 3)
44
- if cap.save > 0
45
- arp_response = PacketFu::Packet.parse(cap.array[0])
46
- target_mac = arp_response.arp_saddr_mac if arp_response.arp_saddr_ip = target_ip
47
- end
48
- timeout += 0.1
49
- sleep 0.1 # Check for a response ten times per second.
50
- end
51
- target_mac
52
- end # cap_thread
53
- cap_thread.value
54
- end
55
-
56
- # Discovers the local IP and Ethernet address, which is useful for writing
57
- # packets you expect to get a response to. Note, this is a noisy
58
- # operation; a UDP packet is generated and dropped on to the default (or named)
59
- # interface, and then captured (which means you need to be root to do this).
60
- #
61
- # whoami? returns a hash of :eth_saddr, :eth_src, :ip_saddr, :ip_src,
62
- # :ip_src_bin, :eth_dst, and :eth_daddr (the last two are usually suitable
63
- # for a gateway mac address). It's most useful as an argument to
64
- # PacketFu::Config.new, or as an argument to the many Packet constructors.
65
- #
66
- # Note that if you have multiple interfaces with the same route (such as when
67
- # wlan0 and eth0 are associated to the same network), the "first" one
68
- # according to Pcap.lookupdev will be used, regardless of which :iface you
69
- # pick.
70
- #
71
- # === Parameters
72
- # :iface => "eth0"
73
- # An interface to listen for packets on. Note that since we rely on the OS to send the probe packet,
74
- # you will need to specify a target which will use this interface.
75
- # :target => "1.2.3.4"
76
- # A target IP address. By default, a packet will be sent to a random address in the 177/8 network.
77
- # Since this network is IANA reserved (for now), this network should be handled by your default gateway
78
- # and default interface.
79
- def self.whoami?(args={})
80
- unless args.kind_of? Hash
81
- raise ArgumentError, "Argument to `whoami?' must be a Hash"
82
- end
83
- if args[:iface].to_s =~ /^lo/ # Linux loopback more or less. Need a switch for windows loopback, too.
84
- dst_host = "127.0.0.1"
85
- else
86
- dst_host = (args[:target] || IPAddr.new((rand(16777216) + 2969567232), Socket::AF_INET).to_s)
87
- end
88
-
89
- dst_port = rand(0xffff-1024)+1024
90
- msg = "PacketFu whoami? packet #{(Time.now.to_i + rand(0xffffff)+1)}"
91
- iface = (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || :lo ).to_s
92
- cap = PacketFu::Capture.new(:iface => iface, :promisc => false, :start => true, :filter => "udp and dst host #{dst_host} and dst port #{dst_port}")
93
- udp_sock = UDPSocket.new
94
- udp_sock.send(msg,0,dst_host,dst_port)
95
- udp_sock = nil
96
- cap.save
97
- pkt = Packet.parse(cap.array[0]) unless cap.save.zero?
98
- timeout = 0
99
- while timeout < 1 # Sometimes packet generation can be a little pokey.
100
- if pkt
101
- timeout = 1.1 # Cancel the timeout
102
- if pkt.payload == msg
103
- my_data = {
104
- :iface => (args[:iface] || ENV['IFACE'] || Pcap.lookupdev || "lo").to_s,
105
- :pcapfile => args[:pcapfile] || "/tmp/out.pcap",
106
- :eth_saddr => pkt.eth_saddr,
107
- :eth_src => pkt.eth_src.to_s,
108
- :ip_saddr => pkt.ip_saddr,
109
- :ip_src => pkt.ip_src,
110
- :ip_src_bin => [pkt.ip_src].pack("N"),
111
- :eth_dst => pkt.eth_dst.to_s,
112
- :eth_daddr => pkt.eth_daddr
113
- }
114
- else raise SecurityError,
115
- "whoami() packet doesn't match sent data. Something fishy's going on."
116
- end
117
- else
118
- sleep 0.1; timeout += 0.1
119
- cap.save
120
- pkt = Packet.parse(cap.array[0]) unless cap.save.zero?
121
- end
122
- raise SocketError, "Didn't receive the whomi() packet, can't automatically configure." if !pkt
123
- cap = nil
124
- end
125
- my_data
126
- end
127
-
128
- # This is a brute-force approach at trying to find a suitable interface with an IP address.
129
- def self.lookupdev
130
- # XXX cycle through eth0-9 and wlan0-9, and if a cap start throws a RuntimeErorr (and we're
131
- # root), it's not a good interface. Boy, really ought to fix lookupdev directly with another
132
- # method that returns an array rather than just the first candidate.
133
- end
134
-
135
- # Handles ifconfig for various (okay, one) platforms. Mac guys, fix this and submit a patch!
136
- # Will have Windows done shortly.
137
- #
138
- # Takes an argument (either string or symbol) of the interface to look up, and
139
- # returns a hash which contains at least the :iface element, and if configured,
140
- # these additional elements:
141
- #
142
- # :eth_saddr # A human readable MAC address
143
- # :eth_src # A packed MAC address
144
- # :ip_saddr # A dotted-quad string IPv4 address
145
- # :ip_src # A packed IPv4 address
146
- # :ip4_obj # An IPAddr object with bitmask
147
- # :ip6_saddr # A colon-delimited hex IPv6 address, with bitmask
148
- # :ip6_obj # An IPAddr object with bitmask
149
- #
150
- # === Example
151
- # PacketFu::Utils.ifconfig :wlan0 # Not associated yet
152
- # #=> {:eth_saddr=>"00:1d:e0:73:9d:ff", :eth_src=>"\000\035\340s\235\377", :iface=>"wlan0"}
153
- # PacketFu::Utils.ifconfig("eth0") # Takes 'eth0' as default
154
- # #=> {:eth_saddr=>"00:1c:23:35:70:3b", :eth_src=>"\000\034#5p;", :ip_saddr=>"10.10.10.9", :ip4_obj=>#<IPAddr: IPv4:10.10.10.0/255.255.254.0>, :ip_src=>"\n\n\n\t", :iface=>"eth0", :ip6_saddr=>"fe80::21c:23ff:fe35:703b/64", :ip6_obj=>#<IPAddr: IPv6:fe80:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:0000:0000:0000:0000>}
155
- # PacketFu::Utils.ifconfig :lo
156
- # #=> {:ip_saddr=>"127.0.0.1", :ip4_obj=>#<IPAddr: IPv4:127.0.0.0/255.0.0.0>, :ip_src=>"\177\000\000\001", :iface=>"lo", :ip6_saddr=>"::1/128", :ip6_obj=>#<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>}
157
- def self.ifconfig(iface='eth0')
158
- ret = {}
159
- iface = iface.to_s.scan(/[0-9A-Za-z]/).join # Sanitizing input, no spaces, semicolons, etc.
160
- case RUBY_PLATFORM
161
- when /linux/i
162
- ifconfig_data = %x[ifconfig #{iface}]
163
- if ifconfig_data =~ /#{iface}/i
164
- ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
165
- else
166
- raise ArgumentError, "Cannot ifconfig #{iface}"
167
- end
168
- real_iface = ifconfig_data.first
169
- ret[:iface] = real_iface.split.first.downcase
170
- if real_iface =~ /[\s]HWaddr[\s]+([0-9a-fA-F:]{17})/i
171
- ret[:eth_saddr] = $1.downcase
172
- ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
173
- end
174
- ifconfig_data.each do |s|
175
- case s
176
- when /inet addr:[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
177
- ret[:ip_saddr] = $1
178
- ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
179
- ret[:ip4_obj] = IPAddr.new($1)
180
- ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
181
- when /inet6 addr:[\s]*([0-9a-fA-F:\x2f]+)/
182
- ret[:ip6_saddr] = $1
183
- ret[:ip6_obj] = IPAddr.new($1)
184
- end
185
- end
186
- end # linux
187
- ret
188
- end
189
-
190
- end
191
-
192
- end
193
-
194
- # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -1,50 +0,0 @@
1
- module PacketFu
2
-
3
- # Check the repo's for version release histories
4
- VERSION = "1.1.1" # Fixes for 1.8
5
-
6
- # Returns PacketFu::VERSION
7
- def self.version
8
- VERSION
9
- end
10
-
11
- # Returns a version string in a binary format for easy comparisons.
12
- def self.binarize_version(str)
13
- if(str.respond_to?(:split) && str =~ /^[0-9]+(\.([0-9]+)(\.[0-9]+)?)?\..+$/)
14
- bin_major,bin_minor,bin_teeny = str.split(/\x2e/).map {|x| x.to_i}
15
- bin_version = (bin_major.to_i << 16) + (bin_minor.to_i << 8) + bin_teeny.to_i
16
- else
17
- raise ArgumentError, "Compare version malformed. Should be \x22x.y.z\x22"
18
- end
19
- end
20
-
21
- # Returns true if the version is equal to or greater than the compare version.
22
- # If the current version of PacketFu is "0.3.1" for example:
23
- #
24
- # PacketFu.at_least? "0" # => true
25
- # PacketFu.at_least? "0.2.9" # => true
26
- # PacketFu.at_least? "0.3" # => true
27
- # PacketFu.at_least? "1" # => true after 1.0's release
28
- # PacketFu.at_least? "1.12" # => false
29
- # PacketFu.at_least? "2" # => false
30
- def self.at_least?(str)
31
- this_version = binarize_version(self.version)
32
- ask_version = binarize_version(str)
33
- this_version >= ask_version
34
- end
35
-
36
- # Returns true if the current version is older than the compare version.
37
- def self.older_than?(str)
38
- return false if str == self.version
39
- this_version = binarize_version(self.version)
40
- ask_version = binarize_version(str)
41
- this_version < ask_version
42
- end
43
-
44
- # Returns true if the current version is newer than the compare version.
45
- def self.newer_than?(str)
46
- return false if str == self.version
47
- !self.older_than?(str)
48
- end
49
-
50
- end
data/test/all_tests.rb DELETED
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # Tested on:
4
- #
5
- # ruby-1.9.3-head [ x86_64 ]
6
- # ruby-1.9.1-p378 [ x86_64 ]
7
- # ruby-1.8.6-p399 [ x86_64 ]
8
- # ruby-1.8.7-p334 [ x86_64 ]
9
- # ruby-1.9.2-p180 [ x86_64 ]
10
-
11
- # Okay so the regular test/unit stuff screws up some of my
12
- # meta magic. I need to move these over to spec and see
13
- # if they're any better. In the meantime, behold my
14
- # ghetto test exec()'er. It all passes with this,
15
- # so I'm just going to go ahead and assume the testing
16
- # methodolgy is flawed. TODO: rewrite all this for spec
17
- # and incidentally get the gem to test like it's supposed
18
- # to.
19
-
20
- $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib/")
21
- require 'packetfu'
22
- puts "Testing PacketFu v#{PacketFu::VERSION}"
23
- dir = Dir.new(File.dirname(__FILE__))
24
-
25
- dir.each { |file|
26
- next unless File.file? file
27
- next unless file[/^test_.*rb$/]
28
- next if file == $0
29
- puts "Running #{file}..."
30
- cmd = %x{ruby #{file}}
31
- if cmd[/ 0 failures/] && cmd[/ 0 errors/]
32
- puts "#{file}: All passed"
33
- else
34
- puts "File: #{file} had failures or errors:"
35
- puts "-" * 80
36
- puts cmd
37
- puts "-" * 80
38
- end
39
- }
40
-
41
- # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
data/test/arp_test.pcap DELETED
Binary file
data/test/eth_test.pcap DELETED
Binary file
@@ -1,74 +0,0 @@
1
- $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
- require 'packetfu'
3
-
4
- include PacketFu
5
-
6
- describe EthPacket, "when read from a pcap file" do
7
-
8
- before :all do
9
- parsed_packets = PcapFile.read_packets(File.join(".","sample.pcap"))
10
- @eth_packet = parsed_packets.first
11
- end
12
-
13
- context "is a regular ethernet packet" do
14
-
15
- subject { @eth_packet }
16
-
17
- it "should be an EthPacket kind of packet" do
18
- subject.should be_kind_of EthPacket
19
- end
20
-
21
- it "should have a dest mac address" do
22
- subject.eth_daddr.should == "00:03:2f:1a:74:de"
23
- end
24
-
25
- it "should have a source mac address" do
26
- subject.eth_saddr.should == "00:1b:11:51:b7:ce"
27
- end
28
-
29
- its(:size) { should == 78 }
30
-
31
- it "should have a payload in its first header" do
32
- subject.headers.first.body.should_not be_nil
33
- end
34
-
35
- context "an EthPacket's first header" do
36
-
37
- subject { @eth_packet.headers.first }
38
-
39
- it "should be 64 bytes" do
40
- subject.body.sz.should == 64
41
- end
42
-
43
- context "EthHeader struct members" do
44
- if RUBY_VERSION =~ /^1\.8/
45
- its(:members) { should include :eth_dst.to_s }
46
- its(:members) { should include :eth_src.to_s }
47
- its(:members) { should include :eth_proto.to_s }
48
- its(:members) { should include :body.to_s }
49
- else
50
- its(:members) { should include :eth_dst }
51
- its(:members) { should include :eth_src }
52
- its(:members) { should include :eth_proto }
53
- its(:members) { should include :body }
54
- end
55
- end
56
-
57
- end
58
-
59
- end
60
-
61
- context "isn't a regular Ethernet packet" do
62
-
63
- subject {
64
- parsed_packets = PcapFile.read_packets(File.join(".","vlan-pcapr.cap"))
65
- parsed_packets.first
66
- }
67
-
68
- it "should not be an EthPacket" do
69
- subject.should_not be_kind_of EthPacket
70
- end
71
-
72
- end
73
-
74
- end
data/test/icmp_test.pcap DELETED
Binary file
data/test/ip_test.pcap DELETED
Binary file
data/test/packet_spec.rb DELETED
@@ -1,73 +0,0 @@
1
- $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
- require 'packetfu'
3
-
4
- describe PacketFu::Packet, "abstract packet class behavior" do
5
-
6
- before(:all) do
7
- class PacketFu::FooPacket < PacketFu::Packet; end
8
- class PacketFu::BarPacket < PacketFu::Packet; end
9
- end
10
-
11
- it "should not be instantiated" do
12
- expect { PacketFu::Packet.new }.to raise_error(NoMethodError)
13
- end
14
-
15
- it "should allow subclasses to instantiate" do
16
- expect { PacketFu::FooPacket.new }. to be
17
- PacketFu.packet_classes.include?(PacketFu::FooPacket).should be_true
18
- end
19
-
20
- it "should register packet classes with PacketFu" do
21
- PacketFu.packet_classes {should include(FooPacket) }
22
- PacketFu.packet_classes {should include(BarPacket) }
23
- end
24
-
25
- it "should disallow badly named subclasses" do
26
- expect {
27
- class PacketFu::PacketNot < PacketFu::Packet
28
- end
29
- }.to raise_error
30
- PacketFu.packet_classes.include?(PacketFu::PacketNot).should be_false
31
- PacketFu.packet_classes {should_not include(PacketNot) }
32
- end
33
-
34
- before(:each) do
35
- @tcp_packet = PacketFu::TCPPacket.new
36
- @tcp_packet.ip_saddr = "10.10.10.10"
37
- end
38
-
39
- it "should shallow copy with dup()" do
40
- p2 = @tcp_packet.dup
41
- p2.ip_saddr = "20.20.20.20"
42
- p2.ip_saddr.should == @tcp_packet.ip_saddr
43
- p2.headers[1].object_id.should == @tcp_packet.headers[1].object_id
44
- end
45
-
46
- it "should deep copy with clone()" do
47
- p3 = @tcp_packet.clone
48
- p3.ip_saddr = "30.30.30.30"
49
- p3.ip_saddr.should_not == @tcp_packet.ip_saddr
50
- p3.headers[1].object_id.should_not == @tcp_packet.headers[1].object_id
51
- end
52
-
53
- it "should have senisble equality" do
54
- p4 = @tcp_packet.dup
55
- p4.should == @tcp_packet
56
- p5 = @tcp_packet.clone
57
- p5.should == @tcp_packet
58
- end
59
-
60
- # It's actually kinda hard to manually create identical TCP packets
61
- it "should be possible to manually create identical packets" do
62
- p6 = @tcp_packet.clone
63
- p6.should == @tcp_packet
64
- p7 = PacketFu::TCPPacket.new
65
- p7.ip_saddr = p6.ip_saddr
66
- p7.ip_id = p6.ip_id
67
- p7.tcp_seq = p6.tcp_seq
68
- p7.tcp_src = p6.tcp_src
69
- p7.tcp_sum = p6.tcp_sum
70
- p7.should == p6
71
- end
72
-
73
- end
@@ -1,13 +0,0 @@
1
- $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
- require 'packetfu'
3
-
4
- PacketFu.packet_classes.each do |pclass|
5
- describe pclass, "peek format" do
6
- it "will display sensible peek information" do
7
- p = pclass.new
8
- p.respond_to?(:peek).should be_true
9
- p.peek.size.should be_<=(80), p.peek.inspect
10
- p.peek.should match(/^[A-Z0-9?]../)
11
- end
12
- end
13
- end