★且听安全★-点关注,不迷路!
★漏洞空间站★-优质漏洞资源和小伙伴聚集地!
2022 年 6月 10 日,PHP 官方发布了 1 个远程命令执行高危漏洞通报,编号为 CVE-2022-31626 :
漏洞源于在 PHP 源码中存在数组内存未初始化导致缓冲区溢出。攻击者在获取了连接数据库权限后,如 Adminer 、 PHPmyAdmin 等工具的权限,通过建立恶意数据库服务器,主动连接至该数据库服务器,造成堆缓冲区溢出,从而导致远程代码执行。漏洞影响版本:
-
PHP 8.1.x < 8.1.7
-
PHP 8.0.x < 8.0.20
-
PHP 7.x < 7.4.30
漏洞位于 `php_mysqlnd_change_auth_response_write` 函数中,这个函数将用户提交的密码( `packet->auth_data` )复制到一个缓冲区,以便将其发送到 MySQL 服务器。需要的条件是:MySQL 服务器要求你以传统的认证方法用明文发送认证信息。
漏洞成因并不复杂,由于 PHP 检查数据长度时没有加上 `MYSQLND_HEADER_SIZE` ,导致 `memcpy` 发生溢出,并且最大溢出长度为 `MYSQLND_HEADER_SIZE` 。当 PHP 尝试连接 MySQL 服务器时,将 `Auth Switch Ruquest` 请求中的数据长度设置为大于 `pfc->cmd_buffer.length` ,可以触发该溢出漏洞:
补丁后的代码修复了长度的计算:
测试 PHP 版本为:v8.1.6 ,启动 MySQL 服务:
配置 `php.ini` 启用 `pdo_mysql` 扩展:
extension_dir = "ext"
extension=pdo_mysql
启动 PHP,并通过脚本连接 MySQL 服务器:
php.exe -r "new PDO('mysql:host=localhost', 'b', str_repeat('a',5000));"
该脚本会调用 `PDO::__construct` 来创建一个表示连接到请求数据库的数据库连接 PDO 实例:
PDO::__construct(string $dsn ,string $username ,string $password)
参数说明
dsn:数据源名称或叫做 DSN,包含了请求连接到数据库的信息。
username:DSN字符串中的用户名。对于某些PDO驱动,此参数为可选项。
password:DSN字符串中的密码。对于某些PDO驱动,此参数为可选项。
漏洞触发过程:在与 MySQL 交互过程中,第一次登陆尝试失败后, MySQL 服务器会发送一个 `Auth_Switch_Request` 来告知客户端自己支持的认证密码插件:
PHP 在处理这个 `Auth_Switch_Request` 时,就会进入漏洞函数 `php_mysqlnd_change_auth_response_write` 。此时,该函数将 `PDO` 对象的构造参数( `str_repeat(‘a’,5000)` )拷贝至发送缓冲区,由于此时 5000 要大于 `pfc->cmd_buffer.length` ,使数据表缓冲区需要重新申请:
申请内存后调整目的地址的指针头,加上头部的大小 `MYSQLND_HEADER_SIZE` (就是 4 ):
最后调用 `memcpy`,出现溢出(4 字节)。
由于是堆溢出,且只能溢出 4 个字节,漏洞被直接利用的可能性较小。虽然漏洞利用难度较大,但鉴于漏洞影响范围较大,不排除配合其他漏洞形成攻击链,受影响客户需要尽快做好补丁升级和防护。
目前官方已发布修复版本,用户可升级至以下安全版本:
-
PHP v8.1.7
-
PHP v8.0.20
-
PHP v7.4.30
由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用本人负责,且听安全团队及文章作者不为此承担任何责任。
★且听安全★-点关注,不迷路!
★漏洞空间站★-优质漏洞资源和小伙伴聚集地!
原文始发于微信公众号(且听安全):CVE-2022-31626 PHP远程命令执行漏洞成因分析与复现