packetfu 1.1.8 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +11 -12
- data/bench/octets.rb +9 -9
- data/examples/100kpackets.rb +13 -12
- data/examples/ackscan.rb +17 -16
- data/examples/arp.rb +36 -35
- data/examples/arphood.rb +37 -36
- data/examples/dissect_thinger.rb +7 -6
- data/examples/ethernet.rb +1 -0
- data/examples/examples.rb +1 -0
- data/examples/ifconfig.rb +1 -0
- data/examples/new-simple-stats.rb +24 -23
- data/examples/packetfu-shell.rb +26 -25
- data/examples/simple-sniffer.rb +10 -9
- data/examples/simple-stats.rb +24 -23
- data/examples/slammer.rb +4 -3
- data/lib/packetfu.rb +128 -127
- data/lib/packetfu/capture.rb +170 -169
- data/lib/packetfu/config.rb +53 -52
- data/lib/packetfu/inject.rb +57 -56
- data/lib/packetfu/packet.rb +529 -528
- data/lib/packetfu/pcap.rb +580 -579
- data/lib/packetfu/protos/arp.rb +91 -90
- data/lib/packetfu/protos/arp/header.rb +159 -158
- data/lib/packetfu/protos/arp/mixin.rb +37 -36
- data/lib/packetfu/protos/eth.rb +45 -44
- data/lib/packetfu/protos/eth/header.rb +244 -243
- data/lib/packetfu/protos/eth/mixin.rb +4 -3
- data/lib/packetfu/protos/hsrp.rb +70 -69
- data/lib/packetfu/protos/hsrp/header.rb +108 -107
- data/lib/packetfu/protos/hsrp/mixin.rb +30 -29
- data/lib/packetfu/protos/icmp.rb +72 -71
- data/lib/packetfu/protos/icmp/header.rb +83 -82
- data/lib/packetfu/protos/icmp/mixin.rb +15 -14
- data/lib/packetfu/protos/invalid.rb +50 -49
- data/lib/packetfu/protos/ip.rb +70 -69
- data/lib/packetfu/protos/ip/header.rb +292 -291
- data/lib/packetfu/protos/ip/mixin.rb +41 -40
- data/lib/packetfu/protos/ipv6.rb +51 -50
- data/lib/packetfu/protos/ipv6/header.rb +189 -188
- data/lib/packetfu/protos/ipv6/mixin.rb +30 -29
- data/lib/packetfu/protos/lldp.rb +3 -1
- data/lib/packetfu/protos/lldp/header.rb +1 -0
- data/lib/packetfu/protos/lldp/mixin.rb +1 -0
- data/lib/packetfu/protos/tcp.rb +177 -176
- data/lib/packetfu/protos/tcp/ecn.rb +36 -35
- data/lib/packetfu/protos/tcp/flags.rb +75 -74
- data/lib/packetfu/protos/tcp/header.rb +269 -268
- data/lib/packetfu/protos/tcp/hlen.rb +33 -32
- data/lib/packetfu/protos/tcp/mixin.rb +47 -46
- data/lib/packetfu/protos/tcp/option.rb +322 -321
- data/lib/packetfu/protos/tcp/options.rb +96 -95
- data/lib/packetfu/protos/tcp/reserved.rb +36 -35
- data/lib/packetfu/protos/udp.rb +117 -116
- data/lib/packetfu/protos/udp/header.rb +92 -91
- data/lib/packetfu/protos/udp/mixin.rb +4 -3
- data/lib/packetfu/structfu.rb +281 -280
- data/lib/packetfu/utils.rb +211 -208
- data/lib/packetfu/version.rb +42 -41
- data/packetfu.gemspec +1 -1
- data/spec/ethpacket_spec.rb +48 -48
- data/spec/packet_spec.rb +57 -57
- data/spec/packet_subclasses_spec.rb +8 -8
- data/spec/packetfu_spec.rb +59 -59
- data/spec/structfu_spec.rb +268 -268
- data/spec/tcp_spec.rb +75 -75
- data/test/all_tests.rb +13 -13
- data/test/func_lldp.rb +3 -3
- data/test/ptest.rb +2 -2
- data/test/test_arp.rb +116 -116
- data/test/test_capture.rb +45 -45
- data/test/test_eth.rb +68 -68
- data/test/test_hsrp.rb +9 -9
- data/test/test_icmp.rb +52 -52
- data/test/test_inject.rb +18 -18
- data/test/test_invalid.rb +16 -16
- data/test/test_ip.rb +36 -36
- data/test/test_ip6.rb +48 -48
- data/test/test_octets.rb +21 -21
- data/test/test_packet.rb +154 -154
- data/test/test_pcap.rb +170 -170
- data/test/test_structfu.rb +97 -97
- data/test/test_tcp.rb +320 -320
- data/test/test_udp.rb +76 -76
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -12,13 +12,9 @@ PacketFu is rdoc-compatible, which means it's sdoc compatible. In the same direc
|
|
12
12
|
|
13
13
|
PcapRub:
|
14
14
|
|
15
|
-
$ svn co http://www.metasploit.com/svn/framework3/trunk/external/pcaprub
|
16
|
-
|
17
|
-
or
|
18
|
-
|
19
15
|
$ rvm gem install pcaprub
|
20
16
|
|
21
|
-
Marshall Beddoe's PcapRub is required only for packet reading and writing from a network interfaces (which is a pretty big only). PcapRub itself relies on libpcap 0.9.8 or later for packet injection. PcapRub also requires root
|
17
|
+
Marshall Beddoe's PcapRub is required only for packet reading and writing from a network interfaces (which is a pretty big only). PcapRub itself relies on libpcap 0.9.8 or later for packet injection. PcapRub also requires root privileges to access the interface directly.
|
22
18
|
|
23
19
|
=== Platforms
|
24
20
|
|
@@ -31,6 +27,16 @@ I tend to test with the following (with bash):
|
|
31
27
|
rvmsudo ./all_tests.rb >> /tmp/tests.txt; rspec . >> /tmp/tests.txt
|
32
28
|
done
|
33
29
|
|
30
|
+
==== Problem Platforms
|
31
|
+
|
32
|
+
* 1.8.6-p420 -- Has problems with pcaprub and capture/inject. Technically, these are pcaprub problems and not PacketFu problems, but PacketFu should at least fail better at them.
|
33
|
+
|
34
|
+
* 1.9.1-p431 -- Has problems with loading gems in general, see http://redmine.ruby-lang.org/issues/2404
|
35
|
+
|
36
|
+
* 2.0.0-p0 -- Has problems with binary encoding of strings that do not manifest in 1.9.x See https://github.com/todb/packetfu/issues/28
|
37
|
+
|
38
|
+
|
39
|
+
|
34
40
|
==== Passing Platforms
|
35
41
|
|
36
42
|
* 1.9.1-p378
|
@@ -38,14 +44,7 @@ I tend to test with the following (with bash):
|
|
38
44
|
* 1.9.2-p180 (suggested version)
|
39
45
|
* 1.9.3-head
|
40
46
|
|
41
|
-
==== Problem Platforms
|
42
|
-
|
43
|
-
* 1.8.6-p420 -- Has problems with pcaprub and capture/inject
|
44
|
-
* 1.9.1-p431 -- Has problems with loading gems in general, see http://redmine.ruby-lang.org/issues/2404
|
45
|
-
|
46
|
-
Technically, these are pcaprub problems and not PacketFu problems, but PacketFu should at least fail better at them.
|
47
47
|
|
48
|
-
Incidentally, I suspect these Ruby problems are the crux of the Mac OSX problems that people report. Try a different Ruby build and please let me know what works for you.
|
49
48
|
|
50
49
|
|
51
50
|
== Examples
|
data/bench/octets.rb
CHANGED
@@ -8,15 +8,15 @@ IPV4_STR = "1.2.3.4"
|
|
8
8
|
|
9
9
|
iters = 50_000
|
10
10
|
Benchmark.bm do |bm|
|
11
|
-
|
12
|
-
|
11
|
+
bm.report("Octets.new.read(...) ") {iters.times {PacketFu::Octets.new.read(IPV4_RAW)}}
|
12
|
+
bm.report("Octets.new.read_quad(...) ") {iters.times {PacketFu::Octets.new.read_quad(IPV4_STR)}}
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
octets = PacketFu::Octets.new
|
15
|
+
bm.report("octets#read(...) ") {iters.times {octets.read(IPV4_RAW)}}
|
16
|
+
bm.report("octets#read_quad(...) ") {iters.times {octets.read_quad(IPV4_STR)}}
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
octets.read(IPV4_RAW)
|
19
|
+
bm.report("octets#to_x() ") {iters.times {octets.to_x}}
|
20
|
+
bm.report("octets#to_i() ") {iters.times {octets.to_i}}
|
21
|
+
bm.report("octets#to_s() ") {iters.times {octets.to_s}}
|
22
22
|
end
|
data/examples/100kpackets.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
|
3
4
|
# Used mainly to test for memory leaks and to demo the preferred ways of
|
4
5
|
# reading and writing packets to and from pcap files.
|
@@ -13,18 +14,18 @@ start_time = Time.now.utc
|
|
13
14
|
count = 0
|
14
15
|
|
15
16
|
100.times do
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
17
|
+
@pcaps = []
|
18
|
+
1000.times do
|
19
|
+
u = UDPPacket.new
|
20
|
+
u.ip_src = [rand(2**32-1)].pack("N")
|
21
|
+
u.ip_dst = [rand(2**32-1)].pack("N")
|
22
|
+
u.recalc
|
23
|
+
@pcaps << u
|
24
|
+
end
|
25
|
+
pfile = PcapFile.new
|
26
|
+
res = pfile.array_to_file(:filename => "/tmp/out.pcap", :array => @pcaps, :append => true)
|
27
|
+
count += res.last
|
28
|
+
puts "Wrote #{count} packets in #{Time.now.utc - start_time} seconds"
|
28
29
|
end
|
29
30
|
|
30
31
|
read_bytes_start = Time.now.utc
|
data/examples/ackscan.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
require 'packetfu'
|
3
4
|
# Portscanning!
|
4
5
|
# Run this on one machine
|
@@ -9,25 +10,25 @@ require 'packetfu'
|
|
9
10
|
#cap = Capture.new(:iface=>'wlan0') # or whatever your interface is
|
10
11
|
# Run this on the third
|
11
12
|
def do_scan
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
puts "Generating packets..."
|
14
|
+
pkt_array = gen_packets.sort_by {rand}
|
15
|
+
puts "Dumping them on the wire..."
|
16
|
+
inj = PacketFu::Inject.new(:iface => ARGV[0])
|
17
|
+
inj.array_to_wire(:array=>pkt_array)
|
18
|
+
puts "Done!"
|
18
19
|
end
|
19
20
|
|
20
21
|
def gen_packets
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
config = PacketFu::Utils.whoami?(:iface=>ARGV[0])
|
23
|
+
pkt = PacketFu::TCPPacket.new(:config=>config, :flavor=>"Windows")
|
24
|
+
pkt.payload ="all I wanna do is ACK ACK ACK and a RST and take your money"
|
25
|
+
pkt.ip_daddr="209.85.165.0" # One of Google's networks
|
26
|
+
pkt.tcp_flags.ack=1
|
27
|
+
pkt.tcp_dst=81
|
28
|
+
pkt_array = []
|
29
|
+
256.times do |i|
|
30
|
+
pkt.ip_dst.o4=i
|
31
|
+
pkt.tcp_src = rand(5000 - 1025) + 1025
|
31
32
|
pkt.recalc
|
32
33
|
pkt_array << pkt.to_s
|
33
34
|
end
|
data/examples/arp.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: binary -*-
|
1
2
|
# This is a somewhat contrived and verbose demonstration of how to implement ARP manually.
|
2
3
|
#
|
3
4
|
# It's contrived because this is really how PacketFu::Utils got born; something similiar
|
@@ -8,11 +9,11 @@ require './examples' # For path setting slight-of-hand
|
|
8
9
|
require 'packetfu'
|
9
10
|
|
10
11
|
def usage
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
if ARGV[0].nil?
|
13
|
+
raise ArgumentError, "You need an IP address to start with."
|
14
|
+
elsif !Process.euid.zero?
|
15
|
+
raise SecurityError, "You need to be root to run this."
|
16
|
+
end
|
16
17
|
end
|
17
18
|
|
18
19
|
usage unless target_ip = ARGV[0] # Need a target IP.
|
@@ -23,36 +24,36 @@ $packetfu_default = PacketFu::Config.new(PacketFu::Utils.whoami?).config
|
|
23
24
|
|
24
25
|
def arp(target_ip)
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
27
|
+
arp_pkt = PacketFu::ARPPacket.new(:flavor => "Windows")
|
28
|
+
arp_pkt.eth_saddr = arp_pkt.arp_saddr_mac = $packetfu_default[:eth_saddr]
|
29
|
+
arp_pkt.eth_daddr = "ff:ff:ff:ff:ff:ff"
|
30
|
+
arp_pkt.arp_daddr_mac = "00:00:00:00:00:00"
|
31
|
+
|
32
|
+
arp_pkt.arp_saddr_ip = $packetfu_default[:ip_saddr]
|
33
|
+
arp_pkt.arp_daddr_ip = target_ip
|
34
|
+
|
35
|
+
# Stick the Capture object in its own thread.
|
36
|
+
|
37
|
+
cap_thread = Thread.new do
|
38
|
+
cap = PacketFu::Capture.new(:start => true,
|
39
|
+
:filter => "arp src #{target_ip} and ether dst #{arp_pkt.eth_saddr}")
|
40
|
+
arp_pkt.to_w # Shorthand for sending single packets to the default interface.
|
41
|
+
target_mac = nil
|
42
|
+
while target_mac.nil?
|
43
|
+
if cap.save > 0
|
44
|
+
arp_response = PacketFu::Packet.parse(cap.array[0])
|
45
|
+
target_mac = arp_response.arp_saddr_mac if arp_response.arp_saddr_ip = target_ip
|
46
|
+
end
|
47
|
+
sleep 0.1 # Check for a response ten times per second.
|
48
|
+
end
|
49
|
+
puts "#{target_ip} is-at #{target_mac}"
|
50
|
+
# That's all we need.
|
51
|
+
exit 0
|
52
|
+
end
|
53
|
+
|
54
|
+
# Timeout for cap_thread
|
55
|
+
sleep 3; puts "Oh noes! Couldn't get an arp out of #{target_ip}. Maybe it's not here."
|
56
|
+
exit 1
|
56
57
|
end
|
57
58
|
|
58
59
|
arp(target_ip)
|
data/examples/arphood.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
|
3
4
|
# A simple local network fingerprinter. Uses the OUI list.
|
4
5
|
# Usage: rvmsudo ./arphood.rb [iface] [network] <oui.txt>
|
@@ -10,20 +11,20 @@ require 'open-uri'
|
|
10
11
|
$oui_prefixes = {}
|
11
12
|
$arp_results = []
|
12
13
|
def build_oui_list
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
14
|
+
if ARGV[2].nil?
|
15
|
+
puts "Fetching the oui.txt from IEEE, it'll be a second. Avoid this with #{$0} [iface] [network] <filename>."
|
16
|
+
oui_file = open("http://standards.ieee.org/regauth/oui/oui.txt")
|
17
|
+
else
|
18
|
+
oui_file = File.open(ARGV[2], "rb")
|
19
|
+
end
|
20
|
+
oui_file.each do |oui_line|
|
21
|
+
maybe_oui = oui_line.scan(/^[0-9a-f]{2}\-[0-9a-f]{2}\-[0-9a-f]{2}/i)[0]
|
22
|
+
unless maybe_oui.nil?
|
23
|
+
oui_value = maybe_oui
|
24
|
+
oui_vendor = oui_line.split(/\(hex\)\s*/n)[1] || "PRIVATE"
|
25
|
+
$oui_prefixes[oui_value] = oui_vendor.chomp
|
26
|
+
end
|
27
|
+
end
|
27
28
|
end
|
28
29
|
|
29
30
|
build_oui_list
|
@@ -31,30 +32,30 @@ build_oui_list
|
|
31
32
|
$root_ok = true if Process.euid.zero?
|
32
33
|
|
33
34
|
def arp_everyone
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
35
|
+
my_net = PacketFu::Config.new(PacketFu::Utils.whoami?(:iface =>(ARGV[0] || 'wlan0')))
|
36
|
+
threads = []
|
37
|
+
network = ARGV[1] || "192.168.2"
|
38
|
+
print "Arping around..."
|
39
|
+
253.times do |i|
|
40
|
+
threads[i] = Thread.new do
|
41
|
+
this_host = network + ".#{i+1}"
|
42
|
+
print "."
|
43
|
+
colon_mac = PacketFu::Utils.arp(this_host,my_net.config)
|
44
|
+
unless colon_mac.nil?
|
45
|
+
hyphen_mac = colon_mac.tr(':','-').upcase[0,8]
|
46
|
+
else
|
47
|
+
hyphen_mac = colon_mac = "NOTHERE"
|
48
|
+
end
|
49
|
+
$arp_results << "%s : %s / %s" % [this_host,colon_mac,$oui_prefixes[hyphen_mac]]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
threads.each {|thr| thr.join}
|
52
53
|
end
|
53
54
|
|
54
55
|
if $root_ok
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
arp_everyone
|
57
|
+
puts "\n"
|
58
|
+
sleep 3
|
59
|
+
$arp_results.sort.each {|a| puts a unless a =~ /NOTHERE/}
|
59
60
|
end
|
60
61
|
|
data/examples/dissect_thinger.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
# This just allows you to eyeball the dissection stuff to make sure it's all right.
|
3
4
|
# Some day, there will be a proper test for it.
|
4
5
|
|
@@ -13,10 +14,10 @@ include PacketFu
|
|
13
14
|
|
14
15
|
packets = PcapFile.file_to_array fname
|
15
16
|
packets.each do |packet|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
puts "_" * 75
|
18
|
+
puts packet.inspect
|
19
|
+
puts "_" * 75
|
20
|
+
pkt = Packet.parse(packet)
|
21
|
+
puts pkt.dissect
|
22
|
+
sleep sleep_interval
|
22
23
|
end
|
data/examples/ethernet.rb
CHANGED
data/examples/examples.rb
CHANGED
data/examples/ifconfig.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
|
3
4
|
# new-simple-stats.rb demonstrates the performance difference
|
4
5
|
# between the old and busted way to parse pcap files and the
|
@@ -12,38 +13,38 @@ require './examples' # For path setting slight-of-hand
|
|
12
13
|
require 'packetfu'
|
13
14
|
|
14
15
|
def print_results(stats)
|
15
|
-
|
16
|
+
stats.each_pair { |k,v| puts "%-12s: %10d" % [k,v] }
|
16
17
|
end
|
17
18
|
|
18
19
|
# Takes a file name, parses the packets, and records the packet
|
19
20
|
# type based on its PacketFu class.
|
20
21
|
def count_packet_types(file)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
22
|
+
stats = {}
|
23
|
+
count = 0
|
24
|
+
elapsed = 0
|
25
|
+
start_time = Time.now
|
26
|
+
PacketFu::PcapFile.read_packets(file) do |pkt|
|
27
|
+
kind = pkt.proto.last.to_sym
|
28
|
+
stats[kind] ? stats[kind] += 1 : stats[kind] = 1
|
29
|
+
count += 1
|
30
|
+
elapsed = (Time.now - start_time).to_i
|
31
|
+
if count % 5_000 == 0
|
32
|
+
puts "After #{count} packets (#{elapsed} seconds elapsed):"
|
33
|
+
print_results(stats)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
puts "Final results for #{count} packets (#{elapsed} seconds elapsed):"
|
37
|
+
print_results(stats)
|
37
38
|
end
|
38
39
|
|
39
40
|
if File.readable?(infile = (ARGV[0] || 'in.pcap'))
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
title = "Packets by packet type in '#{infile}'"
|
42
|
+
puts "-" * title.size
|
43
|
+
puts title
|
44
|
+
puts "-" * title.size
|
45
|
+
count_packet_types(infile)
|
45
46
|
else
|
46
|
-
|
47
|
+
raise RuntimeError, "Need an infile, like so: #{$0} in.pcap"
|
47
48
|
end
|
48
49
|
|
49
50
|
|