Module: Metasploit::Framework::Aws::Client

Includes:
Msf::Exploit::Remote::HttpClient
Defined in:
lib/metasploit/framework/aws/client.rb

Constant Summary collapse

USER_AGENT =
"aws-sdk-ruby2/2.6.27 ruby/2.3.2 x86_64-darwin15"

Instance Attribute Summary

Attributes included from Msf::Exploit::Remote::HttpClient

#client

Instance Method Summary collapse

Methods included from Msf::Exploit::Remote::HttpClient

#basic_auth, #cleanup, #configure_http_login_scanner, #connect, #deregister_http_client_options, #disconnect, #download, #full_uri, #handler, #http_fingerprint, #initialize, #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 Msf::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 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

#auth(creds, service, headers, body_digest, now) ⇒ Object


73
74
75
76
# File 'lib/metasploit/framework/aws/client.rb', line 73

def auth(creds, service, headers, body_digest, now)
  headers_list, signature = sign(creds, service, headers, body_digest, now)
  "AWS4-HMAC-SHA256 Credential=#{creds.fetch('AccessKeyId')}/#{now[0, 8]}/#{datastore['Region']}/#{service}/aws4_request, SignedHeaders=#{headers_list}, Signature=#{signature}"
end

#body(vars_post) ⇒ Object


78
79
80
81
82
83
84
85
86
87
# File 'lib/metasploit/framework/aws/client.rb', line 78

def body(vars_post)
  pstr = ""
  vars_post.each_pair do |var, val|
    pstr << '&' unless pstr.empty?
    pstr << var
    pstr << '='
    pstr << val
  end
  pstr
end

#call_api(creds, service, api_params) ⇒ Object


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/metasploit/framework/aws/client.rb', line 142

def call_api(creds, service, api_params)
  vprint_status("Connecting (#{datastore['RHOST']})...")
  body = body(api_params)
  body_length = body.length
  body_digest = hexdigest(body)
  begin
    res = send_request_raw(
      'method' => 'POST',
      'data' => body,
      'headers' => headers(creds, service, body_digest)
    )
    if res.nil?
      print_error "#{peer} did not respond"
    else
      Hash.from_xml(res.body)
    end
  rescue => e
    print_error e.message
  end
end

#call_ec2(creds, api_params) ⇒ Object


168
169
170
171
# File 'lib/metasploit/framework/aws/client.rb', line 168

def call_ec2(creds, api_params)
  api_params['Version'] = '2015-10-01' unless api_params['Version']
  call_api(creds, 'ec2', api_params)
end

#call_iam(creds, api_params) ⇒ Object


163
164
165
166
# File 'lib/metasploit/framework/aws/client.rb', line 163

def call_iam(creds, api_params)
  api_params['Version'] = '2010-05-08' unless api_params['Version']
  call_api(creds, 'iam', api_params)
end

#call_sts(creds, api_params) ⇒ Object


173
174
175
176
# File 'lib/metasploit/framework/aws/client.rb', line 173

def call_sts(creds, api_params)
  api_params['Version'] = '2011-06-15' unless api_params['Version']
  call_api(creds, 'sts', api_params)
end

#headers(creds, service, body_digest, now = nil) ⇒ Object


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/metasploit/framework/aws/client.rb', line 89

def headers(creds, service, body_digest, now = nil)
  now = Time.now.utc.strftime("%Y%m%dT%H%M%SZ") if now.nil?
  headers = {
    'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
    'Accept-Encoding' => '',
    'User-Agent' => USER_AGENT,
    'X-Amz-Date' => now,
    'Host' => datastore['RHOST'],
    'X-Amz-Content-Sha256' => body_digest,
    'Accept' => '*/*'
  }
  headers['X-Amz-Security-Token'] = creds['Token'] if creds['Token']
  sign_headers = ['Content-Type', 'Host', 'User-Agent', 'X-Amz-Content-Sha256', 'X-Amz-Date']
  auth_headers = headers.select { |k, _| sign_headers.include?(k) }
  headers['Authorization'] = auth(creds, service, auth_headers, body_digest, now)
  headers
end

#hexdigest(value) ⇒ Object


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/metasploit/framework/aws/client.rb', line 15

