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/post/windows/recon/computer_browser_discovery.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::Post
7
include Msf::Auxiliary::Report
8
9
def initialize(info = {})
10
super(
11
update_info(
12
info,
13
'Name' => 'Windows Recon Computer Browser Discovery',
14
'Description' => %q{
15
This module uses railgun to discover hostnames and IPs on the network.
16
LTYPE should be set to one of the following values: WK (all workstations), SVR (all servers),
17
SQL (all SQL servers), DC (all Domain Controllers), DCBKUP (all Domain Backup Servers),
18
NOVELL (all Novell servers), PRINTSVR (all Print Que servers), MASTERBROWSER (all Master Browsers),
19
WINDOWS (all Windows hosts), or UNIX (all Unix hosts).
20
},
21
'License' => MSF_LICENSE,
22
'Author' => [ 'mubix' ],
23
'Platform' => [ 'win' ],
24
'SessionTypes' => [ 'meterpreter' ],
25
'Compat' => {
26
'Meterpreter' => {
27
'Commands' => %w[
28
stdapi_net_resolve_host
29
stdapi_railgun_api
30
stdapi_railgun_memread
31
]
32
}
33
}
34
)
35
)
36
37
register_options(
38
[
39
OptString.new('LTYPE', [true, 'Account informations (type info for known types)', 'WK']), # Enum would be a better choice
40
OptString.new('DOMAIN', [false, 'Domain to perform lookups on, default is current domain', nil]),
41
OptBool.new('SAVEHOSTS', [true, 'Save Discovered Hosts to the Database', false])
42
]
43
)
44
end
45
46
def parse_netserverenum(startmem, count)
47
base = 0
48
sys_list = []
49
mem = client.railgun.memread(startmem, 24 * count)
50
51
count.times do |_i|
52
x = {}
53
x[:platform_id] = mem[(base + 0), 4].unpack('V*')[0]
54
cnameptr = mem[(base + 4), 4].unpack('V*')[0]
55
x[:major_ver] = mem[(base + 8), 4].unpack('V*')[0]
56
x[:minor_ver] = mem[(base + 12), 4].unpack('V*')[0]
57
x[:type] = mem[(base + 16), 4].unpack('V*')[0]
58
commentptr = mem[(base + 20), 4].unpack('V*')[0]
59
60
x[:cname] = client.railgun.memread(cnameptr, 27).split("\0\0")[0].split("\0").join
61
x[:comment] = client.railgun.memread(commentptr, 255).split("\0\0")[0].split("\0").join
62
sys_list << x
63
base += 24
64
vprint_status("Identified: #{x[:cname]} - #{x[:comment]}")
65
end
66
return sys_list
67
end
68
69
def run
70
### MAIN ###
71
client = session
72
73
domain = nil
74
75
# Default = SV_TYPE_NT
76
# Servers = SV_TYPE_ALL
77
# Workstations = SV_TYPE_WORKSTATION
78
# Domain Controllers = SV_TYPE_DOMAINCTRL
79
# Novell Server = SV_TYPE_NOVELL
80
# Terminal Servers = SV_TYPE_TERMINALSERVER
81
# SQL Servers = SV_TYPE_SQLSERVER
82
lookuptype = 1
83
84
case datastore['LTYPE']
85
when 'WK' then lookuptype = '1'.hex
86
when 'SVR' then lookuptype = '2'.hex
87
when 'SQL' then lookuptype = '4'.hex
88
when 'DC' then lookuptype = '8'.hex
89
when 'DCBKUP' then lookuptype = '10'.hex
90
when 'TIME' then lookuptype = '20'.hex
91
when 'NOVELL' then lookuptype = '80'.hex
92
when 'PRINTSVR' then lookuptype = '200'.hex
93
when 'MASTERBROWSER' then lookuptype = '40000'.hex
94
when 'WINDOWS' then lookuptype = '400000'.hex
95
when 'UNIX' then lookuptype = '800'.hex
96
when 'LOCAL' then lookuptype = '40000000'.hex
97
end
98
99
if session.arch == ARCH_X64
100
nameiterator = 8
101
size = 64
102
addrinfoinmem = 32
103
else
104
nameiterator = 4
105
size = 32
106
addrinfoinmem = 24
107
end
108
109
result = client.railgun.netapi32.NetServerEnum(nil, 101, 4, -1, 4, 4, lookuptype, datastore['DOMAIN'], 0)
110
111
if result['totalentries'] == 0
112
print_error('No systems found of that type')
113
return
114
end
115
print_good("Found #{result['totalentries']} systems.")
116
117
endofline = 0
118
i = nameiterator
119
netview = parse_netserverenum(result['bufptr'], result['totalentries'])
120
121
## get IP for host
122
begin
123
netview.each do |x|
124
vprint_status("Looking up IP for #{x[:cname]}")
125
print '.'
126
result = client.net.resolve.resolve_host(x[:cname])
127
if result[:ip].nil? || result[:ip].blank?
128
print_error("There was an error resolving the IP for #{x[:cname]}")
129
next
130
else
131
x[:ip] = result[:ip]
132
end
133
end
134
rescue ::Exception => e
135
print_error(e)
136
print_status('Windows 2000 and prior does not support getaddrinfo')
137
end
138
139
netview = netview.sort_by { |e| e[:type] }
140
141
results = Rex::Text::Table.new(
142
'Header' => 'Netdiscovery Results',
143
'Indent' => 2,
144
'Columns' => ['TYPE', 'IP', 'COMPUTER NAME', 'VERSION', 'COMMENT']
145
)
146
147
netview.each do |x|
148
results << [x[:type], x[:ip], x[:cname], "#{x[:major_ver]}.#{x[:minor_ver]}", x[:comment]]
149
report_host(host: x[:ip]) if datastore['SAVEHOSTS'] && !x[:ip].empty?
150
end
151
print_status(results.to_s)
152
store_loot('discovered.hosts', 'text/plain', session, results.to_s, 'discovered_hosts.txt', 'Computer Browser Discovered Hosts')
153
154
print_status('If none of the IP addresses show up you are running this from a Win2k or older system')
155
print_status("If a host doesn't have an IP it either timed out or only has an IPv6 address assinged to it")
156
end
157
end
158
159