Module: Msf::Exploit::Remote::WinRM

Includes:
Exploit::Remote::NTLM::Client, HttpClient
Defined in:
lib/msf/core/exploit/remote/winrm.rb

Instance Attribute Summary

Attributes included from HttpClient

#client, #cookie_jar

Instance Method Summary collapse

Methods included from HttpClient

#basic_auth, #cleanup, #configure_http_login_scanner, #connect, #connect_ws, #deregister_http_client_options, #disconnect, #download, #full_uri, #handler, #http_fingerprint, #lookup_http_fingerprints, #normalize_uri, #path_from_uri, #peer, #proxies, #reconfig_redirect_opts!, #request_opts_from_url, #request_url, #rhost, #rport, #send_request_cgi, #send_request_cgi!, #send_request_raw, #service_details, #setup, #ssl, #ssl_version, #strip_tags, #target_uri, #validate_fingerprint, #vhost

Methods included from Auxiliary::Report

#active_db?, #create_cracked_credential, #create_credential, #create_credential_and_login, #create_credential_login, #db, #db_warning_given?, #get_client, #get_host, #inside_workspace_boundary?, #invalidate_login, #mytask, #myworkspace, #myworkspace_id, #report_auth_info, #report_client, #report_exploit, #report_host, #report_loot, #report_note, #report_service, #report_vuln, #report_web_form, #report_web_page, #report_web_site, #report_web_vuln, #store_cred, #store_local, #store_loot

Methods included from Metasploit::Framework::Require

optionally, optionally_active_record_railtie, optionally_include_metasploit_credential_creation, #optionally_include_metasploit_credential_creation, optionally_require_metasploit_db_gem_engines

Instance Method Details

#accepts_ntlm_authObject


205
206
207
# File 'lib/msf/core/exploit/remote/winrm.rb', line 205

def accepts_ntlm_auth
  parse_auth_methods(winrm_poke).include? "Negotiate"
end

#generate_uuidObject


201
202
203
# File 'lib/msf/core/exploit/remote/winrm.rb', line 201

def generate_uuid
  ::Rex::Proto::DCERPC::UUID.uuid_unpack(Rex::Text.rand_text(16))
end

#initialize(info = {}) ⇒ Object


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/msf/core/exploit/remote/winrm.rb', line 17

def initialize(info = {})
  super
  register_options(
    [
      Opt::RPORT(5985),
      OptString.new('DOMAIN', [ true, 'The domain to use for Windows authentification', 'WORKSTATION']),
      OptString.new('URI', [ true, "The URI of the WinRM service", "/wsman" ]),
      OptString.new('USERNAME', [ false, 'A specific username to authenticate as' ]),
      OptString.new('PASSWORD', [ false, 'A specific password to authenticate with' ]),
    ], self.class
  )

  register_autofilter_ports([ 80,443,5985,5986 ])
  register_autofilter_services(%W{ winrm })
end

#parse_auth_methods(resp) ⇒ Object


37
38
39
40
41
42
43
44
# File 'lib/msf/core/exploit/remote/winrm.rb', line 37

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

#parse_wql_response(response) ⇒ Object


147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/msf/core/exploit/remote/winrm.rb', line 147

def parse_wql_response(response)
  return nil if response.nil?
  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::Text::Table.new(
    'Header'    => "#{datastore['WQL']} (#{rhost})",
    'Indent'    => 1,
    'Columns'   => columns
  )
  rows.each do |row|
    response_data << row
  end
  return response_data
end

#send_winrm_request(data, timeout = 20) ⇒ Object


227
228
229
230
231
232
233
234
235
236
237
# File 'lib/msf/core/exploit/remote/winrm.rb', line 227

def send_winrm_request(data, timeout=20)
  opts = {
    'uri' => datastore['URI'],
    'method' => 'POST',
     'data' => data,
     'username' => datastore['USERNAME'],
    'password' => datastore['PASSWORD'],
    'ctype' => "application/soap+xml;charset=UTF-8"
  }
  send_request_cgi(opts,timeout)
end

#target_urlObject


209
210
211
212
213
214
215
216
217
218
219
# File 'lib/msf/core/exploit/remote/winrm.rb', line 209

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

#winrm_cmd_msg(cmd, shell_id) ⇒ Object


