Skip to content

Commit 44d4e29

Browse files
David MaloneyDavid Maloney
authored andcommitted
Attempting to cleanup winrm auth
1 parent c71b803 commit 44d4e29

File tree

4 files changed

+29
-117
lines changed

4 files changed

+29
-117
lines changed

lib/msf/core/exploit/winrm.rb

Lines changed: 21 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def winrm_poke(timeout = 20)
4242
c = connect(opts)
4343
to = opts[:timeout] || timeout
4444
ctype = "application/soap+xml;charset=UTF-8"
45-
resp, c = send_request_cgi(opts.merge({
45+
resp, c = send_winrm_request(opts.merge({
4646
'uri' => opts['uri'],
4747
'method' => 'POST',
4848
'ctype' => ctype,
@@ -61,7 +61,7 @@ def parse_auth_methods(resp)
6161
end
6262

6363
def winrm_run_cmd(cmd, timeout=20)
64-
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
64+
resp = send_winrm_request(winrm_open_shell_msg,timeout)
6565
if resp.nil?
6666
print_error "Recieved no reply from server"
6767
return nil
@@ -76,17 +76,17 @@ def winrm_run_cmd(cmd, timeout=20)
7676
return retval
7777
end
7878
shell_id = winrm_get_shell_id(resp)
79-
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout)
79+
resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout)
8080
cmd_id = winrm_get_cmd_id(resp)
81-
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
81+
resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
8282
streams = winrm_get_cmd_streams(resp)
83-
resp,c = send_request_ntlm(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout)
84-
resp,c = send_request_ntlm(winrm_delete_shell_msg(shell_id))
83+
resp = send_winrm_request(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout)
84+
resp = send_winrm_request(winrm_delete_shell_msg(shell_id))
8585
return streams
8686
end
8787

8888
def winrm_run_cmd_hanging(cmd, timeout=20)
89-
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
89+
resp = send_winrm_request(winrm_open_shell_msg,timeout)
9090
if resp.nil?
9191
print_error "Recieved no reply from server"
9292
return nil
@@ -101,9 +101,9 @@ def winrm_run_cmd_hanging(cmd, timeout=20)
101101
return retval
102102
end
103103
shell_id = winrm_get_shell_id(resp)
104-
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout)
104+
resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout)
105105
cmd_id = winrm_get_cmd_id(resp)
106-
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
106+
resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
107107
streams = winrm_get_cmd_streams(resp)
108108
return streams
109109
end
@@ -219,94 +219,6 @@ def generate_uuid
219219
::Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16))
220220
end
221221

222-
def send_request_ntlm(data, timeout = 20)
223-
opts = {
224-
'uri' => datastore['URI'],
225-
'data' => data,
226-
'username' => datastore['USERNAME'],
227-
'password' => datastore['PASSWORD']
228-
}
229-
ntlm_options = {
230-
:signing => false,
231-
:usentlm2_session => datastore['NTLM::UseNTLM2_session'],
232-
:use_ntlmv2 => datastore['NTLM::UseNTLMv2'],
233-
:send_lm => datastore['NTLM::SendLM'],
234-
:send_ntlm => datastore['NTLM::SendNTLM']
235-
}
236-
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
237-
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
238-
domain_name = datastore['DOMAIN']
239-
ntlm_message_1 = "NEGOTIATE " + Rex::Text::encode_base64(NTLM_UTILS::make_ntlmssp_blob_init( domain_name,
240-
workstation_name,
241-
ntlmssp_flags))
242-
to = opts[:timeout] || timeout
243-
begin
244-
c = connect(opts)
245-
ctype = "application/soap+xml;charset=UTF-8"
246-
# First request to get the challenge
247-
r = c.request_cgi(opts.merge({
248-
'uri' => opts['uri'],
249-
'method' => 'POST',
250-
'ctype' => ctype,
251-
'headers' => { 'Authorization' => ntlm_message_1},
252-
'data' => opts['data']
253-
}))
254-
resp = c.send_recv(r, to)
255-
unless resp.kind_of? Rex::Proto::Http::Response
256-
return [nil,nil]
257-
end
258-
return [nil,nil] if resp.code == 404
259-
return [nil,nil] unless resp.code == 401 && resp.headers['WWW-Authenticate']
260-
# Get the challenge and craft the response
261-
ntlm_challenge = resp.headers['WWW-Authenticate'].match(/NEGOTIATE ([A-Z0-9\x2b\x2f=]+)/i)[1]
262-
return [nil,nil] unless ntlm_challenge
263-
264-
#old and simplier method but not compatible with windows 7/2008r2
265-
#ntlm_message_2 = Rex::Proto::NTLM::Message.decode64(ntlm_challenge)
266-
#ntlm_message_3 = ntlm_message_2.response( {:user => opts['username'],:password => opts['password']}, {:ntlmv2 => true})
267-
ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge)
268-
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(ntlm_message_2)
269-
challenge_key = blob_data[:challenge_key]
270-
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
271-
#netbios name
272-
default_name = blob_data[:default_name] || ''
273-
#netbios domain
274-
default_domain = blob_data[:default_domain] || ''
275-
#dns name
276-
dns_host_name = blob_data[:dns_host_name] || ''
277-
#dns domain
278-
dns_domain_name = blob_data[:dns_domain_name] || ''
279-
#Client time
280-
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
281-
spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
282-
resp_lm,
283-
resp_ntlm,
284-
client_challenge,
285-
ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(opts['username'], opts['password'], challenge_key,
286-
domain_name, default_name, default_domain,
287-
dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
288-
spnopt, ntlm_options)
289-
ntlm_message_3 = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, opts['username'],
290-
resp_lm, resp_ntlm, '', ntlmssp_flags)
291-
ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3)
292-
# Send the response
293-
r = c.request_cgi(opts.merge({
294-
'uri' => opts['uri'],
295-
'method' => 'POST',
296-
'ctype' => ctype,
297-
'headers' => { 'Authorization' => "NEGOTIATE #{ntlm_message_3}"},
298-
'data' => opts['data']
299-
}))
300-
resp = c.send_recv(r, to, true)
301-
unless resp.kind_of? Rex::Proto::Http::Response
302-
return [nil,nil]
303-
end
304-
return [nil,nil] if resp.code == 404
305-
return [resp,c]
306-
rescue ::Errno::EPIPE, ::Timeout::Error
307-
end
308-
end
309-
310222
def accepts_ntlm_auth
311223
parse_auth_methods(winrm_poke).include? "Negotiate"
312224
end
@@ -329,6 +241,18 @@ def wmi_namespace
329241
return "/root/cimv2/"
330242
end
331243

