CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/core/exploit/capture.rb
Views: 1904
1
# -*- coding: binary -*-
2
module Msf
3
4
###
5
#
6
# This module provides methods for sending and receiving
7
# raw packets. It should be preferred over the soon-to-be
8
# deprecated Rex::Socket::Ip and Msf::Exploit::Remote::Ip
9
# mixins.
10
#
11
# Please see the pcaprub documentation for more information
12
# on how to use capture objects.
13
#
14
###
15
16
class Exploit
17
module Capture
18
19
#
20
# Initializes an instance of an exploit module that captures traffic
21
#
22
23
def initialize(info = {})
24
super
25
26
register_options(
27
[
28
OptPath.new('PCAPFILE', [false, 'The name of the PCAP capture file to process']),
29
OptString.new('INTERFACE', [false, 'The name of the interface']),
30
OptString.new('FILTER', [false, 'The filter string for capturing traffic']),
31
OptInt.new('SNAPLEN', [true, 'The number of bytes to capture', 65535]),
32
OptInt.new('TIMEOUT', [true, 'The number of seconds to wait for new data', 500]),
33
Opt::RHOST
34
35
], Msf::Exploit::Capture
36
)
37
38
register_advanced_options(
39
[
40
OptInt.new('SECRET', [true, 'A 32-bit cookie for probe requests.', 'MSF!'.unpack('N').first]),
41
OptAddress.new('GATEWAY_PROBE_HOST',
42
[
43
true,
44
'Send a TTL=1 random UDP datagram to this host to discover the default gateway\'s MAC',
45
'8.8.8.8']),
46
OptPort.new('GATEWAY_PROBE_PORT',
47
[
48
false,
49
'The port on GATEWAY_PROBE_HOST to send a random UDP probe to (random if 0 or unset)'])
50
], Msf::Exploit::Capture
51
)
52
53
begin
54
require 'packetfu'
55
require 'pcaprub'
56
@pcaprub_loaded = true
57
rescue ::LoadError => e
58
@pcaprub_loaded = false
59
@pcaprub_error = e
60
end
61
62
begin
63
require 'network_interface'
64
@network_interface_loaded = true
65
rescue ::LoadError => e
66
@network_interface_loaded = false
67
@network_interface_error = e
68
end
69
70
end
71
72
def stats_recv(pcap=self.capture)
73
return(0) unless pcap
74
pcap.stats['recv']
75
end
76
77
def stats_drop(pcap=self.capture)
78
return(0) unless pcap
79
pcap.stats['drop']
80
end
81
82
def stats_ifdrop(pcap=self.capture)
83
return(0) unless pcap
84
pcap.stats['ifdrop']
85
end
86
87
#
88
# Opens a handle to the specified device
89
#
90
def open_pcap(opts={})
91
check_pcaprub_loaded
92
if RUBY_PLATFORM == "i386-mingw32"
93
if opts['INTERFACE'] or datastore['INTERFACE']
94
dev = opts['INTERFACE'] || datastore['INTERFACE']
95
if is_interface?(dev)
96
dev = get_interface_guid(dev)
97
end
98
end
99
else
100
dev = opts['INTERFACE'] || datastore['INTERFACE'] || nil
101
end
102
103
len = (opts['SNAPLEN'] || datastore['SNAPLEN'] || 65535).to_i
104
tim = (opts['TIMEOUT'] || datastore['TIMEOUT'] || 0).to_i
105
fil = opts['FILTER'] || datastore['FILTER']
106
do_arp = (opts['ARPCAP'] == false) ? false : true
107
108
# Look for a PCAP file
109
cap = datastore['PCAPFILE'] || ''
110
111
if (not cap.empty?)
112
if (not File.exist?(cap))
113
raise RuntimeError, "The PCAP file #{cap} could not be found"
114
end
115
self.capture = ::Pcap.open_offline(cap)
116
else
117
dev ||= ::Pcap.lookupdev
118
119
unless RUBY_PLATFORM == "i386-mingw32"
120
system("ifconfig", dev, "up")
121
end
122
123
self.capture = ::Pcap.open_live(dev, len, true, tim)
124
if do_arp
125
self.arp_capture = ::Pcap.open_live(dev, 512, true, tim)
126
preamble = datastore['SECRET'].to_i
127
arp_filter = "arp[6:2] = 2 or (udp[8:4] = #{preamble})"
128
self.arp_capture.setfilter(arp_filter)
129
end
130
end
131
132
if (not self.capture)
133
raise RuntimeError, "Could not start the capture process"
134
elsif (do_arp and !self.arp_capture and cap.empty?)
135
raise RuntimeError, "Could not start the ARP capture process"
136
end
137
138
self.capture.setfilter(fil) if fil
139
end
140
141
def close_pcap
142
return unless self.capture
143
self.capture = nil
144
self.arp_capture = nil
145
end
146
147
def capture_extract_ies(raw)
148
set = {}
149
idx = 0
150
len = 0
151
152
while (idx < raw.length)
153
len = raw[idx+1]
154
return set unless len
155
set[raw[idx]] ||= []
156
set[raw[idx]].push(raw[idx + 2, len])
157
idx += len + 2
158
end
159
160
return set
161
end
162
163
#
164
# Loop through each packet
165
#
166
def each_packet
167
return unless capture
168
@capture_count ||= 0
169
capture.each do |pkt|
170
yield(pkt)
171
@capture_count += 1
172
end
173
@capture_count
174
end
175
176
# Injects a packet on the wire. For all injection-related functions, it's
177
# on the module to open up a capture device first (this way, we don't
178
# needlessly spawn new capture devices).
179
def inject(pkt="", pcap=self.capture)
180
check_pcaprub_loaded
181
if not pcap
182
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)"
183
else
184
pcap.inject(pkt.to_s) # Can be a PacketFu Packet object or a pre-packed string
185
end
186
end
187
188
# Injects an Ethernet packet with an optional payload. The payload
189
# may be a regular PacketFu packet, an EthHeader, or a string.
190
def inject_eth(args={})
191
eth_daddr = args[:eth_daddr] || "ff:ff:ff:ff:ff:ff"
192
eth_saddr = args[:eth_saddr] || "00:00:00:00:00:00"
193
eth_type = args[:eth_type] || 0x0800 # IP default
194
payload = args[:payload]
195
pcap = args[:pcap] || self.capture
196
p = PacketFu::EthPacket.new
197
p.eth_daddr = eth_daddr
198
p.eth_saddr = eth_saddr
199
p.eth_proto = eth_type
200
if payload
201
if payload.kind_of? PacketFu::EthPacket
202
p.payload = payload.eth_header.body
203
elsif payload.kind_of? PacketFu::EthHeader
204
p.payload = payload.body
205
else
206
p.payload = payload.to_s
207
end
208
end
209
inject p.to_s, pcap
210
end
211
212
def inject_pcap(pcap_file, filter=nil, delay = 0, pcap=self.capture)
213
check_pcaprub_loaded
214
unless pcap
215
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)"
216
end
217
218
if (not File.exist?(pcap_file))
219
raise RuntimeError, "The PCAP file #{pcap_file} could not be found"
220
end
221
222
if (pcap_file.empty?)
223
raise RuntimeError, "The PCAP file #{pcap_file} is empty"
224
end
225
226
capture_file = ::Pcap.open_offline(pcap_file)
227
capture_file.setfilter(filter) if filter
228
while (pkt = capture_file.next) do
229
pcap.inject(pkt)
230
Rex.sleep((delay * 1.0)/1000)
231
end
232
end
233
234
# Sends a payload to a given target using the pcap capture interface
235
#
236
# == Parameters:
237
# payload:: The payload String to send
238
# dhost:: the destination host to send to
239
# bcast:: set to `true` to send to the broadcast address if necessary
240
# dev:: the name of the network interface to send the payload on
241
#
242
# == Returns:
243
# The number of bytes sent iff the payload was successfully sent/injected. `false` otherwise
244
def capture_sendto(payload="", dhost=nil, bcast=false, dev=nil)
245
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" unless self.capture
246
raise RuntimeError, "Must specify a host to sendto" unless dhost
247
dev ||= datastore['INTERFACE']
248
dst_mac, src_mac = lookup_eth(dhost, dev)
249
if dst_mac == nil and not bcast
250
vprint_error("Unable to determine the destination MAC for #{dhost} on #{dev} and bcast is false")
251
return false
252
end
253
inject_eth(:payload => payload, :eth_daddr => dst_mac, :eth_saddr => src_mac)
254
end
255
256
# The return value either be a PacketFu::Packet object, or nil
257
def inject_reply(proto=:udp, pcap=self.capture)
258
# Defaults to ~2 seconds
259
to = ((datastore['TIMEOUT'] || 500).to_f * 4) / 1000.0
260
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" if not pcap
261
begin
262
::Timeout.timeout(to) do
263
pcap.each do |r|
264
packet = PacketFu::Packet.parse(r)
265
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
266
return packet
267
end
268
end
269
rescue ::Timeout::Error
270
end
271
nil
272
end
273
274
# This ascertains the correct Ethernet addresses one should use to
275
# ensure injected IP packets actually get where they are going, and
276
# manages the self.arp_cache hash. It always uses self.arp_capture
277
# to inject and capture packets, and will always first fire off a
278
# UDP packet using the regular socket to learn the source host's
279
# and gateway's mac addresses.
280
def lookup_eth(addr=nil, iface=nil)
281
raise RuntimeError, "Could not access the capture process." unless self.arp_capture
282
283
self.arp_cache ||= {}
284
self.dst_cache ||= {}
285
286
return self.dst_cache[addr] if self.dst_cache[addr]
287
288
if !self.arp_cache[Rex::Socket.source_address(addr)]
289
probe_gateway(addr)
290
end
291
292
src_mac = self.arp_cache[Rex::Socket.source_address(addr)]
293
if should_arp?(addr)
294
dst_mac = self.arp_cache[addr] || arp(addr)
295
else
296
dst_mac = self.arp_cache[:gateway]
297
end
298
299
self.dst_cache[addr] = [dst_mac, src_mac]
300
end
301
302
def probe_gateway(addr)
303
dst_host = datastore['GATEWAY_PROBE_HOST']
304
dst_port = datastore['GATEWAY_PROBE_PORT'].to_i == 0 ? rand(30000) + 1024 : datastore['GATEWAY_PROBE_PORT']
305
preamble = [datastore['SECRET']].pack("N")
306
secret = "#{preamble}#{Rex::Text.rand_text(rand(0xff)+1)}"
307
308
begin
309
UDPSocket.open do |sock|
310
sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_TTL, 1)
311
sock.send(secret, 0, dst_host, dst_port)
312
end
313
rescue Errno::ENETUNREACH
314
# This happens on networks with no gateway. We'll need to use a
315
# fake source hardware address.
316
self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00"
317
end
318
319
begin
320
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
321
::Timeout.timeout(to) do
322
loop do
323
my_packet = inject_reply(:udp, self.arp_capture)
324
next unless my_packet
325
next unless my_packet.payload == secret
326
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
327
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
328
return [dst_mac, src_mac]
329
end
330
end
331
rescue ::Timeout::Error
332
# Well, that didn't work (this is common on networks where there's no gateway, like
333
# VMWare network interfaces. We'll need to use a fake source hardware address.
334
self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00"
335
end
336
end
337
338
# A pure-Ruby ARP exchange. It uses self.arp_capture to send and recv
339
# packets, rather than self.capture.
340
def arp(target_ip=nil)
341
return self.arp_cache[target_ip] if self.arp_cache[target_ip]
342
return self.arp_cache[:gateway] unless should_arp? target_ip
343
source_ip = Rex::Socket.source_address(target_ip)
344
raise RuntimeError, "Could not access the capture process." unless self.arp_capture
345
346
p = arp_packet(target_ip, source_ip)
347
348
# Try up to 3 times to get an ARP response
349
1.upto(3) do
350
inject_eth(:eth_type => 0x0806,
351
:payload => p,
352
:pcap => self.arp_capture,
353
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
354
)
355
begin
356
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
357
::Timeout.timeout(to) do
358
loop do
359
my_packet = inject_reply(:arp, self.arp_capture)
360
next unless my_packet
361
next unless my_packet.arp_saddr_ip == target_ip
362
self.arp_cache[target_ip] = my_packet.eth_saddr
363
return self.arp_cache[target_ip]
364
end
365
end
366
rescue ::Timeout::Error
367
end
368
end
369
nil
370
end
371
372
# Creates a full ARP packet, mainly for use with inject_eth()
373
def arp_packet(target_ip=nil, source_ip=nil)
374
p = PacketFu::ARPPacket.new
375
p.arp_opcode = 1
376
p.arp_daddr_ip = target_ip || datastore['RHOST']
377
p.arp_saddr_ip = source_ip || datastore['LHOST']
378
my_eth = self.arp_cache[Rex::Socket.source_address(target_ip)]
379
p.arp_saddr_mac = my_eth || "00:00:00:00:00:00"
380
return p
381
end
382
383
# Allow modules to reset their arp caches arbitrarily.
384
def expire_arpcache
385
self.arp_cache = {}
386
end
387
388
# For compatibility with Msf::Exploit::Remote::Ip
389
def rhost
390
datastore['RHOST']
391
end
392
393
def check_pcaprub_loaded
394
if not @pcaprub_loaded
395
print_status("The Pcaprub module is not available: #{@pcaprub_error}")
396
raise RuntimeError, "Pcaprub not available"
397
elsif not @network_interface_loaded
398
print_status("The NetworkInterface module is not available: #{@network_interface_error}")
399
raise RuntimeError, "NetworkInterface not available"
400
else
401
true
402
end
403
end
404
405
def lookupnet
406
check_pcaprub_loaded
407
dev = datastore['INTERFACE'] || ::Pcap.lookupdev
408
begin
409
my_ip, my_mask = Pcap.lookupnet(dev)
410
# convert the netmask obtained from the relevant interface to CIDR
411
cidr_mask = my_mask.to_s(2).count('1')
412
my_net = IPAddr.new("#{my_ip}/#{cidr_mask}")
413
rescue RuntimeError => e
414
@pcaprub_error = e
415
print_status("Cannot stat device: #{@pcaprub_error}")
416
raise RuntimeError, "Pcaprub error: #{@pcaprub_error}"
417
end
418
return my_net
419
end
420
421
def should_arp?(ip)
422
lookupnet.include?(IPAddr.new(ip))
423
end
424
425
attr_accessor :capture, :arp_cache, :arp_capture, :dst_cache
426
427
# Netifaces code
428
429
def netifaces_implemented?
430
@network_interface_loaded and
431
NetworkInterface.respond_to?(:interfaces) and
432
NetworkInterface.respond_to?(:addresses)
433
end
434
435
def list_interfaces
436
check_pcaprub_loaded
437
NetworkInterface.interfaces
438
end
439
440
def is_interface?(dev)
441
check_pcaprub_loaded
442
if RUBY_PLATFORM == "i386-mingw32"
443
if dev =~ /\\Device\\NPF_\{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}\}/
444
return NetworkInterface.interfaces.include?(dev)
445
elsif dev.to_s =~ /^[0-9]{1,2}$/
446
if (dev.to_i <= NetworkInterface.interfaces.length) and (dev.to_i >= 0)
447
return true
448
else
449
return false
450
end
451
else
452
return false
453
end
454
else
455
return NetworkInterface.interfaces.include?(dev)
456
end
457
end
458
459
# This function is useful only on windows where pcaprub use the GUID
460
def get_interface_guid(dev)
461
check_pcaprub_loaded
462
if RUBY_PLATFORM == "i386-mingw32"
463
if dev.to_s =~ /^[0-9]{1,2}$/
464
if is_interface?(dev)
465
NetworkInterface.interfaces[(dev.to_i) - 1]
466
else
467
return dev
468
end
469
else
470
return dev
471
end
472
else #Non windows
473
return dev
474
end
475
end
476
477
def get_mac(dev)
478
check_pcaprub_loaded
479
dev = get_interface_guid(dev)
480
addrs = NetworkInterface.addresses(dev)
481
raise RuntimeError, "Interface #{dev} does not exist" if !addrs
482
raise RuntimeError, "Cannot get mac address for interface #{dev}" if !addrs[NetworkInterface::AF_LINK][0]['addr']
483
addrs[NetworkInterface::AF_LINK][0]['addr']
484
end
485
486
def get_ipv4_addr_count(dev)
487
check_pcaprub_loaded
488
dev = get_interface_guid(dev)
489
addrs = NetworkInterface.addresses(dev)
490
raise RuntimeError, "Interface #{dev} does not exist" if !addrs
491
addrs[NetworkInterface::AF_INET].length
492
end
493
494
def get_ipv4_addr(dev, num=0)
495
check_pcaprub_loaded
496
dev = get_interface_guid(dev)
497
addrs = NetworkInterface.addresses(dev)
498
raise RuntimeError, "Interface #{dev} does not exist" if !addrs
499
raise RuntimeError, "Interface #{dev} does not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1
500
raise RuntimeError, "Cannot get the IPv4 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['addr']
501
addrs[NetworkInterface::AF_INET][num]['addr']
502
end
503
504
def get_ipv4_netmask(dev, num=0)
505
check_pcaprub_loaded
506
dev = get_interface_guid(dev)
507
addrs = NetworkInterface.addresses(dev)
508
raise RuntimeError, "Interface #{dev} does not exist" if !addrs
509
raise RuntimeError, "Interface #{dev} does not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1
510
raise RuntimeError, "Cannot get IPv4 netmask for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['netmask']
511
addrs[NetworkInterface::AF_INET][num]['netmask']
512
end
513
514
def get_ipv4_broadcast(dev, num=0)
515
check_pcaprub_loaded
516
dev = get_interface_guid(dev)
517
addrs = NetworkInterface.addresses(dev)
518
raise RuntimeError, "Interface #{dev} do not exists" if !addrs
519
raise RuntimeError, "Interface #{dev} do not have an ipv4 address at position #{num}" if addrs[NetworkInterface::AF_INET].length < num + 1
520
raise RuntimeError, "Cannot get IPv4 broadcast address for interface #{dev}" if !addrs[NetworkInterface::AF_INET][num]['broadcast']
521
addrs[NetworkInterface::AF_INET][num]['broadcast']
522
end
523
524
def get_ipv6_addr_count(dev)
525
check_pcaprub_loaded
526
dev = get_interface_guid(dev)
527
raise RuntimeError, "IPv6 information is not available on this platform" unless ::NetworkInterface.const_defined?(:AF_INET6)
528
addrs = NetworkInterface.addresses(dev)
529
raise RuntimeError, "Interface #{dev} do not exists" if !addrs
530
addrs[NetworkInterface::AF_INET6].length
531
end
532
533
# NOTE: IPv6 is not implemented on Windows
534
def get_ipv6_addr(dev, num=0)
535
check_pcaprub_loaded
536
dev = get_interface_guid(dev)
537
raise RuntimeError, "IPv6 information is not available on this platform" unless ::NetworkInterface.const_defined?(:AF_INET6)
538
addrs = NetworkInterface.addresses(dev)
539
raise RuntimeError, "Interface #{dev} do not exists" if !addrs
540
raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1
541
raise RuntimeError, "Cannot get ipv6 address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['addr']
542
addrs[NetworkInterface::AF_INET6][num]['addr'].gsub(/%(.)*$/, '')
543
end
544
545
def get_ipv6_netmask(dev, num=0)
546
check_pcaprub_loaded
547
dev = get_interface_guid(dev)
548
raise RuntimeError, "IPv6 information is not available on this platform" unless ::NetworkInterface.const_defined?(:AF_INET6)
549
addrs = NetworkInterface.addresses(dev)
550
raise RuntimeError, "Interface #{dev} do not exists" if !addrs
551
raise RuntimeError, "Interface #{dev} do not have an ipv6 address at position #{num}" if addrs[NetworkInterface::AF_INET6].length < num + 1
552
raise RuntimeError, "Cannot get ipv6 netmask address for interface #{dev}" if !addrs[NetworkInterface::AF_INET6][num]['netmask']
553
addrs[NetworkInterface::AF_INET6][num]['netmask']
554
end
555
556
# Protocol-specific encoding/decoding methods until more
557
# application protos get into PacketFu proper
558
559
# Intended to be used as the payload to an ICMP echo request's payload
560
def capture_icmp_echo_pack(id=nil, seq=nil, payload=nil)
561
id ||= rand(0x10000)
562
seq ||= rand(0x10000)
563
[id, seq, payload.to_s].pack("nna*")
564
end
565
566
# Decodes and ICMP echo request or response.
567
def capture_icmp_echo_unpack(data)
568
data.unpack("nna*")
569
end
570
571
end
572
573
end
574
575
end
576
577