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/scanner/netbios/nbname.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::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
end
23
24
def scanner_prescan(batch)
25
print_status("Sending NetBIOS requests to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
26
@results = {}
27
end
28
29
def scan_host(ip)
30
scanner_send(create_netbios_status(ip), ip, datastore['RPORT'])
31
end
32
33
def scanner_postscan(batch)
34
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
scanner_send(create_netbios_lookup(@results[ip][:name]), ip, datastore['RPORT'])
41
cnt += 1
42
end
43
44
# Wait for the final replies to trickle in
45
scanner_recv(10) if cnt > 0
46
47
@results.keys.each do |ip|
48
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
aliases << addr
113
end
114
115
if not aliases.empty?
116
report_note(
117
:host => ip,
118
:proto => 'udp',
119
:port => 137,
120
:type => 'netbios.addresses',
121
:data => {:addresses => aliases}
122
)
123
end
124
end
125
126
print_good("#{ip} [#{host[:name]}] OS:#{os}#{user}#{names} #{addrs} Mac:#{host[:mac]} #{extra}")
127
end
128
end
129
130
131
def scanner_process(data, shost, sport)
132
133
head = data.slice!(0,12)
134
135
xid, flags, quests, answers, auths, adds = head.unpack('n6')
136
137
return if quests != 0
138
return if answers == 0
139
140
qname = data.slice!(0,34)
141
rtype,rclass,rttl,rlen = data.slice!(0,10).unpack('nnNn')
142
buff = data.slice!(0,rlen)
143
144
names = []
145
146
hname = nil
147
uname = nil
148
149
@results[shost] ||= {}
150
151
case rtype
152
when 0x21
153
rcnt = buff.slice!(0,1).unpack("C")[0]
154
1.upto(rcnt) do
155
tname = buff.slice!(0,15).gsub(/\x00.*/, '').strip
156
ttype = buff.slice!(0,1).unpack("C")[0]
157
tflag = buff.slice!(0,2).unpack('n')[0]
158
names << [ tname, ttype, tflag ]
159
hname = tname if ttype == 0x20
160
uname = tname if ttype == 0x03
161
end
162
maddr = buff.slice!(0,6).unpack("C*").map{|c| "%.2x" % c }.join(":")
163
164
@results[shost][:names] = names
165
@results[shost][:mac] = maddr
166
167
if (!hname and @results[shost][:names].length > 0)
168
@results[shost][:name] = @results[shost][:names][0][0]
169
end
170
171
@results[shost][:name] = hname if hname
172
@results[shost][:user] = uname if uname
173
174
inf = ''
175
names.each do |name|
176
inf << name[0]
177
inf << ":<%.2x>" % name[1]
178
if (name[2] & 0x8000 == 0)
179
inf << ":U :"
180
else
181
inf << ":G :"
182
end
183
end
184
inf << maddr
185
186
report_service(
187
:host => shost,
188
:mac => (maddr and maddr != '00:00:00:00:00:00') ? maddr : nil,
189
:host_name => (hname) ? hname.downcase : nil,
190
:port => datastore['RPORT'],
191
:proto => 'udp',
192
:name => 'netbios',
193
:info => inf
194
)
195
196
when 0x20
197
1.upto(rlen / 6.0) do
198
tflag = buff.slice!(0,2).unpack('n')[0]
199
taddr = buff.slice!(0,4).unpack("C*").join(".")
200
names << [ taddr, tflag ]
201
end
202
@results[shost][:addrs] = names
203
end
204
end
205
206
def create_netbios_status(ip)
207
data =
208
[rand(0xffff)].pack('n')+
209
"\x00\x00\x00\x01\x00\x00\x00\x00"+
210
"\x00\x00\x20\x43\x4b\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\x41\x41\x41\x41\x41"+
214
"\x41\x41\x41\x00\x00\x21\x00\x01"
215
216
return data
217
end
218
219
def create_netbios_lookup(name)
220
name = [name].pack("A15") + "\x00"
221
222
data =
223
[rand(0xffff)].pack('n') +
224
"\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00" +
225
"\x20" +
226
Rex::Proto::SMB::Utils.nbname_encode(name) +
227
"\x00" +
228
"\x00\x20\x00\x01"
229
230
return data
231
end
232
end
233
234