packetfu 1.1.9 → 1.1.10
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/bench/octets.rb +9 -9
- data/examples/100kpackets.rb +12 -12
- data/examples/ackscan.rb +16 -16
- data/examples/arp.rb +35 -35
- data/examples/arphood.rb +36 -36
- data/examples/dissect_thinger.rb +6 -6
- data/examples/new-simple-stats.rb +23 -23
- data/examples/packetfu-shell.rb +25 -25
- data/examples/simple-sniffer.rb +9 -9
- data/examples/simple-stats.rb +23 -23
- data/examples/slammer.rb +3 -3
- data/lib/packetfu.rb +127 -127
- data/lib/packetfu/capture.rb +169 -169
- data/lib/packetfu/config.rb +52 -52
- data/lib/packetfu/inject.rb +56 -56
- data/lib/packetfu/packet.rb +528 -528
- data/lib/packetfu/pcap.rb +579 -579
- data/lib/packetfu/protos/arp.rb +90 -90
- data/lib/packetfu/protos/arp/header.rb +158 -158
- data/lib/packetfu/protos/arp/mixin.rb +36 -36
- data/lib/packetfu/protos/eth.rb +44 -44
- data/lib/packetfu/protos/eth/header.rb +243 -243
- data/lib/packetfu/protos/eth/mixin.rb +3 -3
- data/lib/packetfu/protos/hsrp.rb +69 -69
- data/lib/packetfu/protos/hsrp/header.rb +107 -107
- data/lib/packetfu/protos/hsrp/mixin.rb +29 -29
- data/lib/packetfu/protos/icmp.rb +71 -71
- data/lib/packetfu/protos/icmp/header.rb +82 -82
- data/lib/packetfu/protos/icmp/mixin.rb +14 -14
- data/lib/packetfu/protos/invalid.rb +49 -49
- data/lib/packetfu/protos/ip.rb +69 -69
- data/lib/packetfu/protos/ip/header.rb +291 -291
- data/lib/packetfu/protos/ip/mixin.rb +40 -40
- data/lib/packetfu/protos/ipv6.rb +50 -50
- data/lib/packetfu/protos/ipv6/header.rb +188 -188
- data/lib/packetfu/protos/ipv6/mixin.rb +29 -29
- data/lib/packetfu/protos/tcp.rb +176 -176
- data/lib/packetfu/protos/tcp/ecn.rb +35 -35
- data/lib/packetfu/protos/tcp/flags.rb +74 -74
- data/lib/packetfu/protos/tcp/header.rb +268 -268
- data/lib/packetfu/protos/tcp/hlen.rb +32 -32
- data/lib/packetfu/protos/tcp/mixin.rb +46 -46
- data/lib/packetfu/protos/tcp/option.rb +321 -321
- data/lib/packetfu/protos/tcp/options.rb +95 -95
- data/lib/packetfu/protos/tcp/reserved.rb +35 -35
- data/lib/packetfu/protos/udp.rb +116 -116
- data/lib/packetfu/protos/udp/header.rb +91 -91
- data/lib/packetfu/protos/udp/mixin.rb +3 -3
- data/lib/packetfu/structfu.rb +280 -280
- data/lib/packetfu/utils.rb +226 -217
- data/lib/packetfu/version.rb +41 -41
- data/packetfu.gemspec +2 -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 +4 -3
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
@@ -14,18 +14,18 @@ start_time = Time.now.utc
|
|
14
14
|
count = 0
|
15
15
|
|
16
16
|
100.times do
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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"
|
29
29
|
end
|
30
30
|
|
31
31
|
read_bytes_start = Time.now.utc
|
data/examples/ackscan.rb
CHANGED
@@ -10,25 +10,25 @@ require 'packetfu'
|
|
10
10
|
#cap = Capture.new(:iface=>'wlan0') # or whatever your interface is
|
11
11
|
# Run this on the third
|
12
12
|
def do_scan
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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!"
|
19
19
|
end
|
20
20
|
|
21
21
|
def gen_packets
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
32
32
|
pkt.recalc
|
33
33
|
pkt_array << pkt.to_s
|
34
34
|
end
|
data/examples/arp.rb
CHANGED
@@ -9,11 +9,11 @@ require './examples' # For path setting slight-of-hand
|
|
9
9
|
require 'packetfu'
|
10
10
|
|
11
11
|
def usage
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
17
17
|
end
|
18
18
|
|
19
19
|
usage unless target_ip = ARGV[0] # Need a target IP.
|
@@ -24,36 +24,36 @@ $packetfu_default = PacketFu::Config.new(PacketFu::Utils.whoami?).config
|
|
24
24
|
|
25
25
|
def arp(target_ip)
|
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
|
-
|
56
|
-
|
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
|
57
57
|
end
|
58
58
|
|
59
59
|
arp(target_ip)
|
data/examples/arphood.rb
CHANGED
@@ -11,20 +11,20 @@ require 'open-uri'
|
|
11
11
|
$oui_prefixes = {}
|
12
12
|
$arp_results = []
|
13
13
|
def build_oui_list
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
28
28
|
end
|
29
29
|
|
30
30
|
build_oui_list
|
@@ -32,30 +32,30 @@ build_oui_list
|
|
32
32
|
$root_ok = true if Process.euid.zero?
|
33
33
|
|
34
34
|
def arp_everyone
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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}
|
53
53
|
end
|
54
54
|
|
55
55
|
if $root_ok
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
arp_everyone
|
57
|
+
puts "\n"
|
58
|
+
sleep 3
|
59
|
+
$arp_results.sort.each {|a| puts a unless a =~ /NOTHERE/}
|
60
60
|
end
|
61
61
|
|
data/examples/dissect_thinger.rb
CHANGED
@@ -14,10 +14,10 @@ include PacketFu
|
|
14
14
|
|
15
15
|
packets = PcapFile.file_to_array fname
|
16
16
|
packets.each do |packet|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
puts "_" * 75
|
18
|
+
puts packet.inspect
|
19
|
+
puts "_" * 75
|
20
|
+
pkt = Packet.parse(packet)
|
21
|
+
puts pkt.dissect
|
22
|
+
sleep sleep_interval
|
23
23
|
end
|
@@ -13,38 +13,38 @@ require './examples' # For path setting slight-of-hand
|
|
13
13
|
require 'packetfu'
|
14
14
|
|
15
15
|
def print_results(stats)
|
16
|
-
|
16
|
+
stats.each_pair { |k,v| puts "%-12s: %10d" % [k,v] }
|
17
17
|
end
|
18
18
|
|
19
19
|
# Takes a file name, parses the packets, and records the packet
|
20
20
|
# type based on its PacketFu class.
|
21
21
|
def count_packet_types(file)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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)
|
38
38
|
end
|
39
39
|
|
40
40
|
if File.readable?(infile = (ARGV[0] || 'in.pcap'))
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
title = "Packets by packet type in '#{infile}'"
|
42
|
+
puts "-" * title.size
|
43
|
+
puts title
|
44
|
+
puts "-" * title.size
|
45
|
+
count_packet_types(infile)
|
46
46
|
else
|
47
|
-
|
47
|
+
raise RuntimeError, "Need an infile, like so: #{$0} in.pcap"
|
48
48
|
end
|
49
49
|
|
50
50
|
|
data/examples/packetfu-shell.rb
CHANGED
@@ -49,12 +49,12 @@ require './examples'
|
|
49
49
|
require 'packetfu'
|
50
50
|
|
51
51
|
module PacketFu
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
def whoami?(args={})
|
53
|
+
Utils.whoami?(args)
|
54
|
+
end
|
55
|
+
def arp(arg)
|
56
|
+
Utils.arp(arg)
|
57
|
+
end
|
58
58
|
end
|
59
59
|
|
60
60
|
include PacketFu
|
@@ -64,7 +64,7 @@ include PacketFu
|
|
64
64
|
# http://jisho.org/words?jap=+%E3%83%91%E3%82%B1%E3%83%83%E3%83%88%E3%83%95&eng=&dict=edict
|
65
65
|
#
|
66
66
|
def packetfu_ascii_art
|
67
|
-
|
67
|
+
puts <<EOM
|
68
68
|
_______ _______ _______ _ _______ _________ _______
|
69
69
|
( ____ )( ___ )( ____ \\| \\ /\\( ____ \\\\__ __/( ____ \\|\\ /|
|
70
70
|
| ( )|| ( ) || ( \\/| \\ / /| ( \\/ ) ( | ( \\/| ) ( |
|
@@ -82,33 +82,33 @@ def packetfu_ascii_art
|
|
82
82
|
a mid-level packet manipulation library for ruby
|
83
83
|
|
84
84
|
EOM
|
85
|
-
|
85
|
+
end
|
86
86
|
|
87
87
|
@pcaprub_loaded = PacketFu.pcaprub_loaded?
|
88
88
|
# Displays a helpful banner.
|
89
89
|
def banner
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
90
|
+
packetfu_ascii_art
|
91
|
+
puts ">>> PacketFu Shell #{PacketFu.version}."
|
92
|
+
if Process.euid.zero? && @pcaprub_loaded
|
93
|
+
puts ">>> Use $packetfu_default.config for salient networking details."
|
94
|
+
print "IP: %-15s Mac: %s" % [$packetfu_default.ip_saddr, $packetfu_default.eth_saddr]
|
95
|
+
puts " Gateway: %s" % $packetfu_default.eth_daddr
|
96
|
+
print "Net: %-15s" % [Pcap.lookupnet($packetfu_default.iface)][0]
|
97
|
+
print " " * 13
|
98
|
+
puts "Iface: %s" % [($packetfu_default.iface)]
|
99
|
+
puts ">>> Packet capturing/injecting enabled."
|
100
|
+
else
|
101
|
+
print ">>> Packet capturing/injecting disabled. "
|
102
|
+
puts Process.euid.zero? ? "(no PcapRub)" : "(not root)"
|
103
|
+
end
|
104
|
+
puts "<>" * 36
|
105
105
|
end
|
106
106
|
|
107
107
|
# Silly wlan0 workaround
|
108
108
|
begin
|
109
|
-
|
109
|
+
$packetfu_default = PacketFu::Config.new(Utils.whoami?) if(@pcaprub_loaded && Process.euid.zero?)
|
110
110
|
rescue RuntimeError
|
111
|
-
|
111
|
+
$packetfu_default = PacketFu::Config.new(Utils.whoami?(:iface => 'wlan0')) if(@pcaprub_loaded && Process.euid.zero?)
|
112
112
|
end
|
113
113
|
|
114
114
|
banner
|
data/examples/simple-sniffer.rb
CHANGED
@@ -8,15 +8,15 @@ include PacketFu
|
|
8
8
|
iface = ARGV[0] || "eth0"
|
9
9
|
|
10
10
|
def sniff(iface)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
cap = Capture.new(:iface => iface, :start => true)
|
12
|
+
cap.stream.each do |p|
|
13
|
+
pkt = Packet.parse p
|
14
|
+
if pkt.is_ip?
|
15
|
+
next if pkt.ip_saddr == Utils.ifconfig(iface)[:ip_saddr]
|
16
|
+
packet_info = [pkt.ip_saddr, pkt.ip_daddr, pkt.size, pkt.proto.last]
|
17
|
+
puts "%-15s -> %-15s %-4d %s" % packet_info
|
18
|
+
end
|
19
|
+
end
|
20
20
|
end
|
21
21
|
|
22
22
|
sniff(iface)
|