110
111
112
113
114
115
116
117
118
# File 'lib/msf/core/exploit/remote/winrm.rb', line 110

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

#winrm_cmd_recv_msg(shell_id, cmd_id) ⇒ Object


120
121
122
123
124
125
126
127
# File 'lib/msf/core/exploit/remote/winrm.rb', line 120

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

#winrm_delete_shell_msg(shell_id) ⇒ Object


138
139
140
141
142
143
144
145
# File 'lib/msf/core/exploit/remote/winrm.rb', line 138

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

#winrm_get_cmd_id(response) ⇒ Object


180
181
182
183
184
# File 'lib/msf/core/exploit/remote/winrm.rb', line 180

def winrm_get_cmd_id(response)
  return nil if response.nil?
  xml = response.body
  cmd_id = REXML::Document.new(xml).elements["//rsp:CommandId"].text
end

#winrm_get_cmd_streams(response) ⇒ Object


186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/msf/core/exploit/remote/winrm.rb', line 186

def winrm_get_cmd_streams(response)
  return nil if response.nil?
  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.decode_base64(node.text)
  end
  return streams
end

#winrm_get_shell_id(response) ⇒ Object


174
175
176
177
178
# File 'lib/msf/core/exploit/remote/winrm.rb', line 174

def winrm_get_shell_id(response)
  return nil if response.nil?
  xml = response.body
  shell_id = REXML::Document.new(xml).elements["//w:Selector"].text
end

#winrm_open_shell_msgObject


101
102
103
104
105
106
107
108
# File 'lib/msf/core/exploit/remote/winrm.rb', line 101

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

#winrm_poke(timeout = 20) ⇒ Object


33
34
35
# File 'lib/msf/core/exploit/remote/winrm.rb', line 33

def winrm_poke(timeout = 20)
  send_winrm_request(Rex::Text.rand_text_alpha(8), timeout)
end

#winrm_run_cmd(cmd, timeout = 20) ⇒ Object


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/msf/core/exploit/remote/winrm.rb', line 46

def winrm_run_cmd(cmd, timeout=20)
  resp = send_winrm_request(winrm_open_shell_msg,timeout)
  if resp.nil?
    print_error "Received no reply from server"
    return nil
  end
  if resp.code == 401
    print_error "Login failure! Recheck supplied credentials."
    return resp .code
  end
  unless resp.code == 200
    print_error "Got unexpected response: \n #{resp.to_s}"
    retval = resp.code || 0
    return retval
  end
  shell_id = winrm_get_shell_id(resp)
  resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout)
  cmd_id = winrm_get_cmd_id(resp)
  resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
  streams = winrm_get_cmd_streams(resp)
  resp = send_winrm_request(winrm_terminate_cmd_msg(shell_id,cmd_id),timeout)
  resp = send_winrm_request(winrm_delete_shell_msg(shell_id))
  return streams
end

#winrm_run_cmd_hanging(cmd, timeout = 20) ⇒ Object


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/msf/core/exploit/remote/winrm.rb', line 71

def winrm_run_cmd_hanging(cmd, timeout=20)
  resp = send_winrm_request(winrm_open_shell_msg,timeout)
  if resp.nil?
    print_error "Received no reply from server"
    return nil
  end
  if resp.code == 401
    print_error "Login failure! Recheck supplied credentials."
    return resp .code
  end
  unless resp.code == 200
    print_error "Got unexpected response: \n #{resp.to_s}"
    retval = resp.code || 0
    return retval
  end
  shell_id = winrm_get_shell_id(resp)
  resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id),timeout)
  cmd_id = winrm_get_cmd_id(resp)
  resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
  streams = winrm_get_cmd_streams(resp)
  return streams
end

#winrm_terminate_cmd_msg(shell_id, cmd_id) ⇒ Object


129
130
131
132
133
134
135
136
# File 'lib/msf/core/exploit/remote/winrm.rb', line 129

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

#winrm_wql_msg(wql) ⇒ Object


94
95
96
97
98
99
# File 'lib/msf/core/exploit/remote/winrm.rb', line 94

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

#wmi_namespaceObject


221
222
223
224
225
# File 'lib/msf/core/exploit/remote/winrm.rb', line 221

def wmi_namespace
  return datastore['NAMESPACE'] if datastore['NAMESPACE']
  return @namespace_override if @namespace_override
  return "/root/cimv2/"
end