Class: PSRP::HTTP::Negotiate

Inherits:
Object
  • Object
show all
Defined in:
lib/transport.rb

Overview

straight copy from WinRM NTLM/Negotiate, secure, HTTP transport

Constant Summary collapse

DEFAULT_RECEIVE_TIMEOUT =
1000

Instance Method Summary collapse

Constructor Details

#initialize(endpoint, user, pass, opts) ⇒ Negotiate

Returns a new instance of Negotiate.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/transport.rb', line 32

def initialize(endpoint, user, pass, opts)
  @endpoint = endpoint.is_a?(String) ? URI.parse(endpoint) : endpoint
  @httpcli = HTTPClient.new(agent_name: 'Ruby PSRP Client')
  @httpcli.receive_timeout = DEFAULT_RECEIVE_TIMEOUT
  @httpcli.connect_timeout = 2
  @httpcli.send_timeout = 2
  @logger = Logging.logger[self]
  require 'rubyntlm'

  # Deleting SSPI authentication
  auths = @httpcli.www_auth.instance_variable_get('@authenticator')
  auths.delete_if { |i| i.is_a? HTTPClient::SSPINegotiateAuth }

  user_parts = user.split('\\')
  if(user_parts.length > 1)
    opts[:domain] = user_parts[0]
    user = user_parts[1]
  end

  @ntlmcli = Net::NTLM::Client.new(user, pass, opts)
  @retryable = true
  no_ssl_peer_verification! if opts[:no_ssl_peer_verification]
  @ssl_peer_fingerprint = opts[:ssl_peer_fingerprint]
  @httpcli.ssl_config.set_trust_ca(opts[:ca_trust_path]) if opts[:ca_trust_path]

end

Instance Method Details

#no_ssl_peer_verification!Object

Disable SSL Peer Verification



60
61
62
# File 'lib/transport.rb', line 60

def no_ssl_peer_verification!
  @httpcli.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
end

#receive_timeoutObject



105
106
107
# File 'lib/transport.rb', line 105

def receive_timeout
  @httpcli.receive_timeout
end

#receive_timeout=(sec) ⇒ Object

HTTP Client receive timeout. How long should a remote call wait for a for a response from WinRM?



101
102
103
# File 'lib/transport.rb', line 101

def receive_timeout=(sec)
  @httpcli.receive_timeout = sec
end

#send_request(message, auth_header = nil) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/transport.rb', line 110

def send_request(message, auth_header = nil)
  ssl_peer_fingerprint_verification!
  auth_header = init_auth if @ntlmcli.session.nil?

  original_length = message.length

  emessage = @ntlmcli.session.seal_message message
  signature = @ntlmcli.session.sign_message message
  seal = "\x10\x00\x00\x00#{signature}#{emessage}"
  
  hdr = {
    "Content-Type" => "multipart/encrypted;protocol=\"application/HTTP-SPNEGO-session-encrypted\";boundary=\"Encrypted Boundary\""
  }
  hdr.merge!(auth_header) if auth_header

  # p hdr

  body = [
    "--Encrypted Boundary",
    "Content-Type: application/HTTP-SPNEGO-session-encrypted",
    "OriginalContent: type=application/soap+xml;charset=UTF-8;Length=#{original_length}",
    "--Encrypted Boundary",
    "Content-Type: application/octet-stream",
    "#{seal}--Encrypted Boundary--",
    ""
  ].join("\r\n")

  @logger.debug("\nOut-Message\n\n")
  doc = REXML::Document.new message
  out = ""
  doc.write(out, 2)
  @logger.debug(out)
  @logger.debug("\n\n")

  resp = @httpcli.post(@endpoint, body, hdr)
  verify_ssl_fingerprint(resp.peer_cert)
  if resp.status == 401 && @retryable
    @retryable = false
    send_request(message, init_auth)
  else
    
              
    @retryable = true
    decrypted_body = resp.body.empty? ? '' : decrypt(resp.body)
    handler = PSRP::ResponseHandler.new(decrypted_body, resp.status)
    data = handler.parse_to_xml()
    
    @logger.debug("Response data\n\n")
    doc = REXML::Document.new decrypted_body
    out = ""
    doc.write(out, 2)
    @logger.debug(out)
    
    data
  end
end

#ssl_peer_fingerprint_verification!Object

SSL Peer Fingerprint Verification prior to connecting



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/transport.rb', line 65

def ssl_peer_fingerprint_verification!
  return unless @ssl_peer_fingerprint && ! @ssl_peer_fingerprint_verified

  with_untrusted_ssl_connection do |connection|
    connection_cert = connection.peer_cert_chain.last
    verify_ssl_fingerprint(connection_cert)
  end
  @logger.info("initial ssl fingerprint #{@ssl_peer_fingerprint} verified\n")
  @ssl_peer_fingerprint_verified = true
  no_ssl_peer_verification!
end

#verify_ssl_fingerprint(cert) ⇒ Object

compare @ssl_peer_fingerprint to current ssl context



92
93
94
95
96
97
# File 'lib/transport.rb', line 92

def verify_ssl_fingerprint(cert)
  return unless @ssl_peer_fingerprint
  conn_fingerprint = OpenSSL::Digest::SHA1.new(cert.to_der).to_s
  return unless @ssl_peer_fingerprint.casecmp(conn_fingerprint) != 0
  fail "ssl fingerprint mismatch!!!!\n"
end

#with_untrusted_ssl_connectionObject

Connect without verification to retrieve untrusted ssl context



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/transport.rb', line 78

def with_untrusted_ssl_connection
  noverify_peer_context = OpenSSL::SSL::SSLContext.new
  noverify_peer_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
  tcp_connection = TCPSocket.new(@endpoint.host, @endpoint.port)
  begin
    ssl_connection = OpenSSL::SSL::SSLSocket.new(tcp_connection, noverify_peer_context)
    ssl_connection.connect
    yield ssl_connection
  ensure
    tcp_connection.close
  end
end