From a15c35091d69e675818ab10dd54d1728668d2f41 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 24 Oct 2012 11:25:39 -0500 Subject: [PATCH 1/4] Add the WinRM login module --- lib/msf/core/exploit/winrm.rb | 4 - .../auxiliary/scanner/winrm/winrm_login.rb | 83 +++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 modules/auxiliary/scanner/winrm/winrm_login.rb diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index 90eb4f2053..ff4e6e5e30 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -20,11 +20,7 @@ module Msf 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' ]), diff --git a/modules/auxiliary/scanner/winrm/winrm_login.rb b/modules/auxiliary/scanner/winrm/winrm_login.rb new file mode 100644 index 0000000000..ca9c8c74af --- /dev/null +++ b/modules/auxiliary/scanner/winrm/winrm_login.rb @@ -0,0 +1,83 @@ +## +# $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. + }, + 'References' => + [ + + ], + '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 "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 "Valid credential found: #{user}:#{pass}" + elsif resp.code == 401 + print_error "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 From 1dcbbdf16206a42cf53b6ccee03e1e6ac9d68ebd Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 24 Oct 2012 13:50:44 -0500 Subject: [PATCH 2/4] changed indent level --- lib/msf/core/exploit/winrm.rb | 802 +++++++++++++++++----------------- 1 file changed, 401 insertions(+), 401 deletions(-) diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index ff4e6e5e30..3e96261348 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -6,418 +6,418 @@ require 'rex/proto/ntlm/constants' require 'rex/proto/ntlm/utils' require 'rex/proto/ntlm/exceptions' module Msf - module Exploit::Remote::WinRM - include Exploit::Remote::NTLM::Client - include Exploit::Remote::HttpClient - # - # Constants - # - NTLM_CRYPT ||= Rex::Proto::NTLM::Crypt - 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::RPORT(5985), - 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' ]), - ], self.class - ) +module Exploit::Remote::WinRM + include Exploit::Remote::NTLM::Client + include Exploit::Remote::HttpClient + # + # Constants + # + NTLM_CRYPT ||= Rex::Proto::NTLM::Crypt + 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::RPORT(5985), + 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' ]), + ], self.class + ) - register_autofilter_ports([ 80,443,5985,5986 ]) - register_autofilter_services(%W{ winrm }) + register_autofilter_ports([ 80,443,5985,5986 ]) + register_autofilter_services(%W{ winrm }) + end + + def winrm_poke(timeout = 20) + opts = { + 'uri' => datastore['URI'], + 'data' => Rex::Text.rand_text_alpha(8) + } + c = connect(opts) + to = opts[:timeout] || timeout + ctype = "application/soap+xml;charset=UTF-8" + resp, c = send_request_cgi(opts.merge({ + 'uri' => opts['uri'], + 'method' => 'POST', + 'ctype' => ctype, + 'data' => opts['data'] + }), to) + return resp + end + + def parse_auth_methods(resp) + return [] unless resp and resp.code == 401 + methods = [] + methods << "Negotiate" if resp.headers['WWW-Authenticate'].include? "Negotiate" + methods << "Kerberos" if resp.headers['WWW-Authenticate'].include? "Kerberos" + methods << "Basic" if resp.headers['WWW-Authenticate'].include? "Basic" + return methods + end + + 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) + resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout) + 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 - def winrm_poke(timeout = 20) - opts = { - 'uri' => datastore['URI'], - 'data' => Rex::Text.rand_text_alpha(8) - } + def winrm_wql_msg(wql) + action = winrm_uri_action("wql") + contents = winrm_header(action) + winrm_wql_body(wql) + msg = winrm_envelope(contents) + return msg + end + + def winrm_open_shell_msg + action = winrm_uri_action("create_shell") + options = winrm_option_set([['WINRS_NOPROFILE', 'FALSE'], ['WINRS_CODEPAGE', '437']]) + header_data = action + options + contents = winrm_header(header_data) + winrm_open_shell_body + msg = winrm_envelope(contents) + return msg + end + + def winrm_cmd_msg(cmd,shell_id) + action = winrm_uri_action("send_cmd") + options = winrm_option_set([['WINRS_CONSOLEMODE_STDIN', 'TRUE'], ['WINRS_SKIP_CMD_SHELL', 'FALSE']]) + selectors = winrm_selector_set([['ShellId', shell_id]]) + header_data = action + options + selectors + contents = winrm_header(header_data) + winrm_cmd_body(cmd) + msg = winrm_envelope(contents) + return msg + end + + def winrm_cmd_recv_msg(shell_id,cmd_id) + action = winrm_uri_action("recv_cmd") + selectors = winrm_selector_set([['ShellId', shell_id]]) + header_data = action + selectors + contents = winrm_header(header_data) + winrm_cmd_recv_body(cmd_id) + msg = winrm_envelope(contents) + return msg + end + + def winrm_terminate_cmd_msg(shell_id,cmd_id) + action = winrm_uri_action("signal_shell") + selectors = winrm_selector_set([['ShellId', shell_id]]) + header_data = action + selectors + contents = winrm_header(header_data) + winrm_terminate_cmd_body(cmd_id) + msg = winrm_envelope(contents) + return msg + end + + def winrm_delete_shell_msg(shell_id) + action = winrm_uri_action("delete_shell") + selectors = winrm_selector_set([['ShellId', shell_id]]) + header_data = action + selectors + contents = winrm_header(header_data) + winrm_empty_body + msg = winrm_envelope(contents) + return msg + end + + def parse_wql_response(response) + xml = response.body + columns = [] + 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 + ) + rows.each do |row| + response_data << row + end + return response_data + end + + def winrm_get_shell_id(response) + xml = response.body + shell_id = REXML::Document.new(xml).elements["//w:Selector"].text + end + + def winrm_get_cmd_id(response) + xml = response.body + cmd_id = REXML::Document.new(xml).elements["//rsp:CommandId"].text + end + + def winrm_get_cmd_streams(response) + streams = { + 'stdout' => '', + '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 + + def generate_uuid + ::Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16)) + end + + def send_request_ntlm(data, timeout = 20) + opts = { + 'uri' => datastore['URI'], + 'data' => data, + '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'] + } + 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) - to = opts[:timeout] || timeout ctype = "application/soap+xml;charset=UTF-8" - resp, c = send_request_cgi(opts.merge({ + # First request to get the challenge + r = c.request_cgi(opts.merge({ 'uri' => opts['uri'], 'method' => 'POST', 'ctype' => ctype, + 'headers' => { 'Authorization' => ntlm_message_1}, 'data' => opts['data'] - }), to) - return resp - end - - def parse_auth_methods(resp) - return [] unless resp and resp.code == 401 - methods = [] - methods << "Negotiate" if resp.headers['WWW-Authenticate'].include? "Negotiate" - methods << "Kerberos" if resp.headers['WWW-Authenticate'].include? "Kerberos" - methods << "Basic" if resp.headers['WWW-Authenticate'].include? "Basic" - return methods - end - - 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 + })) + resp = c.send_recv(r, to) + unless resp.kind_of? Rex::Proto::Http::Response + return [nil,nil] end - unless resp.code == 200 - print_error "Got unexpected response: \n #{resp.to_s}" - retval == resp.code || 0 - return retval + 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 + ntlm_challenge = resp.headers['WWW-Authenticate'].match(/NEGOTIATE ([A-Z0-9\x2b\x2f=]+)/i)[1] + return [nil,nil] unless ntlm_challenge + + #old and simplier method but not compatible with windows 7/2008r2 + #ntlm_message_2 = Rex::Proto::NTLM::Message.decode64(ntlm_challenge) + #ntlm_message_3 = ntlm_message_2.response( {:user => opts['username'],:password => opts['password']}, {:ntlmv2 => true}) + ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge) + blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(ntlm_message_2) + challenge_key = blob_data[:challenge_key] + server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error + #netbios name + default_name = blob_data[:default_name] || '' + #netbios domain + default_domain = blob_data[:default_domain] || '' + #dns name + dns_host_name = blob_data[:dns_host_name] || '' + #dns domain + dns_domain_name = blob_data[:dns_domain_name] || '' + #Client time + chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' + spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost} + resp_lm, + resp_ntlm, + client_challenge, + ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(opts['username'], opts['password'], challenge_key, + domain_name, default_name, default_domain, + dns_host_name, dns_domain_name, chall_MsvAvTimestamp, + spnopt, ntlm_options) + 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'], + 'method' => 'POST', + 'ctype' => ctype, + '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 - 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) - resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout) - 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 + return [nil,nil] if resp.code == 404 + return [resp,c] + rescue ::Errno::EPIPE, ::Timeout::Error end - - def winrm_wql_msg(wql) - action = winrm_uri_action("wql") - contents = winrm_header(action) + winrm_wql_body(wql) - msg = winrm_envelope(contents) - return msg - end - - def winrm_open_shell_msg - action = winrm_uri_action("create_shell") - options = winrm_option_set([['WINRS_NOPROFILE', 'FALSE'], ['WINRS_CODEPAGE', '437']]) - header_data = action + options - contents = winrm_header(header_data) + winrm_open_shell_body - msg = winrm_envelope(contents) - return msg - end - - def winrm_cmd_msg(cmd,shell_id) - action = winrm_uri_action("send_cmd") - options = winrm_option_set([['WINRS_CONSOLEMODE_STDIN', 'TRUE'], ['WINRS_SKIP_CMD_SHELL', 'FALSE']]) - selectors = winrm_selector_set([['ShellId', shell_id]]) - header_data = action + options + selectors - contents = winrm_header(header_data) + winrm_cmd_body(cmd) - msg = winrm_envelope(contents) - return msg - end - - def winrm_cmd_recv_msg(shell_id,cmd_id) - action = winrm_uri_action("recv_cmd") - selectors = winrm_selector_set([['ShellId', shell_id]]) - header_data = action + selectors - contents = winrm_header(header_data) + winrm_cmd_recv_body(cmd_id) - msg = winrm_envelope(contents) - return msg - end - - def winrm_terminate_cmd_msg(shell_id,cmd_id) - action = winrm_uri_action("signal_shell") - selectors = winrm_selector_set([['ShellId', shell_id]]) - header_data = action + selectors - contents = winrm_header(header_data) + winrm_terminate_cmd_body(cmd_id) - msg = winrm_envelope(contents) - return msg - end - - def winrm_delete_shell_msg(shell_id) - action = winrm_uri_action("delete_shell") - selectors = winrm_selector_set([['ShellId', shell_id]]) - header_data = action + selectors - contents = winrm_header(header_data) + winrm_empty_body - msg = winrm_envelope(contents) - return msg - end - - def parse_wql_response(response) - xml = response.body - columns = [] - 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 - ) - rows.each do |row| - response_data << row - end - return response_data - end - - def winrm_get_shell_id(response) - xml = response.body - shell_id = REXML::Document.new(xml).elements["//w:Selector"].text - end - - def winrm_get_cmd_id(response) - xml = response.body - cmd_id = REXML::Document.new(xml).elements["//rsp:CommandId"].text - end - - def winrm_get_cmd_streams(response) - streams = { - 'stdout' => '', - '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 - - def generate_uuid - ::Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16)) - end - - def send_request_ntlm(data, timeout = 20) - opts = { - 'uri' => datastore['URI'], - 'data' => data, - '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'] - } - 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" - # First request to get the challenge - r = c.request_cgi(opts.merge({ - 'uri' => opts['uri'], - 'method' => 'POST', - '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 - ntlm_challenge = resp.headers['WWW-Authenticate'].match(/NEGOTIATE ([A-Z0-9\x2b\x2f=]+)/i)[1] - return [nil,nil] unless ntlm_challenge - - #old and simplier method but not compatible with windows 7/2008r2 - #ntlm_message_2 = Rex::Proto::NTLM::Message.decode64(ntlm_challenge) - #ntlm_message_3 = ntlm_message_2.response( {:user => opts['username'],:password => opts['password']}, {:ntlmv2 => true}) - ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge) - blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(ntlm_message_2) - challenge_key = blob_data[:challenge_key] - server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error - #netbios name - default_name = blob_data[:default_name] || '' - #netbios domain - default_domain = blob_data[:default_domain] || '' - #dns name - dns_host_name = blob_data[:dns_host_name] || '' - #dns domain - dns_domain_name = blob_data[:dns_domain_name] || '' - #Client time - chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' - spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost} - resp_lm, - resp_ntlm, - client_challenge, - ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(opts['username'], opts['password'], challenge_key, - domain_name, default_name, default_domain, - dns_host_name, dns_domain_name, chall_MsvAvTimestamp, - spnopt, ntlm_options) - 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'], - 'method' => 'POST', - 'ctype' => ctype, - '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 - end - end - - def accepts_ntlm_auth - parse_auth_methods(winrm_poke).include? "Negotiate" - end - - def target_url - proto = "http" - if rport == 5986 or datastore['SSL'] - proto = "https" - end - if datastore['VHOST'] - return "#{proto}://#{datastore ['VHOST']}:#{rport}#{@uri.to_s}" - else - return "#{proto}://#{rhost}:#{rport}#{@uri.to_s}" - end - end - - private - - def winrm_option_set(options) - xml = "" - options.each do |option_pair| - xml << winrm_option(*option_pair) - end - xml << "" - return xml - end - - def winrm_option(name,value) - %Q{#{value}} - end - - def winrm_selector_set(selectors) - xml = "" - selectors.each do |selector_pair| - xml << winrm_selector(*selector_pair) - end - xml << "" - return xml - end - - def winrm_selector(name,value) - %Q{#{value}} - end - - def winrm_wql_body(wql) - %Q{ - - - - 32000 - #{wql} - - - } - end - - def winrm_open_shell_body - %q{ - - stdin - stdout stderr - - } - end - - def winrm_cmd_body(cmd) - %Q{ - - "#{cmd}" - - } - end - - def winrm_cmd_recv_body(cmd_id) - %Q{ - - stdout stderr - - } - end - - def winrm_terminate_cmd_body(cmd_id) - %Q{ - - http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate - - } - end - - def winrm_empty_body - %q{} - end - - def winrm_envelope(data) - %Q{ - - #{data} - } - end - - def winrm_header(data) - %Q{ - - #{target_url} - - http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous - - 153600 - uuid:#{generate_uuid} - - - PT60S - #{data} - - } - end - - def winrm_uri_action(type) - case type - when "wql" - return %q{http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/* - http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate} - when "create_shell" - return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd - http://schemas.xmlsoap.org/ws/2004/09/transfer/Create} - when "send_cmd" - return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd - http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command} - when "recv_cmd" - return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd - http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive} - when "signal_shell" - return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd - http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal} - when "delete_shell" - return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd - http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete} - end - end - end + + def accepts_ntlm_auth + parse_auth_methods(winrm_poke).include? "Negotiate" + end + + def target_url + proto = "http" + if rport == 5986 or datastore['SSL'] + proto = "https" + end + if datastore['VHOST'] + return "#{proto}://#{datastore ['VHOST']}:#{rport}#{@uri.to_s}" + else + return "#{proto}://#{rhost}:#{rport}#{@uri.to_s}" + end + end + + private + + def winrm_option_set(options) + xml = "" + options.each do |option_pair| + xml << winrm_option(*option_pair) + end + xml << "" + return xml + end + + def winrm_option(name,value) + %Q{#{value}} + end + + def winrm_selector_set(selectors) + xml = "" + selectors.each do |selector_pair| + xml << winrm_selector(*selector_pair) + end + xml << "" + return xml + end + + def winrm_selector(name,value) + %Q{#{value}} + end + + def winrm_wql_body(wql) + %Q{ + + + + 32000 + #{wql} + + + } + end + + def winrm_open_shell_body + %q{ + + stdin + stdout stderr + + } + end + + def winrm_cmd_body(cmd) + %Q{ + + "#{cmd}" + + } + end + + def winrm_cmd_recv_body(cmd_id) + %Q{ + + stdout stderr + + } + end + + def winrm_terminate_cmd_body(cmd_id) + %Q{ + + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate + + } + end + + def winrm_empty_body + %q{} + end + + def winrm_envelope(data) + %Q{ + + #{data} + } + end + + def winrm_header(data) + %Q{ + + #{target_url} + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + 153600 + uuid:#{generate_uuid} + + + PT60S + #{data} + + } + end + + def winrm_uri_action(type) + case type + when "wql" + return %q{http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/* + http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate} + when "create_shell" + return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + http://schemas.xmlsoap.org/ws/2004/09/transfer/Create} + when "send_cmd" + return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command} + when "recv_cmd" + return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive} + when "signal_shell" + return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal} + when "delete_shell" + return %q{http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete} + end + end + +end end From fb7af536d5f66d3f4d4cbed25e66faa8944877f9 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 25 Oct 2012 10:16:12 -0500 Subject: [PATCH 3/4] wtf, bad metadata Removed extraneous references section --- modules/auxiliary/scanner/winrm/winrm_login.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/auxiliary/scanner/winrm/winrm_login.rb b/modules/auxiliary/scanner/winrm/winrm_login.rb index ca9c8c74af..34a16f8682 100644 --- a/modules/auxiliary/scanner/winrm/winrm_login.rb +++ b/modules/auxiliary/scanner/winrm/winrm_login.rb @@ -30,10 +30,6 @@ class Metasploit3 < Msf::Auxiliary works only if the remote end allows Negotiate(NTLM) authentication. Kerberos is not currently supported. }, - 'References' => - [ - - ], 'Author' => [ 'thelightcosine' ], 'References' => [ From b15c38f81969a6774462668f44fea29158e72a88 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 25 Oct 2012 19:57:29 -0500 Subject: [PATCH 4/4] Fix output to display ip:port --- modules/auxiliary/scanner/winrm/winrm_auth_methods.rb | 6 +++--- modules/auxiliary/scanner/winrm/winrm_login.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb index 910fe06ff2..d0b583a549 100644 --- a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb +++ b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb @@ -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 diff --git a/modules/auxiliary/scanner/winrm/winrm_login.rb b/modules/auxiliary/scanner/winrm/winrm_login.rb index 34a16f8682..198bdd83d6 100644 --- a/modules/auxiliary/scanner/winrm/winrm_login.rb +++ b/modules/auxiliary/scanner/winrm/winrm_login.rb @@ -49,7 +49,7 @@ class Metasploit3 < Msf::Auxiliary each_user_pass do |user, pass| resp,c = send_request_ntlm(test_request) if resp.nil? - print_error "Got no reply from the server, connection may have timed out" + print_error "#{ip}:#{rport}: Got no reply from the server, connection may have timed out" return elsif resp.code == 200 cred_hash = { @@ -62,9 +62,9 @@ class Metasploit3 < Msf::Auxiliary :active => true } report_auth_info(cred_hash) - print_good "Valid credential found: #{user}:#{pass}" + print_good "#{ip}:#{rport}: Valid credential found: #{user}:#{pass}" elsif resp.code == 401 - print_error "Login failed: #{user}:#{pass}" + print_error "#{ip}:#{rport}: Login failed: #{user}:#{pass}" else print_error "Recieved unexpected Response Code: #{resp.code}" end