packetfu 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|