244+
def send_winrm_request(data, timeout=20)
245+
opts = {
246+
'uri' => datastore['URI'],
247+
'method' => 'POST',
248+
'data' => data,
249+
'username' => datastore['USERNAME'],
250+
'password' => datastore['PASSWORD'],
251+
'ctype' => "application/soap+xml;charset=UTF-8"
252+
}
253+
send_request_cgi(opts,timeout)
254+
end
255+
332256

333257
private
334258

modules/auxiliary/scanner/winrm/winrm_login.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def run_host(ip)
4444
return
4545
end
4646
each_user_pass do |user, pass|
47-
resp,c = send_request_ntlm(test_request)
47+
resp = send_winrm_request(test_request)
4848
if resp.nil?
4949
print_error "#{ip}:#{rport}: Got no reply from the server, connection may have timed out"
5050
return

modules/auxiliary/scanner/winrm/winrm_wql.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def run_host(ip)
4747
return
4848
end
4949

50-
resp,c = send_request_ntlm(winrm_wql_msg(datastore['WQL']))
50+
resp = send_winrm_request(winrm_wql_msg(datastore['WQL']))
5151
if resp.nil?
5252
print_error "Got no reply from the server"
5353
return

modules/exploits/windows/winrm/winrm_script_exec.rb

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,8 @@ def initialize(info = {})
6666
@compat_mode = false
6767
end
6868

69-
def check
70-
unless accepts_ntlm_auth
71-
print_error "The Remote WinRM server does not appear to allow Negotiate (NTLM) auth"
72-
return Msf::Exploit::CheckCode::Safe
73-
end
74-
75-
return Msf::Exploit::CheckCode::Vulnerable
76-
end
77-
78-
7969
def exploit
80-
unless check == Msf::Exploit::CheckCode::Vulnerable
81-
return
82-
end
70+
8371
unless valid_login?
8472
print_error "Login Failure. Recheck your credentials"
8573
return
@@ -141,7 +129,7 @@ def encoded_psh(script)
141129

142130
def temp_dir
143131
print_status "Grabbing %TEMP%"
144-
resp,c = send_request_ntlm(winrm_open_shell_msg)
132+
resp = send_winrm_request(winrm_open_shell_msg)
145133
if resp.nil?
146134
print_error "Got no reply from the server"
147135
return nil
@@ -152,16 +140,16 @@ def temp_dir
152140
end
153141
shell_id = winrm_get_shell_id(resp)
154142
cmd = "echo %TEMP%"
155-
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id))
143+
resp= send_winrm_request(winrm_cmd_msg(cmd, shell_id))
156144
cmd_id = winrm_get_cmd_id(resp)
157-
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id))
145+
resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id))
158146
streams = winrm_get_cmd_streams(resp)
159147
return streams['stdout'].chomp
160148
end
161149

162150
def check_remote_arch
163151
wql = %q{select AddressWidth from Win32_Processor where DeviceID="CPU0"}
164-
resp,c = send_request_ntlm(winrm_wql_msg(wql))
152+
resp = send_winrm_request(winrm_wql_msg(wql))
165153
#Default to x86 if we can't be sure
166154
return "x86" if resp.nil? or resp.code != 200
167155
resp_tbl = parse_wql_response(resp)
@@ -247,7 +235,7 @@ def powershell2?
247235

248236
def valid_login?
249237
data = winrm_wql_msg("Select Name,Status from Win32_Service")
250-
resp,c = send_request_ntlm(data)
238+
resp = send_winrm_request(data)
251239
unless resp.code == 200
252240
return false
253241
end

0 commit comments

Comments
 (0)