Skip to content

Commit bd4738b

Browse files
committed
Land rapid7#4827, capture and nbns fixups
2 parents 47a7f99 + d7fa0ec commit bd4738b

File tree

5 files changed

+186
-159
lines changed

5 files changed

+186
-159
lines changed

lib/msf/core/exploit/capture.rb

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def initialize(info = {})
4242
[
4343
true,
4444
'Send a TTL=1 random UDP datagram to this host to discover the default gateway\'s MAC',
45-
'www.metasploit.com']),
45+
'8.8.8.8']),
4646
OptPort.new('GATEWAY_PROBE_PORT',
4747
[
4848
false,
@@ -143,7 +143,6 @@ def close_pcap
143143
return unless self.capture
144144
self.capture = nil
145145
self.arp_capture = nil
146-
GC.start()
147146
end
148147

149148
def capture_extract_ies(raw)
@@ -163,26 +162,15 @@ def capture_extract_ies(raw)
163162
end
164163

165164
#
166-
# This monstrosity works around a series of bugs in the interrupt
167-
# signal handling of Ruby 1.9
165+
# Loop through each packet
168166
#
169167
def each_packet
170168
return unless capture
171-
begin
172-
@capture_count = 0
173-
reader = framework.threads.spawn("PcapReceiver", false) do
174-
capture.each do |pkt|
175-
yield(pkt)
176-
@capture_count += 1
177-
end
178-
end
179-
reader.join
180-
rescue ::Exception
181-
raise $!
182-
ensure
183-
reader.kill if reader.alive?
169+
@capture_count ||= 0
170+
capture.each do |pkt|
171+
yield(pkt)
172+
@capture_count += 1
184173
end
185-
186174
@capture_count
187175
end
188176

@@ -242,10 +230,9 @@ def inject_pcap(pcap_file, filter=nil, delay = 0, pcap=self.capture)
242230
pcap.inject(pkt)
243231
Rex.sleep((delay * 1.0)/1000)
244232
end
245-
GC.start
246233
end
247234

248-
# Capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires
235+
# capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires
249236
# a payload and a destination address. To send to the broadcast address, set bcast
250237
# to true (this will guarantee that packets will be sent even if ARP doesn't work
251238
# out).
@@ -262,24 +249,20 @@ def capture_sendto(payload="", dhost=nil, bcast=false, dev=nil)
262249

263250
# The return value either be a PacketFu::Packet object, or nil
264251
def inject_reply(proto=:udp, pcap=self.capture)
265-
reply = nil
266-
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
267-
if not pcap
268-
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)"
269-
else
270-
begin
271-
::Timeout.timeout(to) do
272-
pcap.each do |r|
273-
packet = PacketFu::Packet.parse(r)
274-
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
275-
reply = packet
276-
break
277-
end
252+
# Defaults to ~2 seconds
253+
to = (datastore['TIMEOUT'] * 4) / 1000.0
254+
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" if not pcap
255+
begin
256+
::Timeout.timeout(to) do
257+
pcap.each do |r|
258+
packet = PacketFu::Packet.parse(r)
259+
next unless packet.proto.map { |x| x.downcase.to_sym }.include? proto
260+
return packet
278261
end
279-
rescue ::Timeout::Error
280262
end
263+
rescue ::Timeout::Error
281264
end
282-
return reply
265+
nil
283266
end
284267

285268
# This ascertains the correct Ethernet addresses one should use to
@@ -328,20 +311,19 @@ def probe_gateway(addr)
328311
end
329312

330313
begin
331-
to = (datastore['TIMEOUT'] || 1500).to_f / 1000.0
314+
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
332315
::Timeout.timeout(to) do
333-
while (my_packet = inject_reply(:udp, self.arp_capture))
334-
if my_packet.payload == secret
335-
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
336-
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
337-
return [dst_mac, src_mac]
338-
else
339-
next
340-
end
316+
loop do
317+
my_packet = inject_reply(:udp, self.arp_capture)
318+
next unless my_packet
319+
next unless my_packet.payload == secret
320+
dst_mac = self.arp_cache[:gateway] = my_packet.eth_daddr
321+
src_mac = self.arp_cache[Rex::Socket.source_address(addr)] = my_packet.eth_saddr
322+
return [dst_mac, src_mac]
341323
end
342324
end
343325
rescue ::Timeout::Error
344-
# Well, that didn't work (this common on networks where there's no gatway, like
326+
# Well, that didn't work (this is common on networks where there's no gateway, like
345327
# VMWare network interfaces. We'll need to use a fake source hardware address.
346328
self.arp_cache[Rex::Socket.source_address(addr)] = "00:00:00:00:00:00"
347329
end
@@ -354,26 +336,31 @@ def arp(target_ip=nil)
354336
return self.arp_cache[:gateway] unless should_arp? target_ip
355337
source_ip = Rex::Socket.source_address(target_ip)
356338
raise RuntimeError, "Could not access the capture process." unless self.arp_capture
339+
357340
p = arp_packet(target_ip, source_ip)
358-
inject_eth(:eth_type => 0x0806,
359-
:payload => p,
360-
:pcap => self.arp_capture,
361-
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
362-
)
363-
begin
364-
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
365-
::Timeout.timeout(to) do
366-
while (my_packet = inject_reply(:arp, self.arp_capture))
367-
if my_packet.arp_saddr_ip == target_ip
341+
342+
# Try up to 3 times to get an ARP response
343+
1.upto(3) do
344+
inject_eth(:eth_type => 0x0806,
345+
:payload => p,
346+
:pcap => self.arp_capture,
347+
:eth_saddr => self.arp_cache[Rex::Socket.source_address(target_ip)]
348+
)
349+
begin
350+
to = ((datastore['TIMEOUT'] || 500).to_f * 8) / 1000.0
351+
::Timeout.timeout(to) do
352+
loop do
353+
my_packet = inject_reply(:arp, self.arp_capture)
354+
next unless my_packet
355+
next unless my_packet.arp_saddr_ip == target_ip
368356
self.arp_cache[target_ip] = my_packet.eth_saddr
369357
return self.arp_cache[target_ip]
370-
else
371-
next
372358
end
373359
end
360+
rescue ::Timeout::Error
374361
end
375-
rescue ::Timeout::Error
376362
end
363+
nil
377364
end
378365

379366
# Creates a full ARP packet, mainly for use with inject_eth()

lib/msf/core/exploit/ipv6.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ def close_icmp_pcap()
7676

7777
return if not @ipv6_icmp6_capture
7878
@ipv6_icmp6_capture = nil
79-
GC.start()
8079
end
8180

8281
#

modules/auxiliary/spoof/arp/arp_poisoning.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ def run
103103

104104
if datastore['LISTENER']
105105
@listener.kill if @listener
106-
GC.start()
107106
end
108107

109108
if capture and @spoofing and not datastore['BROADCAST']

modules/auxiliary/spoof/llmnr/llmnr_response.rb

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,7 @@ def dispatch_request(packet, rhost, src_port)
139139
end
140140
ip_pkt.recalc
141141

142-
open_pcap
143-
capture_sendto(ip_pkt, rhost.to_s, true)
144-
close_pcap
142+
capture_sendto(ip_pkt, rhost.to_s, true)
145143
end
146144

147145
def monitor_socket
@@ -176,7 +174,10 @@ def should_print_reply?(host)
176174

177175
def run
178176
check_pcaprub_loaded()
179-
::Socket.do_not_reverse_lookup = true
177+
::Socket.do_not_reverse_lookup = true # Mac OS X workaround
178+
179+
# Avoid receiving extraneous traffic on our send socket
180+
open_pcap({'FILTER' => 'ether host f0:f0:f0:f0:f0:f0'})
180181

181182
# Multicast Address for LLMNR
182183
multicast_addr = ::IPAddr.new("224.0.0.252")
@@ -191,24 +192,28 @@ def run
191192
self.sock = Rex::Socket.create_udp(
192193
# This must be INADDR_ANY to receive multicast packets
193194
'LocalHost' => "0.0.0.0",
194-
'LocalPort' => 5355)
195+
'LocalPort' => 5355,
196+
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
197+
)
195198
self.sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
196199
self.sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_ADD_MEMBERSHIP, optval)
197200

198201
self.thread = Rex::ThreadFactory.spawn("LLMNRServerMonitor", false) {
199-
monitor_socket
202+
monitor_socket
200203
}
201204

202205
print_status("LLMNR Spoofer started. Listening for LLMNR requests with REGEX \"#{datastore['REGEX']}\" ...")
203206

204207
add_socket(self.sock)
205208

206-
while thread.alive?
207-
select(nil, nil, nil, 0.25)
208-
end
209-
210-
self.thread.kill
211-
self.sock.close rescue nil
209+
self.thread.join
212210
end
213211

212+
def cleanup
213+
if self.thread and self.thread.alive?
214+
self.thread.kill
215+
self.thread = nil
216+
end
217+
close_pcap
218+
end
214219
end

0 commit comments

Comments
 (0)