Skip to content

Commit dfa9131

Browse files
committed
Support checking a single URI for ntlm information.
1 parent 1a05390 commit dfa9131

File tree

1 file changed

+60
-48
lines changed

1 file changed

+60
-48
lines changed

modules/auxiliary/scanner/http/ntlm_info_enumeration.rb

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -26,42 +26,56 @@ def initialize
2626
)
2727
register_options(
2828
[
29-
OptPath.new('TARGETURIS', [ true, "Path to list of URIs to request", File.join(Msf::Config.data_directory, "wordlists", "http_owa_common.txt")])
29+
OptString.new('TARGET', [ true, "Target URI information", File.join(Msf::Config.data_directory, "wordlists", "http_owa_common.txt")]),
30+
OptEnum.new('TARGETTYPE', [ true, "Whether TARGET is a file of URIs or a single URI", 'FILE', %w{ FILE URI } ])
3031
], self.class)
3132
end
3233

3334
def run_host(ip)
34-
File.open(datastore['TARGETURIS'], 'rb').each_line do |line|
35+
if datastore['TARGETTYPE'] == 'URI'
36+
test_path = normalize_uri(datastore['TARGET'])
37+
result = check_url(test_path)
38+
if result
39+
handle_result(test_path, result)
40+
return
41+
end
42+
end
43+
44+
File.open(datastore['TARGET'], 'rb').each_line do |line|
3545
test_uri = line.chomp
3646
test_path = normalize_uri(test_uri)
3747
result = check_url(test_path)
3848
if result
39-
message = "Enumerated info on #{peer}#{test_path} - "
40-
message << "(name:#{result[:nb_name]}) "
41-
message << "(domain:#{result[:nb_domain]}) "
42-
message << "(domain_fqdn:#{result[:dns_domain]}) "
43-
message << "(server_fqdn:#{result[:dns_server]})"
44-
print_good(message)
45-
report_note(
46-
:host => ip,
47-
:port => rport,
48-
:proto => 'tcp',
49-
:sname => (ssl ? 'https' : 'http'),
50-
:ntype => 'ntlm.enumeration.info',
51-
:data => {
52-
:uri=>test_path,
53-
:SMBName => result[:nb_name],
54-
:SMBDomain => result[:nb_domain],
55-
:FQDNDomain => result[:dns_domain],
56-
:FQDNName => result[:dns_server]
57-
},
58-
:update => :unique_data
59-
)
49+
handle_result(test_path, result)
6050
return
6151
end
6252
end
6353
end
6454

55+
def handle_result(path, result)
56+
message = "Enumerated info on #{peer}#{path} - "
57+
message << "(name:#{result[:nb_name]}) "
58+
message << "(domain:#{result[:nb_domain]}) "
59+
message << "(domain_fqdn:#{result[:dns_domain]}) "
60+
message << "(server_fqdn:#{result[:dns_server]})"
61+
print_good(message)
62+
report_note(
63+
:host => rhost,
64+
:port => rport,
65+
:proto => 'tcp',
66+
:sname => (ssl ? 'https' : 'http'),
67+
:ntype => 'ntlm.enumeration.info',
68+
:data => {
69+
:uri => path,
70+
:SMBName => result[:nb_name],
71+
:SMBDomain => result[:nb_domain],
72+
:FQDNDomain => result[:dns_domain],
73+
:FQDNName => result[:dns_server]
74+
},
75+
:update => :unique_data
76+
)
77+
end
78+
6579
def check_url(test_uri)
6680
begin
6781

@@ -72,31 +86,6 @@ def check_url(test_uri)
7286
'method' => 'GET',
7387
'headers' => { "Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="}
7488
})
75-
76-
return if res.nil?
77-
78-
vprint_status("Status: #{res.code}")
79-
if res and res.code == 401 and res['WWW-Authenticate'].match(/^NTLM/i)
80-
hash = res['WWW-Authenticate'].split('NTLM ')[1]
81-
#Parse out the NTLM and just get the Target Information Data
82-
target = Rex::Proto::NTLM::Message.parse(Rex::Text.decode_base64(hash))[:target_info].value()
83-
# Retrieve Domain name subblock info
84-
nb_domain = parse_ntlm_info(target, "\x02\x00", 0)
85-
# Retrieve Server name subblock info
86-
nb_name = parse_ntlm_info(target, "\x01\x00", nb_domain[:new_offset])
87-
# Retrieve DNS domain name subblock info
88-
dns_domain = parse_ntlm_info(target, "\x04\x00", nb_name[:new_offset])
89-
# Retrieve DNS server name subblock info
90-
dns_server = parse_ntlm_info(target, "\x03\x00", dns_domain[:new_offset])
91-
92-
return {
93-
:nb_name => nb_name[:message],
94-
:nb_domain => nb_domain[:message],
95-
:dns_domain => dns_domain[:message],
96-
:dns_server => dns_server[:message]
97-
}
98-
end
99-
10089
rescue OpenSSL::SSL::SSLError
10190
vprint_error("#{peer} - SSL error")
10291
return
@@ -108,6 +97,29 @@ def check_url(test_uri)
10897
return
10998
end
11099

100+
return if res.nil?
101+
102+
vprint_status("Status: #{res.code}")
103+
if res and res.code == 401 and res['WWW-Authenticate'].match(/^NTLM/i)
104+
hash = res['WWW-Authenticate'].split('NTLM ')[1]
105+
# Parse out the NTLM and just get the Target Information Data
106+
target = Rex::Proto::NTLM::Message.parse(Rex::Text.decode_base64(hash))[:target_info].value()
107+
# Retrieve Domain name subblock info
108+
nb_domain = parse_ntlm_info(target, "\x02\x00", 0)
109+
# Retrieve Server name subblock info
110+
nb_name = parse_ntlm_info(target, "\x01\x00", nb_domain[:new_offset])
111+
# Retrieve DNS domain name subblock info
112+
dns_domain = parse_ntlm_info(target, "\x04\x00", nb_name[:new_offset])
113+
# Retrieve DNS server name subblock info
114+
dns_server = parse_ntlm_info(target, "\x03\x00", dns_domain[:new_offset])
115+
116+
return {
117+
:nb_name => nb_name[:message],
118+
:nb_domain => nb_domain[:message],
119+
:dns_domain => dns_domain[:message],
120+
:dns_server => dns_server[:message]
121+
}
122+
end
111123
end
112124

113125
def parse_ntlm_info(message,pattern,offset)

0 commit comments

Comments
 (0)