AWS Pentesting: Cybr’s Exploiting Lambda Command Injection to access DynamoDB lab

@ro0taddict
7 min readJan 3, 2025

--

Introduction

This walkthrough covers the Cybr’s Exploitation Lambda Command Injection to access DynamoDB lab. Lambda is a serverless compute service offered by AWS that automatically runs your code in response to events, scaling as needed and charging only for the compute time used. Lambda can be exposed to the internet or private.

The lab features a web application powered by Lambda that is vulnerable to Command Injection.

Command injection is an attack in which the goal is execution of arbitrary commands on the host operating system via a vulnerable application. Command injection attacks are possible when an application passes unsafe user supplied data (forms, cookies, HTTP headers etc.) to a system shell.

Due to command injection, we can then get the temporary tokens of the Lambda service. This token has access to DynamoDB , a fully managed NoSQL database service offered by AWS, that provides fast and flexible key-value and document-based storage.

Turning on the lab generates a unique Lambda endpoint. Below is our endpoint as shown in the sample screenshots.

https://eknihhrhvlutbd3ag7gsmsx5he0xkazi.lambda-url.us-east-1.on.aws/

In this lab, we used Burp Suite pro and the Burp-imbedded browser.

Lets access the Lambda endpoint in a browser. The image below shows an input field where one needs to enter a date to retrieve the newspaper for the day. Entering a single quote or a number shows there is some form of syntax validation implemented.

We noticed that the URL doesn't change even if a valid response was returned.

Checking the Page Source shows that the user input is supplied in the “path” parameter.

We can confirm it in Burp.

If traffic isn’t a concern during a pentest, we can simultaneously run a vulnerability scan on the request while conducting manual recon

In Burp pro, we can do it by right clicking the request then select “Scan”. or “Do active scan”. We can also configure the Scope first.

If you dont have Burp pro, you can also use OWASP Zap for this use case. Another tool you may utilize when finding command injection vulnerability is Commix which we can get from this link.

In my case, I sent the request to Repeater and Intruder.

In Intruder, I added a word “test” at the end of the request just for a placeholder. For the attack type, I selected “Sniper attack”. For payload type, I selected “ Simple list”. We will use a wordlist from Payloadallthethings. We can then add some of the wordlist that we know will work in the web app. The lab mentioned that for the security of the platform, certain commands are just whitelisted such as “;ls” and “;pwd”.

Click “Start attack” to run the attack. We can then filter the result by status 200 and by length. We will then notice that “;ls” returned a different length.

Checking the response shows the “ls” command was executed by the app.

Thinking this is a Lambda service, we can use command such as “printenv”, ”env”, or “cat /proc/self/environ” to try to get the STS temporary credentials.

After getting the temporary credentials ( notice it says ASIA instead of AKIA), lets configure this credentials to check the permission we got.

As usual, we can use aws-enumerator again, which we can get from this link, to bruteforce for permission available for the token.

Remember that some AWS resources are region-specific, so we can try running the tool both with and without the region configured.

The output of the tool will display results only for the STS service.

Lets try another tool such as enumerate-iam from Andres Riancho, which we can get from this link.

enumerate-iam.py  --access-key ACCESS_KEY --secret-key SECRET_KEY --session-token SESSION_TOKEN --region REGION

(If you noticed it, the Access keys, secret and token are different because I requested another token)

Running enumerate-iam shows that we have permission to list the tables in DynamoDB.

As part of my methodology, I would run Cloudfox with “inventory” option ( or Prowler with “quick-check” option) to see the services allowed in the current IAM access from a high level perspective.

./cloudfox aws --profile cybr  inventory

Cloudfox also shows that DynamoDB is used in the target organization. Lets then run the “list-tables” dynamodb command to check for available table names.

aws dynamodb list-tables --profile cybr

The image above shows there is a table named “rcecybr”. Lets try to scan the table by running “scan” dynamodb command.

aws dynamodb scan --table-name rcecybr --region us-east-1 --profile cybr >output.json && cat output.json
echo "RkxBR<redacted>==" | base64 -d

The results below indicate that the token values for all users are the same, except for the user John. Decoding this Base64 value, his token reveals the flag.

The vulnerable code:

The code snippet below is extracting the path value from the query string parameters of an event (likely in the context of an AWS Lambda function or a similar event-driven system).

if 'queryStringParameters' in event and event['queryStringParameters'] and 'path' in event['queryStringParameters']:
path = event['queryStringParameters']['path']

The “path” parameter is user controllable input.

Another code snippet below shows the reason why we are able to terminate the first command using “;”. The code basically splits the user input (path) using a semicolon (;):

parts = path.split(';', 1)  # Split only on the first semicolon
date_part = parts[0].strip()
cmd_part = parts[1].strip() if len(parts) > 1 else ""

date_part is the first segment before the semicolon. The cmd_part is anything that comes after the semicolon.

The snippet below show that there is some syntactic input validation used. The date is validated against a regex to ensure it follows the format DD MM YYYY. However, there is no validation or sanitization of the cmd_part

valid_date = re.match(r'^\\\\d{2} \\\\d{2} \\\\d{4}$', date_part)

The variable “allowed_commands” was just used specifically for this lab to secure the lab platform from unintended use. It whitelisted specific commands such as “ls”, “pwd” and others.

allowed_commands = ['ls', 'pwd', 'date', 'printenv', 'env', 'cat /proc/self/environ']
if cmd_part and cmd_part in allowed_commands:
result = subprocess.check_output(cmd_part, shell=True, stderr=subprocess.STDOUT, universal_newlines=True)

The code below executes a shell command defined in cmd_part and captures its output and errors as a string, which poses a security risk if cmd_part includes untrusted input.

result = subprocess.check_output(cmd_part, shell=True, stderr=subprocess.STDOUT, universal_newlines=True)

Using shell=True runs the command in a shell, which can allow command injection.

Mitigation/Remediation:

Below are directly quoted from Cybr as mitigation strategies to protect against command injection:

1.Avoid Using shell=True:

The subprocess module should be used with shell=False to prevent the shell from interpreting the input. This means any shell metacharacters will not be processed.

2. Strict Input Validation:
Use strict validation rules to ensure the input matches only the expected format. Do not split input into multiple parts that could allow unintended commands.

3. Sanitize Input Thoroughly:
Use sanitization techniques to remove or escape any characters that could be used for command injection, such as ;, &, |, >, etc. Best approach is whitelisting not blacklisting

4. Use a Safe Execution Framework:
Instead of directly executing shell commands, use a more secure framework or API that safely handles the specific tasks you need (e.g., listing files, getting the current directory).

5. Log and Monitor Input and Execution:
Keep thorough logs of all inputs and command executions, and monitor them for any unusual activity.

References:

https://medium.com/@kariarce2377/cybr-academy-exploiting-lambda-command-injection-to-access-dynamodb-walkthrough-699ffb1ba34c
https://cybr.com/hands-on-labs/lab/exploiting-lambda-command-injection-to-access-dynamodb/
https://owasp.org/www-community/attacks/Command_Injection
https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html

--

--

@ro0taddict
@ro0taddict

Written by @ro0taddict

InfoSec enthusiast; Lifelong learner

No responses yet