AWS - Lambda Privesc
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
More info about lambda in:
iam:PassRole
, lambda:CreateFunction
, (lambda:InvokeFunction
| lambda:InvokeFunctionUrl
)Users with the iam:PassRole
, lambda:CreateFunction
, and lambda:InvokeFunction
permissions can escalate their privileges.
They can create a new Lambda function and assign it an existing IAM role, granting the function the permissions associated with that role. The user can then write and upload code to this Lambda function (with a rev shell for example).
Once the function is set up, the user can trigger its execution and the intended actions by invoking the Lambda function through the AWS API. This approach effectively allows the user to perform tasks indirectly through the Lambda function, operating with the level of access granted to the IAM role associated with it.\
A attacker could abuse this to get a rev shell and steal the token:
You could also abuse the lambda role permissions from the lambda function itself. If the lambda role had enough permissions you could use it to grant admin rights to you:
It is also possible to leak the lambda's role credentials without needing an external connection. This would be useful for Network isolated Lambdas used on internal tasks. If there are unknown security groups filtering your reverse shells, this piece of code will allow you to directly leak the credentials as the output of the lambda.
Potential Impact: Direct privesc to the arbitrary lambda service role specified.
Note that even if it might looks interesting lambda:InvokeAsync
doesn't allow on it's own to execute aws lambda invoke-async
, you also need lambda:InvokeFunction
iam:PassRole
, lambda:CreateFunction
, lambda:AddPermission
Like in the previous scenario, you can grant yourself the lambda:InvokeFunction
permission if you have the permission lambda:AddPermission
Potential Impact: Direct privesc to the arbitrary lambda service role specified.
iam:PassRole
, lambda:CreateFunction
, lambda:CreateEventSourceMapping
Users with iam:PassRole
, lambda:CreateFunction
, and lambda:CreateEventSourceMapping
permissions (and potentially dynamodb:PutItem
and dynamodb:CreateTable
) can indirectly escalate privileges even without lambda:InvokeFunction
.
They can create a Lambda function with malicious code and assign it an existing IAM role.
Instead of directly invoking the Lambda, the user sets up or utilizes an existing DynamoDB table, linking it to the Lambda through an event source mapping. This setup ensures the Lambda function is triggered automatically upon a new item entry in the table, either by the user's action or another process, thereby indirectly invoking the Lambda function and executing the code with the permissions of the passed IAM role.
If DynamoDB is already active in the AWS environment, the user only needs to establish the event source mapping for the Lambda function. However, if DynamoDB isn't in use, the user must create a new table with streaming enabled:
Now it's posible connect the Lambda function to the DynamoDB table by creating an event source mapping:
With the Lambda function linked to the DynamoDB stream, the attacker can indirectly trigger the Lambda by activating the DynamoDB stream. This can be accomplished by inserting an item into the DynamoDB table:
Potential Impact: Direct privesc to the lambda service role specified.
lambda:AddPermission
An attacker with this permission can grant himself (or others) any permissions (this generates resource based policies to grant access to the resource):
Potential Impact: Direct privesc to the lambda service role used by granting permission to modify the code and run it.
lambda:AddLayerVersionPermission
An attacker with this permission can grant himself (or others) the permission lambda:GetLayerVersion
. He could access the layer and search for vulnerabilities or sensitive information
Potential Impact: Potential access to sensitive information.
lambda:UpdateFunctionCode
Users holding the lambda:UpdateFunctionCode
permission has the potential to modify the code of an existing Lambda function that is linked to an IAM role.
The attacker can modify the code of the lambda to exfiltrate the IAM credentials.
Although the attacker might not have the direct ability to invoke the function, if the Lambda function is pre-existing and operational, it's probable that it will be triggered through existing workflows or events, thus indirectly facilitating the execution of the modified code.
Potential Impact: Direct privesc to the lambda service role used.
lambda:UpdateFunctionConfiguration
With this permissions it's possible to add environment variables that will cause the Lambda to execute arbitrary code. For example in python it's possible to abuse the environment variables PYTHONWARNING
and BROWSER
to make a python process execute arbitrary commands:
For other scripting languages there are other env variables you can use. For more info check the subsections of scripting languages in:
Lambda Layers allows to include code in your lamdba function but storing it separately, so the function code can stay small and several functions can share code.
Inside lambda you can check the paths from where python code is loaded with a function like the following:
These are the places:
/var/task
/opt/python/lib/python3.7/site-packages
/opt/python
/var/runtime
/var/lang/lib/python37.zip
/var/lang/lib/python3.7
/var/lang/lib/python3.7/lib-dynload
/var/lang/lib/python3.7/site-packages
/opt/python/lib/python3.7/site-packages
/opt/python
For example, the library boto3 is loaded from /var/runtime/boto3
(4th position).
It's possible to abuse the permission lambda:UpdateFunctionConfiguration
to add a new layer to a lambda function. To execute arbitrary code this layer need to contain some library that the lambda is going to import. If you can read the code of the lambda, you could find this easily, also note that it might be possible that the lambda is already using a layer and you could download the layer and add your code in there.
For example, lets suppose that the lambda is using the library boto3, this will create a local layer with the last version of the library:
You can open ./lambda_layer/boto3/__init__.py
and add the backdoor in the global code (a function to exfiltrate credentials or get a reverse shell for example).
Then, zip that ./lambda_layer
directory and upload the new lambda layer in your own account (or in the victims one, but you might not have permissions for this).
Note that you need to create a python folder and put the libraries in there to override /opt/python/boto3. Also, the layer needs to be compatible with the python version used by the lambda and if you upload it to your account, it needs to be in the same region:
Now, make the uploaded lambda layer accessible by any account:
And attach the lambda layer to the victim lambda function:
The next step would be to either invoke the function ourselves if we can or to wait until it gets invoked by normal means–which is the safer method.
A more stealth way to exploit this vulnerability can be found in:
Potential Impact: Direct privesc to the lambda service role used.
iam:PassRole
, lambda:CreateFunction
, lambda:CreateFunctionUrlConfig
, lambda:InvokeFunctionUrl
Maybe with those permissions you are able to create a function and execute it calling the URL... but I could find a way to test it, so let me know if you do!
Some lambdas are going to be receiving sensitive info from the users in parameters. If get RCE in one of them, you can exfiltrate the info other users are sending to it, check it in:
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)