def hexdigest(value)
  if value.nil? || !value.instance_of?(String)
    print_error "Unexpected value format"
    return nil
  end
  digest = OpenSSL::Digest::SHA256.new
  if value.respond_to?(:read)
    chunk = nil
    chunk_size = 1024 * 1024 # 1 megabyte
    digest.update(chunk) while chunk = value.read(chunk_size)
    value.rewind
  else
    digest.update(value)
  end
  digest.hexdigest
end

#hexhmac(key, value) ⇒ Object


40
41
42
43
44
45
46
# File 'lib/metasploit/framework/aws/client.rb', line 40

def hexhmac(key, value)
  if key.nil? || !key.instance_of?(String) || value.nil? || !value.instance_of?(String)
    print_error "Unexpected key/value format"
    return nil
  end
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, value)
end

#hmac(key, value) ⇒ Object


32
33
34
35
36
37
38
# File 'lib/metasploit/framework/aws/client.rb', line 32

def hmac(key, value)
  if key.nil? || !key.instance_of?(String) || value.nil? || !value.instance_of?(String)
    print_error "Unexpected key/value format"
    return nil
  end
  OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, value)
end

107
108
109
110
111
112
# File 'lib/metasploit/framework/aws/client.rb', line 107

def print_hsh(hsh)
  return if hsh.nil? || !hsh.instance_of?(Hash)
  hsh.each do |key, value|
    vprint_status "#{key}: #{value}"
  end
end

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
# File 'lib/metasploit/framework/aws/client.rb', line 114

def print_results(doc, action)
  response = "#{action}Response"
  result = "#{action}Result"
  resource = /[A-Z][a-z]+([A-Za-z]+)/.match(action)[1]

  if doc["ErrorResponse"] && doc["ErrorResponse"]["Error"]
    print_error doc["ErrorResponse"]["Error"]["Message"]
    return nil
  end

  idoc = doc.fetch(response)
  if idoc.nil? || !idoc.instance_of?(Hash)
    print_error "Unexpected response structure"
    return {}
  end
  idoc = idoc[result] if idoc[result]
  idoc = idoc[resource] if idoc[resource]

  if idoc["member"]
    idoc["member"].each do |x|
      print_hsh x
    end
  else
    print_hsh idoc
  end
  idoc
end

#register_autofilter_hosts(ports = []) ⇒ Object


12
# File 'lib/metasploit/framework/aws/client.rb', line 12

def register_autofilter_hosts(ports=[]); end

#register_autofilter_ports(ports = []) ⇒ Object

because Post modules require these to be defined when including HttpClient


11
# File 'lib/metasploit/framework/aws/client.rb', line 11

def register_autofilter_ports(ports=[]); end

#register_autofilter_services(services = []) ⇒ Object


13
# File 'lib/metasploit/framework/aws/client.rb', line 13

def register_autofilter_services(services=[]); end

#request_to_sign(headers, body_digest) ⇒ Object


48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/metasploit/framework/aws/client.rb', line 48

def request_to_sign(headers, body_digest)
  if headers.nil? || !headers.instance_of?(Hash) || body_digest.nil? || !body_digest.instance_of?(String)
    return nil, nil
  end
  headers_block = headers.sort_by(&:first).map do |k, v|
    v = "#{v},#{v}" if k == 'Host'
    "#{k.downcase}:#{v}"
  end.join("\n")
  headers_list = headers.keys.sort.map(&:downcase).join(';')
  flat_request = [ "POST", "/", '', headers_block + "\n", headers_list, body_digest].join("\n")
  [headers_list, flat_request]
end

#sign(creds, service, headers, body_digest, now) ⇒ Object


61
62
63
64
65
66
67
68
69
70
71
# File 'lib/metasploit/framework/aws/client.rb', line 61

def sign(creds, service, headers, body_digest, now)
  date_mac = hmac("AWS4" + creds.fetch('SecretAccessKey'), now[0, 8])
  region_mac = hmac(date_mac, datastore['Region'])
  service_mac = hmac(region_mac, service)
  credentials_mac = hmac(service_mac, 'aws4_request')
  headers_list, flat_request = request_to_sign(headers, body_digest)
  doc = "AWS4-HMAC-SHA256\n#{now}\n#{now[0, 8]}/#{datastore['Region']}/#{service}/aws4_request\n#{hexdigest(flat_request)}"

  signature = hexhmac(credentials_mac, doc)
  [headers_list, signature]
end