Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/netbios/nbname.rb
19715 views
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::Auxiliary::Report
8
include Msf::Auxiliary::UDPScanner
9
10
def initialize
11
super(
12
'Name' => 'NetBIOS Information Discovery',
13
'Description' => 'Discover host information through NetBIOS',
14
'Author' => 'hdm',
15
'License' => MSF_LICENSE
16
)
17
18
register_options(
19
[
20
Opt::RPORT(137)
21
]
22
)
23
end
24
25
def scanner_prescan(batch)
26
print_status("Sending NetBIOS requests to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
27
@results = {}
28
end
29
30
def scan_host(ip)
31
scanner_send(create_netbios_status(ip), ip, datastore['RPORT'])
32
end
33
34
def scanner_postscan(batch)
35
cnt = 0
36
37
# Perform a second pass based on responsive hosts
38
@results.keys.each do |ip|
39
next if not @results[ip][:name]
40
41
scanner_send(create_netbios_lookup(@results[ip][:name]), ip, datastore['RPORT'])
42
cnt += 1
43
end
44
45
# Wait for the final replies to trickle in
46
scanner_recv(10) if cnt > 0
47
48
@results.keys.each do |ip|
49
host = @results[ip]
50
user = ""
51
os = "Windows"
52
53
if (host[:user] and host[:mac] != "00:00:00:00:00:00")
54
user = " User:#{host[:user]}"
55
end
56
57
if (host[:mac] == "00:00:00:00:00:00")
58
os = "Unix"
59
end
60
61
names = ""
62
if (host[:names])
63
names = " Names:(" + host[:names].map { |n| n[0] }.uniq.join(", ") + ")"
64
end
65
66
addrs = ""
67
if (host[:addrs])
68
addrs = "Addresses:(" + host[:addrs].map { |n| n[0] }.uniq.join(", ") + ")"
69
end
70
71
if (host[:mac] != "00:00:00:00:00:00")
72
report_host(:host => ip, :mac => host[:mac])
73
else
74
report_host(:host => ip)
75
end
76
77
extra = ""
78
79
virtual = nil
80
case host[:mac]
81
when /^00:13:07/i
82
virtual = 'ParaVirtual'
83
when /^(00:1C:14|00:50:56|00:05:69|00:0c:29)/i
84
virtual = 'VMWare'
85
when /^00:1C:42/
86
virtual = "Parallels"
87
when /^00:18:51/
88
virtual = "SWsoft Virtuozzo"
89
when /^00:21:F6/i
90
virtual = 'Virtual Iron'
91
when /^00:16:3e/
92
virtual = 'Xen'
93
when /^(54:52:00|DE:AD:BE)/
94
virtual = 'QEMU (unofficial)'
95
when /^00:24:0B/i
96
virtual = 'Virtual Computer Inc'
97
end
98
99
if (virtual)
100
extra = "Virtual Machine:#{virtual}"
101
report_note(
102
:host => ip,
103
:type => 'host.virtual_machine',
104
:data => { :vendor => virtual, :method => 'netbios' }
105
)
106
end
107
108
if (host[:addrs])
109
aliases = []
110
host[:addrs].map { |n| n[0] }.uniq.each do |addr|
111
next if addr == ip
112
113
aliases << addr
114
end
115
116
if not aliases.empty?
117
report_note(
118
:host => ip,
119
:proto => 'udp',
120
:port => 137,
121
:type => 'netbios.addresses',
122
:data => { :addresses => aliases }
123
)
124
end
125
end
126
127
print_good("#{ip} [#{host[:name]}] OS:#{os}#{user}#{names} #{addrs} Mac:#{host[:mac]} #{extra}")
128
end
129
end
130
131
def scanner_process(data, shost, sport)
132
head = data.slice!(0, 12)
133
134
xid, flags, quests, answers, auths, adds = head.unpack('n6')
135
136
return if quests != 0
137
return if answers == 0
138
139
qname = data.slice!(0, 34)
140
rtype, rclass, rttl, rlen = data.slice!(0, 10).unpack('nnNn')
141
buff = data.slice!(0, rlen)
142
143
names = []
144
145
hname = nil
146
uname = nil
147
148
@results[shost] ||= {}
149
150
case rtype
151
when 0x21
152
rcnt = buff.slice!(0, 1).unpack("C")[0]
153
1.upto(rcnt) do
154
tname = buff.slice!(0, 15).gsub(/\x00.*/, '').strip
155
ttype = buff.slice!(0, 1).unpack("C")[0]
156
tflag = buff.slice!(0, 2).unpack('n')[0]
157
names << [ tname, ttype, tflag ]
158
hname = tname if ttype == 0x20
159
uname = tname if ttype == 0x03
160
end
161
maddr = buff.slice!(0, 6).unpack("C*").map { |c| "%.2x" % c }.join(":")
162
163
@results[shost][:names] = names
164
@results[shost][:mac] = maddr
165
166
if (!hname and @results[shost][:names].length > 0)
167
@results[shost][:name] = @results[shost][:names][0][0]
168
end
169
170
@results[shost][:name] = hname if hname
171
@results[shost][:user] = uname if uname
172
173
inf = ''
174
names.each do |name|
175
inf << name[0]
176
inf << ":<%.2x>" % name[1]
177
if (name[2] & 0x8000 == 0)
178
inf << ":U :"
179
else
180
inf << ":G :"
181
end
182
end
183
inf << maddr
184
185
report_service(
186
:host => shost,
187
:mac => (maddr and maddr != '00:00:00:00:00:00') ? maddr : nil,
188
:host_name => (hname) ? hname.downcase : nil,
189
:port => datastore['RPORT'],
190
:proto => 'udp',
191
:name => 'netbios',
192
:info => inf
193
)
194
195
when 0x20
196
1.upto(rlen / 6.0) do
197
tflag = buff.slice!(0, 2).unpack('n')[0]
198
taddr = buff.slice!(0, 4).unpack("C*").join(".")
199
names << [ taddr, tflag ]
200
end
201
@results[shost][:addrs] = names
202
end
203
end
204
205
def create_netbios_status(ip)
206
data =
207
[rand(0xffff)].pack('n') +
208
"\x00\x00\x00\x01\x00\x00\x00\x00" +
209
"\x00\x00\x20\x43\x4b\x41\x41\x41" +
210
"\x41\x41\x41\x41\x41\x41\x41\x41" +
211
"\x41\x41\x41\x41\x41\x41\x41\x41" +
212
"\x41\x41\x41\x41\x41\x41\x41\x41" +
213
"\x41\x41\x41\x00\x00\x21\x00\x01"
214
215
return data
216
end
217
218
def create_netbios_lookup(name)
219
name = [name].pack("A15") + "\x00"
220
221
data =
222
[rand(0xffff)].pack('n') +
223
"\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00" +
224
"\x20" +
225
Rex::Proto::SMB::Utils.nbname_encode(name) +
226
"\x00" +
227
"\x00\x20\x00\x01"
228
229
return data
230
end
231
end
232
233