From 3a8dd261aebc56d6f56074a844932460ab6a311a Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 19 Oct 2012 15:08:58 -0500 Subject: [PATCH 01/11] WinRM mixin and basic discovery module --- lib/msf/core/exploit/winrm.rb | 480 ++++++++++++++++++ .../scanner/winrm/winrm_auth_methods.rb | 68 +++ 2 files changed, 548 insertions(+) create mode 100644 lib/msf/core/exploit/winrm.rb create mode 100644 modules/auxiliary/scanner/winrm/winrm_auth_methods.rb diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb new file mode 100644 index 0000000000..e793f02cd1 --- /dev/null +++ b/lib/msf/core/exploit/winrm.rb @@ -0,0 +1,480 @@ +# -*- coding: binary -*- +require 'uri' +require 'digest' +require 'rex/proto/ntlm/crypt' +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::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' ]), + ], self.class + ) + + register_advanced_options( + [ + OptString.new('UserAgent', [false, 'The User-Agent header to use for all requests', + Rex::Proto::Http::Client::DefaultUserAgent + ]), + ], self.class + ) + + register_evasion_options( + [ + OptEnum.new('HTTP::uri_encode_mode', [false, 'Enable URI encoding', 'hex-normal', ['none', 'hex-normal', 'hex-all', 'hex-random', 'u-normal', 'u-all', 'u-random']]), + OptBool.new('HTTP::uri_full_url', [false, 'Use the full URL for all HTTP requests', false]), + OptInt.new('HTTP::pad_method_uri_count', [false, 'How many whitespace characters to use between the method and uri', 1]), + OptInt.new('HTTP::pad_uri_version_count', [false, 'How many whitespace characters to use between the uri and version', 1]), + OptEnum.new('HTTP::pad_method_uri_type', [false, 'What type of whitespace to use between the method and uri', 'space', ['space', 'tab', 'apache']]), + OptEnum.new('HTTP::pad_uri_version_type', [false, 'What type of whitespace to use between the uri and version', 'space', ['space', 'tab', 'apache']]), + OptBool.new('HTTP::method_random_valid', [false, 'Use a random, but valid, HTTP method for request', false]), + OptBool.new('HTTP::method_random_invalid', [false, 'Use a random invalid, HTTP method for request', false]), + OptBool.new('HTTP::method_random_case', [false, 'Use random casing for the HTTP method', false]), + OptBool.new('HTTP::uri_dir_self_reference', [false, 'Insert self-referential directories into the uri', false]), + OptBool.new('HTTP::uri_dir_fake_relative', [false, 'Insert fake relative directories into the uri', false]), + OptBool.new('HTTP::uri_use_backslashes', [false, 'Use back slashes instead of forward slashes in the uri ', false]), + OptBool.new('HTTP::pad_fake_headers', [false, 'Insert random, fake headers into the HTTP request', false]), + OptInt.new('HTTP::pad_fake_headers_count', [false, 'How many fake headers to insert into the HTTP request', 0]), + OptBool.new('HTTP::pad_get_params', [false, 'Insert random, fake query string variables into the request', false]), + OptInt.new('HTTP::pad_get_params_count', [false, 'How many fake query string variables to insert into the request', 16]), + OptBool.new('HTTP::pad_post_params', [false, 'Insert random, fake post variables into the request', false]), + OptInt.new('HTTP::pad_post_params_count', [false, 'How many fake post variables to insert into the request', 16]), + OptBool.new('HTTP::uri_fake_end', [false, 'Add a fake end of URI (eg: /%20HTTP/1.0/../../)', false]), + OptBool.new('HTTP::uri_fake_params_start', [false, 'Add a fake start of params to the URI (eg: /%3fa=b/../)', false]), + OptBool.new('HTTP::header_folding', [false, 'Enable folding of HTTP headers', false]) + ], self.class) + + register_autofilter_ports([ 80,443,5985,5986 ]) + register_autofilter_services(%W{ winrm }) + end + + def winrm_poke(timeout = 20) + opts = { + 'uri' => datastore['URI'], + 'data' => 'test' + } + 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'] + })) + return resp + end + + def parse_auth_methods(resp) + return [] unless 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}" + return resp.code + 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_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']] << Base64.decode64(node.text) + end + return streams + end + + 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 + + def generate_uuid + bytes = ::SecureRandom.random_bytes(16) + ::Rex::Proto::DCERPC::UUID.uuid_unpack(bytes) + 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 + + end + +end diff --git a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb new file mode 100644 index 0000000000..c56af6c0ce --- /dev/null +++ b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb @@ -0,0 +1,68 @@ +## +# $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::Scanner + + def initialize + super( + 'Name' => 'WinRM Authentication Methos Detection', + 'Version' => '$Revision$', + 'Description' => %q{ + This module sends a request to a an http/https service to see if it is a WinRM service. + If it is a WinRM service, it also gathers the Authentication Methods supported. + }, + 'Author' => [ 'thelightcosine' ], + 'License' => MSF_LICENSE + ) + + register_options( + [ + OptString.new('URI', [ true, "The URI of the WinRM service", "/wsman" ]) + ], self.class) + + deregister_options('USERNAME', 'PASSWORD') + + end + + + def run_host(ip) + resp = winrm_poke + if resp.code == 401 and resp.headers['Server'].include? "Microsoft-HTTPAPI" + methods = parse_auth_methods(resp) + desc = resp.headers['Server'] + " Authentication Methods: " + methods.to_s + report_service( + :host => ip, + :port => rport, + :proto => 'tcp', + :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" + else + print_error "#{ip}:#{rport} Does not appear to be a WinRM server" + end + end + + +end From 56cbe6a67e2c34214980c93e74c91ccfc07e27f8 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 19 Oct 2012 15:25:03 -0500 Subject: [PATCH 02/11] Some minor fixups --- lib/msf/core/exploit/mixins.rb | 3 ++ lib/msf/core/exploit/winrm.rb | 32 ------------------- .../scanner/winrm/winrm_auth_methods.rb | 5 --- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/lib/msf/core/exploit/mixins.rb b/lib/msf/core/exploit/mixins.rb index 4bda434584..76cfac86e4 100644 --- a/lib/msf/core/exploit/mixins.rb +++ b/lib/msf/core/exploit/mixins.rb @@ -88,3 +88,6 @@ require 'msf/core/exploit/java' # WBEM require 'msf/core/exploit/wbemexec' +#WinRM +require 'msf/core/exploit/winrm' + diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index e793f02cd1..ca76bfcb4a 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -36,38 +36,6 @@ module Msf ], self.class ) - register_advanced_options( - [ - OptString.new('UserAgent', [false, 'The User-Agent header to use for all requests', - Rex::Proto::Http::Client::DefaultUserAgent - ]), - ], self.class - ) - - register_evasion_options( - [ - OptEnum.new('HTTP::uri_encode_mode', [false, 'Enable URI encoding', 'hex-normal', ['none', 'hex-normal', 'hex-all', 'hex-random', 'u-normal', 'u-all', 'u-random']]), - OptBool.new('HTTP::uri_full_url', [false, 'Use the full URL for all HTTP requests', false]), - OptInt.new('HTTP::pad_method_uri_count', [false, 'How many whitespace characters to use between the method and uri', 1]), - OptInt.new('HTTP::pad_uri_version_count', [false, 'How many whitespace characters to use between the uri and version', 1]), - OptEnum.new('HTTP::pad_method_uri_type', [false, 'What type of whitespace to use between the method and uri', 'space', ['space', 'tab', 'apache']]), - OptEnum.new('HTTP::pad_uri_version_type', [false, 'What type of whitespace to use between the uri and version', 'space', ['space', 'tab', 'apache']]), - OptBool.new('HTTP::method_random_valid', [false, 'Use a random, but valid, HTTP method for request', false]), - OptBool.new('HTTP::method_random_invalid', [false, 'Use a random invalid, HTTP method for request', false]), - OptBool.new('HTTP::method_random_case', [false, 'Use random casing for the HTTP method', false]), - OptBool.new('HTTP::uri_dir_self_reference', [false, 'Insert self-referential directories into the uri', false]), - OptBool.new('HTTP::uri_dir_fake_relative', [false, 'Insert fake relative directories into the uri', false]), - OptBool.new('HTTP::uri_use_backslashes', [false, 'Use back slashes instead of forward slashes in the uri ', false]), - OptBool.new('HTTP::pad_fake_headers', [false, 'Insert random, fake headers into the HTTP request', false]), - OptInt.new('HTTP::pad_fake_headers_count', [false, 'How many fake headers to insert into the HTTP request', 0]), - OptBool.new('HTTP::pad_get_params', [false, 'Insert random, fake query string variables into the request', false]), - OptInt.new('HTTP::pad_get_params_count', [false, 'How many fake query string variables to insert into the request', 16]), - OptBool.new('HTTP::pad_post_params', [false, 'Insert random, fake post variables into the request', false]), - OptInt.new('HTTP::pad_post_params_count', [false, 'How many fake post variables to insert into the request', 16]), - OptBool.new('HTTP::uri_fake_end', [false, 'Add a fake end of URI (eg: /%20HTTP/1.0/../../)', false]), - OptBool.new('HTTP::uri_fake_params_start', [false, 'Add a fake start of params to the URI (eg: /%3fa=b/../)', false]), - OptBool.new('HTTP::header_folding', [false, 'Enable folding of HTTP headers', false]) - ], self.class) register_autofilter_ports([ 80,443,5985,5986 ]) register_autofilter_services(%W{ winrm }) diff --git a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb index c56af6c0ce..9de14a96b8 100644 --- a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb +++ b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb @@ -34,11 +34,6 @@ class Metasploit3 < Msf::Auxiliary 'License' => MSF_LICENSE ) - register_options( - [ - OptString.new('URI', [ true, "The URI of the WinRM service", "/wsman" ]) - ], self.class) - deregister_options('USERNAME', 'PASSWORD') end From 57514e5407078e1912d397f3947b1a0d952902ef Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 19 Oct 2012 16:56:52 -0500 Subject: [PATCH 03/11] Msftidyness --- lib/msf/core/exploit/winrm.rb | 817 ++++++++++++++++------------------ 1 file changed, 383 insertions(+), 434 deletions(-) diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index ca76bfcb4a..9037e99e5a 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -6,443 +6,392 @@ 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::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' ]), + ], self.class + ) - module Exploit::Remote::WinRM - include Exploit::Remote::NTLM::Client - include Exploit::Remote::HttpClient + register_autofilter_ports([ 80,443,5985,5986 ]) + register_autofilter_services(%W{ winrm }) + end + def winrm_poke(timeout = 20) + opts = { + 'uri' => datastore['URI'], + 'data' => 'test' + } + 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'] + })) + return resp + end + def parse_auth_methods(resp) + return [] unless 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}" + return resp.code + 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 - # - # 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 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 initialize(info = {}) - super + 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']] << Base64.decode64(node.text) + end + return streams + end + 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 + def generate_uuid + bytes = ::SecureRandom.random_bytes(16) + ::Rex::Proto::DCERPC::UUID.uuid_unpack(bytes) + end - 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' ]), - ], self.class - ) - - - register_autofilter_ports([ 80,443,5985,5986 ]) - register_autofilter_services(%W{ winrm }) - end - - def winrm_poke(timeout = 20) - opts = { - 'uri' => datastore['URI'], - 'data' => 'test' - } - 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'] - })) - return resp - end - - def parse_auth_methods(resp) - return [] unless 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}" - return resp.code - 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_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']] << Base64.decode64(node.text) - end - return streams - end - - 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 - - def generate_uuid - bytes = ::SecureRandom.random_bytes(16) - ::Rex::Proto::DCERPC::UUID.uuid_unpack(bytes) - 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 - - 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 + end end From 7866b61a7e8a75184ef6dea99eecb5c017892e79 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Sat, 20 Oct 2012 00:31:35 -0500 Subject: [PATCH 04/11] Typo fix --- modules/auxiliary/scanner/winrm/winrm_auth_methods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb index 9de14a96b8..591ca20093 100644 --- a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb +++ b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb @@ -24,7 +24,7 @@ class Metasploit3 < Msf::Auxiliary def initialize super( - 'Name' => 'WinRM Authentication Methos Detection', + 'Name' => 'WinRM Authentication Method Detection', 'Version' => '$Revision$', 'Description' => %q{ This module sends a request to a an http/https service to see if it is a WinRM service. From e08cedec2eb5fb09bcee4e617a68b7bf7a897cdd Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 22 Oct 2012 17:01:00 -0500 Subject: [PATCH 05/11] Requested revisions/cleanup minor fixes to spacing, some typos, and abse64 switched to Rex --- lib/msf/core/exploit/winrm.rb | 272 ++++++++++-------- .../scanner/winrm/winrm_auth_methods.rb | 2 +- 2 files changed, 152 insertions(+), 122 deletions(-) diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index 9037e99e5a..03fc2a6f3a 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -25,7 +25,7 @@ module Msf 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('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' ]), @@ -35,10 +35,11 @@ module Msf register_autofilter_ports([ 80,443,5985,5986 ]) register_autofilter_services(%W{ winrm }) end + def winrm_poke(timeout = 20) opts = { 'uri' => datastore['URI'], - 'data' => 'test' + 'data' => Rex::Text.rand_text_alpha(8) } c = connect(opts) to = opts[:timeout] || timeout @@ -51,14 +52,16 @@ module Msf })) return resp end + def parse_auth_methods(resp) - return [] unless resp.code == 401 + 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 @@ -67,7 +70,8 @@ module Msf end unless resp.code == 200 print_error "Got unexpected response: \n #{resp.to_s}" - return resp.code + 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) @@ -85,6 +89,7 @@ module Msf 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']]) @@ -93,6 +98,7 @@ module Msf 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']]) @@ -102,6 +108,7 @@ module Msf 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]]) @@ -110,6 +117,7 @@ module Msf 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]]) @@ -118,6 +126,7 @@ module Msf 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]]) @@ -152,14 +161,17 @@ module Msf 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' => '', @@ -169,127 +181,13 @@ module Msf rxml = REXML::Document.new(xml).root rxml.elements.to_a("//rsp:Stream").each do |node| next if node.text.nil? - streams[node.attributes['Name']] << Base64.decode64(node.text) + streams[node.attributes['Name']] << Rex::Text.base64_decode(node.text) end return streams end - 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 + def generate_uuid - bytes = ::SecureRandom.random_bytes(16) - ::Rex::Proto::DCERPC::UUID.uuid_unpack(bytes) + ::Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16)) end def send_request_ntlm(data, timeout = 20) @@ -379,9 +277,11 @@ module Msf 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'] @@ -393,5 +293,135 @@ module Msf 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 diff --git a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb index 591ca20093..7dc1b3779f 100644 --- a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb +++ b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Auxiliary 'Name' => 'WinRM Authentication Method Detection', 'Version' => '$Revision$', 'Description' => %q{ - This module sends a request to a an http/https service to see if it is a WinRM service. + This module sends a request to an HTTP/HTTPS service to see if it is a WinRM service. If it is a WinRM service, it also gathers the Authentication Methods supported. }, 'Author' => [ 'thelightcosine' ], From 04fd990741bcab3f1d267ab97f36946fca404e13 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Mon, 22 Oct 2012 17:03:40 -0500 Subject: [PATCH 06/11] bad indent --- lib/msf/core/exploit/winrm.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index 03fc2a6f3a..c614725e77 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -192,11 +192,11 @@ module Msf def send_request_ntlm(data, timeout = 20) opts = { - 'uri' => datastore['URI'], - 'data' => data, - 'username' => datastore['USERNAME'], - 'password' => datastore['PASSWORD'] - } + 'uri' => datastore['URI'], + 'data' => data, + 'username' => datastore['USERNAME'], + 'password' => datastore['PASSWORD'] + } ntlm_options = { :signing => false, :usentlm2_session => datastore['NTLM::UseNTLM2_session'], From 2335c582c35a080de7759d4ddf790825b8f3bcdd Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 23 Oct 2012 00:25:31 -0500 Subject: [PATCH 07/11] Null response handling --- modules/auxiliary/scanner/winrm/winrm_auth_methods.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb index 7dc1b3779f..910fe06ff2 100644 --- a/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb +++ b/modules/auxiliary/scanner/winrm/winrm_auth_methods.rb @@ -41,7 +41,8 @@ class Metasploit3 < Msf::Auxiliary def run_host(ip) resp = winrm_poke - if resp.code == 401 and resp.headers['Server'].include? "Microsoft-HTTPAPI" + return nil if resp.nil? + if resp.code == 401 and resp.headers['Server'].include? "Microsoft-HTTPAPI" methods = parse_auth_methods(resp) desc = resp.headers['Server'] + " Authentication Methods: " + methods.to_s report_service( @@ -53,8 +54,8 @@ class Metasploit3 < Msf::Auxiliary ) 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" - else + print_good "Basic protocol supported" if methods.include? "Basic" + else print_error "#{ip}:#{rport} Does not appear to be a WinRM server" end end From e19f2d235c97cb463a2c0f48b5e52aaec4591a3d Mon Sep 17 00:00:00 2001 From: David Maloney Date: Tue, 23 Oct 2012 11:29:32 -0500 Subject: [PATCH 08/11] Actually use the timeout in winrm cmd --- lib/msf/core/exploit/winrm.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index c614725e77..90eb4f2053 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -49,7 +49,7 @@ module Msf 'method' => 'POST', 'ctype' => ctype, 'data' => opts['data'] - })) + }), to) return resp end From 8deead3bd23cf5f9638432f3de2b189e5dc40d69 Mon Sep 17 00:00:00 2001 From: Daniel Miller Date: Tue, 23 Oct 2012 12:31:14 -0500 Subject: [PATCH 09/11] Fix payload ambiguity with php/bind_tcp_ipv6 stager Was seeing this in framework.log: [w(0)] core: The module php/meterpreter/bind_tcp is ambiguous with php/meterpreter/bind_tcp. Added handler_type_alias based on windows/bind_ipv6_tcp stager. --- modules/payloads/stagers/php/bind_tcp_ipv6.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/payloads/stagers/php/bind_tcp_ipv6.rb b/modules/payloads/stagers/php/bind_tcp_ipv6.rb index b7900dc573..859029e0d7 100644 --- a/modules/payloads/stagers/php/bind_tcp_ipv6.rb +++ b/modules/payloads/stagers/php/bind_tcp_ipv6.rb @@ -18,6 +18,10 @@ module Metasploit3 include Msf::Payload::Stager include Msf::Payload::Php + def self.handler_type_alias + "bind_tcp_ipv6" + end + def initialize(info = {}) super(merge_info(info, 'Name' => 'Bind TCP Stager IPv6', From 9c95c7992b7a57e80eb2dea8601eb0a0a785e51e Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 23 Oct 2012 13:24:05 -0500 Subject: [PATCH 10/11] Require's for all the include's --- modules/exploits/linux/local/sock_sendpage.rb | 1 + modules/exploits/linux/local/udev_netlink.rb | 1 + modules/exploits/unix/local/setuid_nmap.rb | 1 + modules/exploits/windows/local/ask.rb | 3 +++ modules/exploits/windows/local/bypassuac.rb | 3 +++ modules/exploits/windows/local/current_user_psexec.rb | 1 + modules/exploits/windows/local/ms10_092_schelevator.rb | 2 ++ modules/exploits/windows/local/trusted_service_path.rb | 2 ++ modules/post/multi/gather/dns_srv_lookup.rb | 1 + modules/post/osx/gather/enum_adium.rb | 1 + modules/post/osx/gather/enum_osx.rb | 3 ++- modules/post/osx/gather/hashdump.rb | 3 ++- modules/post/windows/escalate/service_permissions.rb | 1 + modules/post/windows/gather/arp_scanner.rb | 1 + modules/post/windows/gather/bitcoin_jacker.rb | 1 + modules/post/windows/gather/credentials/coreftp.rb | 1 + .../post/windows/gather/credentials/credential_collector.rb | 1 + modules/post/windows/gather/credentials/dyndns.rb | 1 + modules/post/windows/gather/credentials/enum_picasa_pwds.rb | 1 + modules/post/windows/gather/credentials/epo_sql.rb | 1 + modules/post/windows/gather/credentials/flashfxp.rb | 2 ++ modules/post/windows/gather/credentials/ftpnavigator.rb | 1 + modules/post/windows/gather/credentials/gpp.rb | 1 + modules/post/windows/gather/credentials/idm.rb | 1 + modules/post/windows/gather/credentials/imail.rb | 1 + modules/post/windows/gather/credentials/imvu.rb | 1 + modules/post/windows/gather/credentials/meebo.rb | 1 + modules/post/windows/gather/credentials/mremote.rb | 1 + modules/post/windows/gather/credentials/nimbuzz.rb | 1 + modules/post/windows/gather/credentials/outlook.rb | 1 + modules/post/windows/gather/credentials/razorsql.rb | 1 + modules/post/windows/gather/credentials/tortoisesvn.rb | 1 + modules/post/windows/gather/credentials/total_commander.rb | 2 ++ modules/post/windows/gather/credentials/trillian.rb | 2 ++ modules/post/windows/gather/credentials/vnc.rb | 1 + modules/post/windows/gather/credentials/windows_autologin.rb | 1 + modules/post/windows/gather/credentials/winscp.rb | 1 + modules/post/windows/gather/credentials/wsftp_client.rb | 1 + modules/post/windows/gather/enum_artifacts.rb | 1 + modules/post/windows/gather/enum_db.rb | 1 + modules/post/windows/gather/enum_files.rb | 1 + modules/post/windows/gather/enum_snmp.rb | 1 + modules/post/windows/gather/enum_termserv.rb | 1 + modules/post/windows/gather/enum_tomcat.rb | 1 + modules/post/windows/gather/forensics/duqu_check.rb | 1 + modules/post/windows/gather/hashdump.rb | 1 + modules/post/windows/gather/smart_hashdump.rb | 1 + modules/post/windows/gather/tcpnetstat.rb | 1 + modules/post/windows/gather/win_privs.rb | 1 + modules/post/windows/manage/clone_proxy_settings.rb | 1 + modules/post/windows/manage/pxexploit.rb | 1 + modules/post/windows/recon/computer_browser_discovery.rb | 1 + modules/post/windows/wlan/wlan_bss_list.rb | 1 + modules/post/windows/wlan/wlan_current_connection.rb | 1 + modules/post/windows/wlan/wlan_disconnect.rb | 1 + modules/post/windows/wlan/wlan_profile.rb | 1 + 56 files changed, 67 insertions(+), 2 deletions(-) diff --git a/modules/exploits/linux/local/sock_sendpage.rb b/modules/exploits/linux/local/sock_sendpage.rb index 6617d7b422..576d6c20a2 100644 --- a/modules/exploits/linux/local/sock_sendpage.rb +++ b/modules/exploits/linux/local/sock_sendpage.rb @@ -13,6 +13,7 @@ require 'msf/core/post/linux/priv' require 'msf/core/exploit/local/linux_kernel' require 'msf/core/exploit/local/linux' require 'msf/core/exploit/local/unix' +require 'msf/core/exploit/exe' #load 'lib/msf/core/post/file.rb' #load 'lib/msf/core/exploit/local/unix.rb' diff --git a/modules/exploits/linux/local/udev_netlink.rb b/modules/exploits/linux/local/udev_netlink.rb index c9fcd64d47..24928464dc 100644 --- a/modules/exploits/linux/local/udev_netlink.rb +++ b/modules/exploits/linux/local/udev_netlink.rb @@ -13,6 +13,7 @@ require 'msf/core/post/linux/priv' require 'msf/core/exploit/local/linux_kernel' require 'msf/core/exploit/local/linux' require 'msf/core/exploit/local/unix' +require 'msf/core/exploit/exe' #load 'lib/msf/core/post/file.rb' #load 'lib/msf/core/exploit/local/unix.rb' diff --git a/modules/exploits/unix/local/setuid_nmap.rb b/modules/exploits/unix/local/setuid_nmap.rb index 636a22290a..0c8d5891fa 100644 --- a/modules/exploits/unix/local/setuid_nmap.rb +++ b/modules/exploits/unix/local/setuid_nmap.rb @@ -10,6 +10,7 @@ require 'rex' require 'msf/core/post/common' require 'msf/core/post/file' require 'msf/core/post/linux/priv' +require 'msf/core/exploit/exe' class Metasploit4 < Msf::Exploit::Local diff --git a/modules/exploits/windows/local/ask.rb b/modules/exploits/windows/local/ask.rb index 88a8657f6b..d1b8909940 100644 --- a/modules/exploits/windows/local/ask.rb +++ b/modules/exploits/windows/local/ask.rb @@ -10,6 +10,9 @@ ## require 'msf/core' +require 'msf/core/post/common' +require 'msf/core/exploit/exe' +require 'msf/core/post/file' class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking diff --git a/modules/exploits/windows/local/bypassuac.rb b/modules/exploits/windows/local/bypassuac.rb index e297048830..c87460445d 100644 --- a/modules/exploits/windows/local/bypassuac.rb +++ b/modules/exploits/windows/local/bypassuac.rb @@ -10,6 +10,9 @@ ## require 'msf/core' +require 'msf/core/post/common' +require 'msf/core/exploit/exe' +require 'msf/core/post/file' class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking diff --git a/modules/exploits/windows/local/current_user_psexec.rb b/modules/exploits/windows/local/current_user_psexec.rb index 7e1a85b5d1..e95e8db28c 100644 --- a/modules/exploits/windows/local/current_user_psexec.rb +++ b/modules/exploits/windows/local/current_user_psexec.rb @@ -14,6 +14,7 @@ require 'rex' require 'msf/core/post/windows/services' require 'msf/core/post/common' require 'msf/core/post/file' +require 'msf/core/exploit/exe' class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking diff --git a/modules/exploits/windows/local/ms10_092_schelevator.rb b/modules/exploits/windows/local/ms10_092_schelevator.rb index 02aca0b6fe..3a2e101ac0 100644 --- a/modules/exploits/windows/local/ms10_092_schelevator.rb +++ b/modules/exploits/windows/local/ms10_092_schelevator.rb @@ -9,6 +9,8 @@ require 'msf/core' require 'msf/core/post/common' require 'rex' require 'zlib' +require 'msf/core/exploit/exe' +require 'msf/core/post/file' class Metasploit3 < Msf::Exploit::Local diff --git a/modules/exploits/windows/local/trusted_service_path.rb b/modules/exploits/windows/local/trusted_service_path.rb index b5ab369c6f..17c61e9e6b 100644 --- a/modules/exploits/windows/local/trusted_service_path.rb +++ b/modules/exploits/windows/local/trusted_service_path.rb @@ -8,6 +8,8 @@ require 'msf/core' require 'msf/core/post/common' require 'msf/core/post/windows/services' +require 'msf/core/exploit/exe' +require 'msf/core/post/file' class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking diff --git a/modules/post/multi/gather/dns_srv_lookup.rb b/modules/post/multi/gather/dns_srv_lookup.rb index d3af7104a1..bc62259acd 100644 --- a/modules/post/multi/gather/dns_srv_lookup.rb +++ b/modules/post/multi/gather/dns_srv_lookup.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/common' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/osx/gather/enum_adium.rb b/modules/post/osx/gather/enum_adium.rb index 4a38be509b..2a9e08f4b2 100644 --- a/modules/post/osx/gather/enum_adium.rb +++ b/modules/post/osx/gather/enum_adium.rb @@ -9,6 +9,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/common' require 'msf/core/post/file' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/osx/gather/enum_osx.rb b/modules/post/osx/gather/enum_osx.rb index 4f3cc0dc5c..61effe8e0f 100644 --- a/modules/post/osx/gather/enum_osx.rb +++ b/modules/post/osx/gather/enum_osx.rb @@ -11,9 +11,10 @@ require 'msf/core' require 'rex' - require 'msf/core/post/common' require 'msf/core/post/file' +require 'msf/core/auxiliary/report' + class Metasploit3 < Msf::Post diff --git a/modules/post/osx/gather/hashdump.rb b/modules/post/osx/gather/hashdump.rb index 841340c591..ff97c6ee46 100644 --- a/modules/post/osx/gather/hashdump.rb +++ b/modules/post/osx/gather/hashdump.rb @@ -11,9 +11,10 @@ require 'msf/core' require 'rex' - require 'msf/core/post/common' require 'msf/core/post/file' +require 'msf/core/auxiliary/report' + class Metasploit3 < Msf::Post diff --git a/modules/post/windows/escalate/service_permissions.rb b/modules/post/windows/escalate/service_permissions.rb index 46888a79e7..ac7bf099c6 100644 --- a/modules/post/windows/escalate/service_permissions.rb +++ b/modules/post/windows/escalate/service_permissions.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'msf/core/post/windows/services' require 'rex' +require 'msf/core//post/windows/services' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/arp_scanner.rb b/modules/post/windows/gather/arp_scanner.rb index ea3ed30c73..dd3ba4db48 100644 --- a/modules/post/windows/gather/arp_scanner.rb +++ b/modules/post/windows/gather/arp_scanner.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/common' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/bitcoin_jacker.rb b/modules/post/windows/gather/bitcoin_jacker.rb index ab4613183e..3d1a4e63db 100644 --- a/modules/post/windows/gather/bitcoin_jacker.rb +++ b/modules/post/windows/gather/bitcoin_jacker.rb @@ -10,6 +10,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Auxiliary::Report diff --git a/modules/post/windows/gather/credentials/coreftp.rb b/modules/post/windows/gather/credentials/coreftp.rb index a07259cf13..a8a0b4b757 100644 --- a/modules/post/windows/gather/credentials/coreftp.rb +++ b/modules/post/windows/gather/credentials/coreftp.rb @@ -13,6 +13,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Post::Windows::Registry diff --git a/modules/post/windows/gather/credentials/credential_collector.rb b/modules/post/windows/gather/credentials/credential_collector.rb index bd10050b82..0818285f0d 100644 --- a/modules/post/windows/gather/credentials/credential_collector.rb +++ b/modules/post/windows/gather/credentials/credential_collector.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/common' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/dyndns.rb b/modules/post/windows/gather/credentials/dyndns.rb index 547670d978..b652ac216b 100644 --- a/modules/post/windows/gather/credentials/dyndns.rb +++ b/modules/post/windows/gather/credentials/dyndns.rb @@ -10,6 +10,7 @@ ## require 'msf/core' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/enum_picasa_pwds.rb b/modules/post/windows/gather/credentials/enum_picasa_pwds.rb index 4b24e90c5c..2f277ec6ee 100644 --- a/modules/post/windows/gather/credentials/enum_picasa_pwds.rb +++ b/modules/post/windows/gather/credentials/enum_picasa_pwds.rb @@ -13,6 +13,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/priv' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/epo_sql.rb b/modules/post/windows/gather/credentials/epo_sql.rb index ab577f43ab..2d7722ec20 100644 --- a/modules/post/windows/gather/credentials/epo_sql.rb +++ b/modules/post/windows/gather/credentials/epo_sql.rb @@ -13,6 +13,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' require "net/dns/resolver" +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/flashfxp.rb b/modules/post/windows/gather/credentials/flashfxp.rb index e18f65a81c..7187ebd9ff 100644 --- a/modules/post/windows/gather/credentials/flashfxp.rb +++ b/modules/post/windows/gather/credentials/flashfxp.rb @@ -11,6 +11,8 @@ require 'msf/core' require 'rex' require 'rex/parser/ini' require 'msf/core/post/windows/user_profiles' +require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/ftpnavigator.rb b/modules/post/windows/gather/credentials/ftpnavigator.rb index 595e1cd821..581a8c39a0 100644 --- a/modules/post/windows/gather/credentials/ftpnavigator.rb +++ b/modules/post/windows/gather/credentials/ftpnavigator.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/gpp.rb b/modules/post/windows/gather/credentials/gpp.rb index 83d614a062..9acda15881 100644 --- a/modules/post/windows/gather/credentials/gpp.rb +++ b/modules/post/windows/gather/credentials/gpp.rb @@ -10,6 +10,7 @@ require 'rex' require 'rexml/document' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/priv' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Auxiliary::Report diff --git a/modules/post/windows/gather/credentials/idm.rb b/modules/post/windows/gather/credentials/idm.rb index ea77531fe6..fa71646afe 100644 --- a/modules/post/windows/gather/credentials/idm.rb +++ b/modules/post/windows/gather/credentials/idm.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Post::Windows::Registry diff --git a/modules/post/windows/gather/credentials/imail.rb b/modules/post/windows/gather/credentials/imail.rb index ed44c8141e..180d1c265e 100644 --- a/modules/post/windows/gather/credentials/imail.rb +++ b/modules/post/windows/gather/credentials/imail.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/imvu.rb b/modules/post/windows/gather/credentials/imvu.rb index 6c27b0d04e..6512eacded 100644 --- a/modules/post/windows/gather/credentials/imvu.rb +++ b/modules/post/windows/gather/credentials/imvu.rb @@ -14,6 +14,7 @@ require 'msf/core' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/meebo.rb b/modules/post/windows/gather/credentials/meebo.rb index 8d7f100655..c8b7c64ba7 100644 --- a/modules/post/windows/gather/credentials/meebo.rb +++ b/modules/post/windows/gather/credentials/meebo.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Auxiliary::Report diff --git a/modules/post/windows/gather/credentials/mremote.rb b/modules/post/windows/gather/credentials/mremote.rb index 041a73a45f..b80590aaed 100644 --- a/modules/post/windows/gather/credentials/mremote.rb +++ b/modules/post/windows/gather/credentials/mremote.rb @@ -15,6 +15,7 @@ require 'msf/core' require 'rex' require 'rexml/document' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Post::Windows::UserProfiles diff --git a/modules/post/windows/gather/credentials/nimbuzz.rb b/modules/post/windows/gather/credentials/nimbuzz.rb index 029fae439f..4d883d9a6e 100644 --- a/modules/post/windows/gather/credentials/nimbuzz.rb +++ b/modules/post/windows/gather/credentials/nimbuzz.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Post::Windows::Registry diff --git a/modules/post/windows/gather/credentials/outlook.rb b/modules/post/windows/gather/credentials/outlook.rb index 748f511119..89e6f6429e 100644 --- a/modules/post/windows/gather/credentials/outlook.rb +++ b/modules/post/windows/gather/credentials/outlook.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/priv' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/razorsql.rb b/modules/post/windows/gather/credentials/razorsql.rb index 9d870ee4a8..5189599d36 100644 --- a/modules/post/windows/gather/credentials/razorsql.rb +++ b/modules/post/windows/gather/credentials/razorsql.rb @@ -8,6 +8,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/tortoisesvn.rb b/modules/post/windows/gather/credentials/tortoisesvn.rb index c53ef63edc..2d5cc48437 100644 --- a/modules/post/windows/gather/credentials/tortoisesvn.rb +++ b/modules/post/windows/gather/credentials/tortoisesvn.rb @@ -3,6 +3,7 @@ require 'rex' require 'msf/core/post/windows/priv' require 'msf/core/post/windows/registry' require 'base64' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/total_commander.rb b/modules/post/windows/gather/credentials/total_commander.rb index 3af30f0910..be900ccf9f 100644 --- a/modules/post/windows/gather/credentials/total_commander.rb +++ b/modules/post/windows/gather/credentials/total_commander.rb @@ -11,6 +11,8 @@ require 'msf/core' require 'rex' require 'rex/parser/ini' require 'msf/core/post/windows/user_profiles' +require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Post::Windows::Registry diff --git a/modules/post/windows/gather/credentials/trillian.rb b/modules/post/windows/gather/credentials/trillian.rb index d8ed694f04..55f42350fe 100644 --- a/modules/post/windows/gather/credentials/trillian.rb +++ b/modules/post/windows/gather/credentials/trillian.rb @@ -14,6 +14,8 @@ require 'rex' require 'rex/parser/ini' require 'base64' require 'msf/core/post/windows/user_profiles' +require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/vnc.rb b/modules/post/windows/gather/credentials/vnc.rb index 0a31c63fd4..d23d922d54 100644 --- a/modules/post/windows/gather/credentials/vnc.rb +++ b/modules/post/windows/gather/credentials/vnc.rb @@ -15,6 +15,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/credentials/windows_autologin.rb b/modules/post/windows/gather/credentials/windows_autologin.rb index 1c77792250..3149ab5404 100644 --- a/modules/post/windows/gather/credentials/windows_autologin.rb +++ b/modules/post/windows/gather/credentials/windows_autologin.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Post::Windows::Registry diff --git a/modules/post/windows/gather/credentials/winscp.rb b/modules/post/windows/gather/credentials/winscp.rb index 32785ff0ad..79f26ab4a2 100644 --- a/modules/post/windows/gather/credentials/winscp.rb +++ b/modules/post/windows/gather/credentials/winscp.rb @@ -16,6 +16,7 @@ require 'rex' require 'msf/core/post/windows/registry' require 'rex/parser/ini' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Post::Windows::Registry diff --git a/modules/post/windows/gather/credentials/wsftp_client.rb b/modules/post/windows/gather/credentials/wsftp_client.rb index d6e80229a1..7963bd8c52 100644 --- a/modules/post/windows/gather/credentials/wsftp_client.rb +++ b/modules/post/windows/gather/credentials/wsftp_client.rb @@ -12,6 +12,7 @@ require 'rex' require 'rex/parser/ini' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/enum_artifacts.rb b/modules/post/windows/gather/enum_artifacts.rb index 3d8090b0c2..82e6a9e6fe 100644 --- a/modules/post/windows/gather/enum_artifacts.rb +++ b/modules/post/windows/gather/enum_artifacts.rb @@ -10,6 +10,7 @@ require 'msf/core' require 'msf/core/post/file' require 'msf/core/post/windows/registry' require 'yaml' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/enum_db.rb b/modules/post/windows/gather/enum_db.rb index 29e130e40a..7c2f7aac8b 100644 --- a/modules/post/windows/gather/enum_db.rb +++ b/modules/post/windows/gather/enum_db.rb @@ -10,6 +10,7 @@ require 'msf/core' require 'msf/core/post/file' require 'msf/core/post/common' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/enum_files.rb b/modules/post/windows/gather/enum_files.rb index a348eb58ba..dc91747353 100644 --- a/modules/post/windows/gather/enum_files.rb +++ b/modules/post/windows/gather/enum_files.rb @@ -7,6 +7,7 @@ require 'msf/core' require 'msf/core/post/file' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/enum_snmp.rb b/modules/post/windows/gather/enum_snmp.rb index c43fc9313b..98a54dc4f8 100644 --- a/modules/post/windows/gather/enum_snmp.rb +++ b/modules/post/windows/gather/enum_snmp.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/enum_termserv.rb b/modules/post/windows/gather/enum_termserv.rb index 44f0f4d969..84688978ae 100644 --- a/modules/post/windows/gather/enum_termserv.rb +++ b/modules/post/windows/gather/enum_termserv.rb @@ -15,6 +15,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/user_profiles' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/enum_tomcat.rb b/modules/post/windows/gather/enum_tomcat.rb index 1d22656fe0..091035ce1f 100644 --- a/modules/post/windows/gather/enum_tomcat.rb +++ b/modules/post/windows/gather/enum_tomcat.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'msf/core/post/file' require 'msf/core/post/common' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/forensics/duqu_check.rb b/modules/post/windows/gather/forensics/duqu_check.rb index fe86768dd5..a52a9e900a 100644 --- a/modules/post/windows/gather/forensics/duqu_check.rb +++ b/modules/post/windows/gather/forensics/duqu_check.rb @@ -9,6 +9,7 @@ require 'msf/core' require 'msf/core/post/common' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/priv' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/hashdump.rb b/modules/post/windows/gather/hashdump.rb index 6b7307c1c2..0bb42f4565 100644 --- a/modules/post/windows/gather/hashdump.rb +++ b/modules/post/windows/gather/hashdump.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/registry' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/smart_hashdump.rb b/modules/post/windows/gather/smart_hashdump.rb index 61f9128f43..5df0862a9c 100644 --- a/modules/post/windows/gather/smart_hashdump.rb +++ b/modules/post/windows/gather/smart_hashdump.rb @@ -16,6 +16,7 @@ require 'msf/core/post/windows/priv' require 'msf/core/post/windows/registry' require 'msf/core/post/windows/accounts' require 'msf/core/post/file' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/tcpnetstat.rb b/modules/post/windows/gather/tcpnetstat.rb index d1eafb072f..6f17769802 100644 --- a/modules/post/windows/gather/tcpnetstat.rb +++ b/modules/post/windows/gather/tcpnetstat.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/common' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/gather/win_privs.rb b/modules/post/windows/gather/win_privs.rb index 19aca41a22..9bc614a9eb 100644 --- a/modules/post/windows/gather/win_privs.rb +++ b/modules/post/windows/gather/win_privs.rb @@ -8,6 +8,7 @@ require 'msf/core' require 'rex' require 'msf/core/post/windows/priv' +require 'msf/core/post/common' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/manage/clone_proxy_settings.rb b/modules/post/windows/manage/clone_proxy_settings.rb index 4393ed8716..09da0b8c8b 100644 --- a/modules/post/windows/manage/clone_proxy_settings.rb +++ b/modules/post/windows/manage/clone_proxy_settings.rb @@ -10,6 +10,7 @@ ## require 'msf/core' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/manage/pxexploit.rb b/modules/post/windows/manage/pxexploit.rb index eb54fef208..87d183daec 100644 --- a/modules/post/windows/manage/pxexploit.rb +++ b/modules/post/windows/manage/pxexploit.rb @@ -10,6 +10,7 @@ ## require 'msf/core' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/recon/computer_browser_discovery.rb b/modules/post/windows/recon/computer_browser_discovery.rb index 9fdfd36568..55fc8fd2fc 100644 --- a/modules/post/windows/recon/computer_browser_discovery.rb +++ b/modules/post/windows/recon/computer_browser_discovery.rb @@ -12,6 +12,7 @@ require 'msf/core' require 'rex' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post diff --git a/modules/post/windows/wlan/wlan_bss_list.rb b/modules/post/windows/wlan/wlan_bss_list.rb index e4a59b00c9..06ba5a63a5 100644 --- a/modules/post/windows/wlan/wlan_bss_list.rb +++ b/modules/post/windows/wlan/wlan_bss_list.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'rex' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Auxiliary::Report diff --git a/modules/post/windows/wlan/wlan_current_connection.rb b/modules/post/windows/wlan/wlan_current_connection.rb index e1883256a1..13d88d6a9f 100644 --- a/modules/post/windows/wlan/wlan_current_connection.rb +++ b/modules/post/windows/wlan/wlan_current_connection.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'rex' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Auxiliary::Report diff --git a/modules/post/windows/wlan/wlan_disconnect.rb b/modules/post/windows/wlan/wlan_disconnect.rb index 854d15870a..aab4c3065b 100644 --- a/modules/post/windows/wlan/wlan_disconnect.rb +++ b/modules/post/windows/wlan/wlan_disconnect.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'rex' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Auxiliary::Report diff --git a/modules/post/windows/wlan/wlan_profile.rb b/modules/post/windows/wlan/wlan_profile.rb index dd84bddf43..04a80cf959 100644 --- a/modules/post/windows/wlan/wlan_profile.rb +++ b/modules/post/windows/wlan/wlan_profile.rb @@ -11,6 +11,7 @@ require 'msf/core' require 'rex' +require 'msf/core/auxiliary/report' class Metasploit3 < Msf::Post include Msf::Auxiliary::Report From 8c1304557f3c122dd0d8a4d213dff6dad7b44968 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Tue, 23 Oct 2012 16:32:26 -0500 Subject: [PATCH 11/11] Code cleanup --- lib/msf/core/exploit/winrm.rb | 850 ++++++++++++++++++---------------- 1 file changed, 447 insertions(+), 403 deletions(-) diff --git a/lib/msf/core/exploit/winrm.rb b/lib/msf/core/exploit/winrm.rb index 90eb4f2053..40db61aa8b 100644 --- a/lib/msf/core/exploit/winrm.rb +++ b/lib/msf/core/exploit/winrm.rb @@ -5,423 +5,467 @@ require 'rex/proto/ntlm/crypt' 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::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' ]), - ], self.class - ) - register_autofilter_ports([ 80,443,5985,5986 ]) - register_autofilter_services(%W{ winrm }) +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::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' ]) + ], self.class + ) + + 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 - def winrm_poke(timeout = 20) - opts = { - 'uri' => datastore['URI'], - 'data' => Rex::Text.rand_text_alpha(8) + 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_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 + + response_data = Rex::Ui::Text::Table.new( + 'Header' => "#{datastore['WQL']} (#{rhost})", + 'Indent' => 1, + 'Columns' => columns.uniq! + ) + + 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 + resp = c.send_recv(r, to) - 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 + 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