packetfu 1.0.0 → 1.0.2.pre

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