Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/windows/recon/computer_browser_discovery.rb
19500 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::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
'Notes' => {
35
'Stability' => [CRASH_SAFE],
36
'SideEffects' => [],
37
'Reliability' => []
38
}
39
)
40
)
41
42
register_options(
43
[
44
OptString.new('LTYPE', [true, 'Account informations (type info for known types)', 'WK']), # Enum would be a better choice
45
OptString.new('DOMAIN', [false, 'Domain to perform lookups on, default is current domain', nil]),
46
OptBool.new('SAVEHOSTS', [true, 'Save Discovered Hosts to the Database', false])
47
]
48
)
49
end
50
51
def parse_netserverenum(startmem, count)
52
base = 0
53
sys_list = []
54
mem = client.railgun.memread(startmem, 24 * count)
55
56
count.times do |_i|
57
x = {}
58
x[:platform_id] = mem[(base + 0), 4].unpack('V*')[0]
59
cnameptr = mem[(base + 4), 4].unpack('V*')[0]
60
x[:major_ver] = mem[(base + 8), 4].unpack('V*')[0]
61
x[:minor_ver] = mem[(base + 12), 4].unpack('V*')[0]
62
x[:type] = mem[(base + 16), 4].unpack('V*')[0]
63
commentptr = mem[(base + 20), 4].unpack('V*')[0]
64
65
x[:cname] = client.railgun.memread(cnameptr, 27).split("\0\0")[0].split("\0").join
66
x[:comment] = client.railgun.memread(commentptr, 255).split("\0\0")[0].split("\0").join
67
sys_list << x
68
base += 24
69
vprint_status("Identified: #{x[:cname]} - #{x[:comment]}")
70
end
71
return sys_list
72
end
73
74
def run
75
client = session
76
77
# Default = SV_TYPE_NT
78
# Servers = SV_TYPE_ALL
79
# Workstations = SV_TYPE_WORKSTATION
80
# Domain Controllers = SV_TYPE_DOMAINCTRL
81
# Novell Server = SV_TYPE_NOVELL
82
# Terminal Servers = SV_TYPE_TERMINALSERVER
83
# SQL Servers = SV_TYPE_SQLSERVER
84
lookuptype = 1
85
86
case datastore['LTYPE']
87
when 'WK' then lookuptype = '1'.hex
88
when 'SVR' then lookuptype = '2'.hex
89
when 'SQL' then lookuptype = '4'.hex
90
when 'DC' then lookuptype = '8'.hex
91
when 'DCBKUP' then lookuptype = '10'.hex
92
when 'TIME' then lookuptype = '20'.hex
93
when 'NOVELL' then lookuptype = '80'.hex
94
when 'PRINTSVR' then lookuptype = '200'.hex
95
when 'MASTERBROWSER' then lookuptype = '40000'.hex
96
when 'WINDOWS' then lookuptype = '400000'.hex
97
when 'UNIX' then lookuptype = '800'.hex
98
when 'LOCAL' then lookuptype = '40000000'.hex
99
end
100
101
result = client.railgun.netapi32.NetServerEnum(nil, 101, 4, -1, 4, 4, lookuptype, datastore['DOMAIN'], 0)
102
103
if result['totalentries'] == 0
104
print_error('No systems found of that type')
105
return
106
end
107
print_good("Found #{result['totalentries']} systems.")
108
109
netview = parse_netserverenum(result['bufptr'], result['totalentries'])
110
111
## get IP for host
112
begin
113
netview.each do |x|
114
vprint_status("Looking up IP for #{x[:cname]}")
115
print '.'
116
result = client.net.resolve.resolve_host(x[:cname])
117
if result[:ip].nil? || result[:ip].blank?
118
print_error("There was an error resolving the IP for #{x[:cname]}")
119
next
120
else
121
x[:ip] = result[:ip]
122
end
123
end
124
rescue StandardError => e
125
print_error(e)
126
print_status('Windows 2000 and prior does not support getaddrinfo')
127
end
128
129
netview = netview.sort_by { |h| h[:type] }
130
131
results = Rex::Text::Table.new(
132
'Header' => 'Netdiscovery Results',
133
'Indent' => 2,
134
'Columns' => ['TYPE', 'IP', 'COMPUTER NAME', 'VERSION', 'COMMENT']
135
)
136
137
netview.each do |x|
138
results << [x[:type], x[:ip], x[:cname], "#{x[:major_ver]}.#{x[:minor_ver]}", x[:comment]]
139
report_host(host: x[:ip]) if datastore['SAVEHOSTS'] && !x[:ip].empty?
140
end
141
print_status(results.to_s)
142
store_loot('discovered.hosts', 'text/plain', session, results.to_s, 'discovered_hosts.txt', 'Computer Browser Discovered Hosts')
143
144
print_status('If none of the IP addresses show up you are running this from a Win2k or older system')
145
print_status("If a host doesn't have an IP it either timed out or only has an IPv6 address assinged to it")
146
end
147
end
148
149