Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/net/winrm/rex_http_transport.rb
Views: 11780
require 'winrm'12module Net3module MsfWinRM4# Transport for communicating to a WinRM service, using Rex sockets5class RexHttpTransport < WinRM::HTTP::HttpTransport6# rubocop:disable Lint/7def initialize(opts)8if opts[:kerberos_authenticator]9self.http_client = opts.fetch(:http_client) { Rex::Proto::Http::Client.new(opts[:host], opts[:port], {}, opts[:ssl], opts[:ssl_version], opts[:proxies], kerberos_authenticator: opts[:kerberos_authenticator]) }10self.preferred_auth = 'Kerberos'11else12self.http_client = opts.fetch(:http_client) { Rex::Proto::Http::Client.new(opts[:host], opts[:port], {}, opts[:ssl], opts[:ssl_version], opts[:proxies], opts[:user], opts[:password]) }13self.preferred_auth = 'Negotiate'14end15self.timeout = opts[:timeout]16@mutex = Mutex.new17self.uri = opts[:uri]18self.vhost = opts[:vhost]19if opts[:realm]20http_client.set_config('domain' => opts[:realm])21end22end2324def peerinfo25if http_client && http_client.conn26http_client.conn.peerinfo27end28end2930def localinfo31if http_client && http_client.conn32http_client.conn.localinfo33end34end3536def krb_transform_response(encryptor, response)37# OMI server doesn't always respond to encrypted messages with encrypted responses over SSL38return unless response39return if response.headers['Content-Type'] && response.headers['Content-Type'].first =~ (%r{\Aapplication/soap\+xml}i)40return if response.body.empty?4142str = response.body.force_encoding('BINARY')43str.sub!(%r{^.*Content-Type: application/octet-stream\r\n(.*)--Encrypted.*$}m, '\1')44str.sub!(%r{^.*Content-Type: application/octet-stream\r\n(.*)-- Encrypted.*$}m, '\1')4546# Strip off the "encrypted message header length" token47str = str[4, str.length-4]48begin49plaintext = encryptor.decrypt_and_verify(str)50rescue Rex::Proto::Kerberos::Model::Error::KerberosError => exception51raise WinRM::WinRMHTTPTransportError, "Could not decrypt Kerberos message (#{exception})"52end53response.body = plaintext54end5556def krb_transform_request(encryptor, req)57return req if !req.opts['data']58opts = req.opts.dup5960body_type = 'application/HTTP-Kerberos-session-encrypted'61opts['ctype'] = 'multipart/encrypted;protocol="' + body_type + '";boundary="Encrypted Boundary"'62data = opts['data']63emessage, header_length, pad_length = encryptor.encrypt_and_increment(data)64emessage = [header_length].pack('V') + emessage6566opts['data'] = body(emessage, data.length + pad_length, body_type)67Rex::Proto::Http::ClientRequest.new(opts)68end6970# Performs decryption of the stream coming from the HTTP client71def ntlm_transform_response(ntlm_client, response)72# OMI server doesn't always respond to encrypted messages with encrypted responses over SSL73return unless response74return if response.headers['Content-Type'] && response.headers['Content-Type'].first =~ (%r{\Aapplication/soap\+xml}i)75return if response.body.empty?7677str = response.body.force_encoding('BINARY')78str.sub!(%r{^.*Content-Type: application/octet-stream\r\n(.*)--Encrypted.*$}m, '\1')7980signature = str[4..19]81message = ntlm_client.session.unseal_message(str[20..-1])82if ntlm_client.session.verify_signature(signature, message)83response.body = message84return85else86raise WinRM::WinRMHTTPTransportError, 'Could not decrypt NTLM message.'87end88end8990# Performs encryption of the stream being sent to the HTTP client91def ntlm_transform_request(ntlm_client, req)92return req if !req.opts['data']93opts = req.opts.dup9495opts['ctype'] = 'multipart/encrypted;protocol="application/HTTP-SPNEGO-session-encrypted";boundary="Encrypted Boundary"'96data = opts['data']97emessage = ntlm_client.session.seal_message(data)98signature = ntlm_client.session.sign_message(data)99edata = "\x10\x00\x00\x00#{signature}#{emessage}"100101opts['data'] = body(edata, data.bytesize)102Rex::Proto::Http::ClientRequest.new(opts)103end104105def _send_request(message)106@mutex.synchronize do107opts = {108'uri' => uri,109'method' => 'POST',110'agent' => 'Microsoft WinRM Client',111'ctype' => 'application/soap+xml;charset=UTF-8',112'no_body_for_auth' => true,113'preferred_auth' => self.preferred_auth,114}115116opts.merge!('vhost' => self.vhost) if self.vhost117118if message119opts['data'] = message120opts['krb_transform_request'] = method(:krb_transform_request)121opts['krb_transform_response'] = method(:krb_transform_response)122opts['ntlm_transform_request'] = method(:ntlm_transform_request)123opts['ntlm_transform_response'] = method(:ntlm_transform_response)124end125request = http_client.request_cgi(opts)126response = http_client.send_recv(request, timeout, true)127if response128WinRM::ResponseHandler.new(response.body, response.code).parse_to_xml129else130raise WinRM::WinRMHTTPTransportError, 'No response'131end132end133end134135def send_request(message)136_send_request(message)137end138139protected140141attr_accessor :http_client, :uri, :timeout, :preferred_auth, :vhost142end143end144end145146147