packetfu 1.0.0 → 1.0.2.pre

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/lib/packetfu/pcap.rb CHANGED
@@ -266,8 +266,8 @@ module PacketFu
266
266
  # that readfile clears any existing packets, since that seems to be the
267
267
  # typical use.
268
268
  def readfile(file)
269
- f = File.open(file, "rb") {|f| f.read}
270
- self.read! f
269
+ fdata = File.open(file, "rb") {|f| f.read}
270
+ self.read! fdata
271
271
  end
272
272
 
273
273
  # file_to_array() translates a libpcap file into an array of packets.
@@ -416,7 +416,7 @@ module PacketFu
416
416
 
417
417
  # set_byte_order is pretty much totally deprecated.
418
418
  def set_byte_order(byte_order)
419
- PacketFu.instance_variable_set("@byte_order",byte_order)
419
+ PacketFu.instance_variable_set(:@byte_order,byte_order)
420
420
  return true
421
421
  end
422
422
 
@@ -450,7 +450,7 @@ module PacketFu
450
450
  arr = args[:arr] || args[:array] || []
451
451
  ts = args[:ts] || args[:timestamp] || Time.now.to_i
452
452
  ts_inc = args[:ts_inc] || args[:timestamp_increment]
453
- pkts = PcapFile.new.array_to_file(:endian => PacketFu.instance_variable_get("@byte_order"),
453
+ pkts = PcapFile.new.array_to_file(:endian => PacketFu.instance_variable_get(:@byte_order),
454
454
  :arr => arr,
455
455
  :ts => ts,
456
456
  :ts_inc => ts_inc)
@@ -468,7 +468,7 @@ module PacketFu
468
468
  append = args[:append]
469
469
  Read.set_byte_order(byte_order) if [:big, :little].include? byte_order
470
470
  pf = PcapFile.new
471
- pf.array_to_file(:endian => PacketFu.instance_variable_get("@byte_order"),
471
+ pf.array_to_file(:endian => PacketFu.instance_variable_get(:@byte_order),
472
472
  :arr => arr,
473
473
  :ts => ts,
474
474
  :ts_inc => ts_inc)
@@ -173,13 +173,29 @@ module PacketFu
173
173
 
174
174
  attr_accessor :eth_header, :arp_header
175
175
 
176
+ def self.can_parse?(str)
177
+ return false unless EthPacket.can_parse? str
178
+ return false unless str.size >= 28
179
+ return false unless str[12,2] == "\x08\x06"
180
+ true
181
+ end
182
+
183
+ def read(str=nil,args={})
184
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
185
+ @eth_header.read(str)
186
+ @arp_header.read(str[14,str.size])
187
+ @eth_header.body = @arp_header
188
+ super(args)
189
+ self
190
+ end
191
+
176
192
  def initialize(args={})
177
193
  @eth_header = EthHeader.new(args).read(args[:eth])
178
194
  @arp_header = ARPHeader.new(args).read(args[:arp])
179
195
  @eth_header.eth_proto = "\x08\x06"
180
196
  @eth_header.body=@arp_header
181
197
 
182
- # Please send more flavors to todb-packetfu@planb-security.net.
198
+ # Please send more flavors to todb+packetfu@planb-security.net.
183
199
  # Most of these initial fingerprints come from one (1) sample.
184
200
  case (args[:flavor].nil?) ? :nil : args[:flavor].to_s.downcase.intern
185
201
  when :windows; @arp_header.body = "\x00" * 64 # 64 bytes of padding
@@ -197,7 +213,6 @@ module PacketFu
197
213
 
198
214
  @headers = [@eth_header, @arp_header]
199
215
  super
200
-
201
216
  end
202
217
 
203
218
  # Generates summary data for ARP packets.
@@ -245,10 +245,15 @@ module PacketFu
245
245
  class EthPacket < Packet
246
246
  attr_accessor :eth_header
247
247
 
248
- def initialize(args={})
249
- @eth_header = EthHeader.new(args).read(args[:eth])
250
- @headers = [@eth_header]
251
- super
248
+ def self.can_parse?(str)
249
+ str.size >= 14
250
+ end
251
+
252
+ def read(str=nil,args={})
253
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
254
+ @eth_header.read(str)
255
+ super(args)
256
+ return self
252
257
  end
253
258
 
254
259
  # Does nothing, really, since there's no length or
@@ -257,6 +262,12 @@ module PacketFu
257
262
  @headers[0].inspect
258
263
  end
259
264
 
265
+ def initialize(args={})
266
+ @eth_header = EthHeader.new(args).read(args[:eth])
267
+ @headers = [@eth_header]
268
+ super
269
+ end
270
+
260
271
  end
261
272
 
262
273
  end
@@ -0,0 +1,200 @@
1
+ module PacketFu
2
+
3
+ # HSRPHeader is a complete HSRP struct, used in HSRPPacket. HSRP is typically used for
4
+ # fault-tolerant default gateway in IP routing environment.
5
+ #
6
+ # For more on HSRP packets, see http://www.networksorcery.com/enp/protocol/hsrp.htm
7
+ #
8
+ # Submitted by fropert@packetfault.org. Thanks, Francois!
9
+ #
10
+ # ==== Header Definition
11
+ #
12
+ # Int8 :hsrp_version Default: 0 # Version
13
+ # Int8 :hsrp_opcode # Opcode
14
+ # Int8 :hsrp_state # State
15
+ # Int8 :hsrp_hellotime Default: 3 # Hello Time
16
+ # Int8 :hsrp_holdtime Default: 10 # Hold Time
17
+ # Int8 :hsrp_priority # Priority
18
+ # Int8 :hsrp_group # Group
19
+ # Int8 :hsrp_reserved Default: 0 # Reserved
20
+ # String :hsrp_password # Authentication Data
21
+ # Octets :hsrp_vip # Virtual IP Address
22
+ # String :body
23
+ class HSRPHeader < Struct.new(:hsrp_version, :hsrp_opcode, :hsrp_state,
24
+ :hsrp_hellotime, :hsrp_holdtime,
25
+ :hsrp_priority, :hsrp_group,
26
+ :hsrp_reserved, :hsrp_password,
27
+ :hsrp_vip, :body)
28
+
29
+ include StructFu
30
+
31
+ def initialize(args={})
32
+ super(
33
+ Int8.new(args[:hsrp_version] || 0),
34
+ Int8.new(args[:hsrp_opcode]),
35
+ Int8.new(args[:hsrp_state]),
36
+ Int8.new(args[:hsrp_hellotime] || 3),
37
+ Int8.new(args[:hsrp_holdtime] || 10),
38
+ Int8.new(args[:hsrp_priority]),
39
+ Int8.new(args[:hsrp_group]),
40
+ Int8.new(args[:hsrp_reserved] || 0),
41
+ StructFu::String.new.read(args[:hsrp_password] || "cisco\x00\x00\x00"),
42
+ Octets.new.read(args[:hsrp_vip] || ("\x00" * 4)),
43
+ StructFu::String.new.read(args[:body])
44
+ )
45
+ end
46
+
47
+ # Returns the object in string form.
48
+ def to_s
49
+ self.to_a.map {|x| x.to_s}.join
50
+ end
51
+
52
+ # Reads a string to populate the object.
53
+ def read(str)
54
+ force_binary(str)
55
+ return self if str.nil?
56
+ self[:hsrp_version].read(str[0,1])
57
+ self[:hsrp_opcode].read(str[1,1])
58
+ self[:hsrp_state].read(str[2,1])
59
+ self[:hsrp_hellotime].read(str[3,1])
60
+ self[:hsrp_holdtime].read(str[4,1])
61
+ self[:hsrp_priority].read(str[5,1])
62
+ self[:hsrp_group].read(str[6,1])
63
+ self[:hsrp_reserved].read(str[7,1])
64
+ self[:hsrp_password].read(str[8,8])
65
+ self[:hsrp_vip].read(str[16,4])
66
+ self[:body].read(str[20,str.size]) if str.size > 20
67
+ self
68
+ end
69
+
70
+ # Setter for the type.
71
+ def hsrp_version=(i); typecast i; end
72
+ # Getter for the type.
73
+ def hsrp_version; self[:hsrp_version].to_i; end
74
+ # Setter for the type.
75
+ def hsrp_opcode=(i); typecast i; end
76
+ # Getter for the type.
77
+ def hsrp_opcode; self[:hsrp_opcode].to_i; end
78
+ # Setter for the type.
79
+ def hsrp_state=(i); typecast i; end
80
+ # Getter for the type.
81
+ def hsrp_state; self[:hsrp_state].to_i; end
82
+ # Setter for the type.
83
+ def hsrp_hellotime=(i); typecast i; end
84
+ # Getter for the type.
85
+ def hsrp_hellotime; self[:hsrp_hellotime].to_i; end
86
+ # Setter for the type.
87
+ def hsrp_holdtime=(i); typecast i; end
88
+ # Getter for the type.
89
+ def hsrp_holdtime; self[:hsrp_holdtime].to_i; end
90
+ # Setter for the type.
91
+ def hsrp_priority=(i); typecast i; end
92
+ # Getter for the type.
93
+ def hsrp_priority; self[:hsrp_priority].to_i; end
94
+ # Setter for the type.
95
+ def hsrp_group=(i); typecast i; end
96
+ # Getter for the type.
97
+ def hsrp_group; self[:hsrp_group].to_i; end
98
+ # Setter for the type.
99
+ def hsrp_reserved=(i); typecast i; end
100
+ # Getter for the type.
101
+ def hsrp_reserved; self[:hsrp_reserved].to_i; end
102
+
103
+ def hsrp_addr=(addr)
104
+ self[:hsrp_vip].read_quad(addr)
105
+ end
106
+
107
+ # Returns a more readable IP source address.
108
+ def hsrp_addr
109
+ self[:hsrp_vip].to_x
110
+ end
111
+
112
+
113
+ end
114
+
115
+ # HSRPPacket is used to construct HSRP Packets. They contain an EthHeader, an IPHeader, and a UDPHeader.
116
+ #
117
+ # == Example
118
+ #
119
+ # hsrp_pkt.new
120
+ # hsrp_pkt.hsrp_opcode = 0
121
+ # hsrp_pkt.hsrp_state = 16
122
+ # hsrp_pkt.hsrp_priority = 254
123
+ # hsrp_pkt.hsrp_group = 1
124
+ # hsrp_pkt.hsrp_vip = 10.100.100.254
125
+ # hsrp_pkt.recalc
126
+ # hsrp_pkt.to_f('/tmp/hsrp.pcap')
127
+ #
128
+ # == Parameters
129
+ #
130
+ # :eth
131
+ # A pre-generated EthHeader object.
132
+ # :ip
133
+ # A pre-generated IPHeader object.
134
+ # :udp
135
+ # A pre-generated UDPHeader object.
136
+ # :flavor
137
+ # TODO: HSRP packets don't tend have any flavor.
138
+ # :config
139
+ # A hash of return address details, often the output of Utils.whoami?
140
+ class HSRPPacket < Packet
141
+
142
+ attr_accessor :eth_header, :ip_header, :udp_header, :hsrp_header
143
+
144
+ def self.can_parse?(str)
145
+ return false unless str.size >= 54
146
+ return false unless EthPacket.can_parse? str
147
+ return false unless IPPacket.can_parse? str
148
+ return false unless UDPPacket.can_parse? str
149
+ temp_packet = UDPPacket.new
150
+ temp_packet.read(str)
151
+ if temp_packet.ip_ttl == 1 and [temp_packet.udp_sport,temp_packet.udp_dport] == [1985,1985]
152
+ return true
153
+ else
154
+ return false
155
+ end
156
+ end
157
+
158
+ def read(str=nil, args={})
159
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
160
+ @eth_header.read(str)
161
+ @ip_header.read(str[14,str.size])
162
+ @eth_header.body = @ip_header
163
+ @udp_header.read(str[14+(@ip_header.ip_hlen),str.size])
164
+ @ip_header.body = @udp_header
165
+ @hsrp_header.read(str[14+(@ip_header.ip_hlen)+8,str.size])
166
+ @udp_header.body = @hsrp_header
167
+ super(args)
168
+ self
169
+ end
170
+
171
+ def initialize(args={})
172
+ @eth_header = EthHeader.new(args).read(args[:eth])
173
+ @ip_header = IPHeader.new(args).read(args[:ip])
174
+ @ip_header.ip_proto = 0x11
175
+ @udp_header = UDPHeader.new(args).read(args[:udp])
176
+ @hsrp_header = HSRPHeader.new(args).read(args[:hsrp])
177
+ @udp_header.body = @hsrp_header
178
+ @ip_header.body = @udp_header
179
+ @eth_header.body = @ip_header
180
+ @headers = [@eth_header, @ip_header, @udp_header, @hsrp_header]
181
+ super
182
+ end
183
+
184
+ # Peek provides summary data on packet contents.
185
+ def peek(args={})
186
+ peek_data = ["H "]
187
+ peek_data << "%-5d" % self.to_s.size
188
+ peek_data << "%-21s" % "#{self.hsrp_vip}:#{self.hsrp_group}:#{self.hsrp_password}"
189
+ peek_data << "%23s" % "U:"
190
+ peek_data << "%-21s" % "#{self.ip_saddr}:#{self.udp_sport}"
191
+ peek_data << "->"
192
+ peek_data << "%21s" % "#{self.ip_daddr}:#{self.udp_dport}"
193
+ peek_data.join
194
+ end
195
+
196
+ end
197
+
198
+ end
199
+
200
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -114,7 +114,26 @@ module PacketFu
114
114
  class ICMPPacket < Packet
115
115
 
116
116
  attr_accessor :eth_header, :ip_header, :icmp_header
117
-
117
+
118
+ def self.can_parse?(str)
119
+ return false unless str.size >= 54
120
+ return false unless EthPacket.can_parse? str
121
+ return false unless IPPacket.can_parse? str
122
+ return false unless str[23,1] == "\x01"
123
+ return true
124
+ end
125
+
126
+ def read(str=nil, args={})
127
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
128
+ @eth_header.read(str)
129
+ @ip_header.read(str[14,str.size])
130
+ @eth_header.body = @ip_header
131
+ @icmp_header.read(str[14+(@ip_header.ip_hlen),str.size])
132
+ @ip_header.body = @icmp_header
133
+ super(args)
134
+ self
135
+ end
136
+
118
137
  def initialize(args={})
119
138
  @eth_header = EthHeader.new(args).read(args[:eth])
120
139
  @ip_header = IPHeader.new(args).read(args[:ip])
@@ -30,6 +30,20 @@ module PacketFu
30
30
  class InvalidPacket < Packet
31
31
  attr_accessor :invalid_header
32
32
 
33
+ # Any packet is potentially an invalid packet
34
+ def self.can_parse?(str)
35
+ true
36
+ end
37
+
38
+ def self.layer
39
+ 0
40
+ end
41
+
42
+ def read(str=nil,args={})
43
+ @invalid_header.read(str)
44
+ self
45
+ end
46
+
33
47
  def initialize(args={})
34
48
  @invalid_header = (args[:invalid] || InvalidHeader.new)
35
49
  @headers = [@invalid_header]
@@ -175,6 +175,11 @@ module PacketFu
175
175
  (ip_hl * 4) + body.to_s.length
176
176
  end
177
177
 
178
+ # Return the claimed header length
179
+ def ip_hlen
180
+ (ip_hl * 4)
181
+ end
182
+
178
183
  # Calculate the true checksum of the packet.
179
184
  # (Yes, this is the long way to do it, but it's e-z-2-read for mathtards like me.)
180
185
  def ip_calc_sum
@@ -289,6 +294,30 @@ module PacketFu
289
294
 
290
295
  attr_accessor :eth_header, :ip_header
291
296
 
297
+ def self.can_parse?(str)
298
+ return false unless str.size >= 34
299
+ return false unless EthPacket.can_parse? str
300
+ if str[12,2] == "\x08\x00"
301
+ if 1.respond_to? :ord
302
+ ipv = str[14,1][0].ord >> 4
303
+ else
304
+ ipv = str[14,1][0] >> 4
305
+ end
306
+ return true if ipv == 4
307
+ else
308
+ return false
309
+ end
310
+ end
311
+
312
+ def read(str=nil, args={})
313
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
314
+ @eth_header.read(str)
315
+ @ip_header.read(str[14,str.size])
316
+ @eth_header.body = @ip_header
317
+ super(args)
318
+ self
319
+ end
320
+
292
321
  # Creates a new IPPacket object.
293
322
  def initialize(args={})
294
323
  @eth_header = EthHeader.new(args).read(args[:eth])
@@ -203,12 +203,27 @@ module PacketFu
203
203
 
204
204
  attr_accessor :eth_header, :ipv6_header
205
205
 
206
+ def self.can_parse?(str)
207
+ return false unless EthPacket.can_parse? str
208
+ return false unless str.size >= 54
209
+ return false unless str[12,2] == "\x86\xdd"
210
+ true
211
+ end
212
+
213
+ def read(str=nil,args={})
214
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
215
+ @eth_header.read(str)
216
+ @ipv6_header.read(str[14,str.size])
217
+ @eth_header.body = @ipv6_header
218
+ super(args)
219
+ self
220
+ end
221
+
206
222
  def initialize(args={})
207
223
  @eth_header = (args[:eth] || EthHeader.new)
208
224
  @ipv6_header = (args[:ipv6] || IPv6Header.new)
209
225
  @eth_header.eth_proto = 0x86dd
210
226
  @eth_header.body=@ipv6_header
211
-
212
227
  @headers = [@eth_header, @ipv6_header]
213
228
  super
214
229
  end
@@ -920,8 +920,32 @@ module PacketFu
920
920
  # A hash of return address details, often the output of Utils.whoami?
921
921
  class TCPPacket < Packet
922
922
 
923
- attr_accessor :eth_header, :ip_header, :tcp_header, :headers
924
-
923
+ attr_accessor :eth_header, :ip_header, :tcp_header
924
+
925
+ def self.can_parse?(str)
926
+ return false unless str.size >= 54
927
+ return false unless EthPacket.can_parse? str
928
+ return false unless IPPacket.can_parse? str
929
+ return false unless str[23,1] == "\x06"
930
+ return true
931
+ end
932
+
933
+ def read(str=nil, args={})
934
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
935
+ @eth_header.read(str)
936
+ @ip_header.read(str[14,str.size])
937
+ @eth_header.body = @ip_header
938
+ if args[:strip]
939
+ tcp_len = str[16,2].unpack("n")[0] - 20
940
+ @tcp_header.read(str[14+(@ip_header.ip_hlen),tcp_len])
941
+ else
942
+ @tcp_header.read(str[14+(@ip_header.ip_hlen),str.size])
943
+ end
944
+ @ip_header.body = @tcp_header
945
+ super(args)
946
+ self
947
+ end
948
+
925
949
  def initialize(args={})
926
950
  @eth_header = (args[:eth] || EthHeader.new)
927
951
  @ip_header = (args[:ip] || IPHeader.new)