cve-2022-31626[to be continue]

有相当长的时间没有写文章了 上一篇文章还停留在2021-12-28 然后 是10-30 然后又是半年

写博客也是相当好的一个习惯吧至少我认为

关于安全 还有很多事情要做 但是这一年做了点别的事情 时常感觉自己没有动力 本事不大脾气不小 只感觉到生命的流逝 兜兜转转还是回到这个最熟悉的领域 果然最后还是安全给了我安全感

但 一旦没有跟上脚步 即使你出发的再早 等哪一天身边那些起步晚数年的都已经超过你了 看起来还是让人觉得很惆怅 真的压力好大… 还好我今年才24…

去挑几个好玩的漏洞来分析一下

https://www.cvedetails.com/vulnerability-list/vendor_id-74/product_id-128/year-2022/PHP-PHP.html

https://github.com/CFandR-github/PHP-binary-bugs/blob/main/cve_2022_31626_remote_exploit/cve_writeup.md

从这里开始学习二进制

学而时习之 不亦说乎

开始学习吧

image-20220704212842810

内存申请不够导致边界溢出 那么入手点就在MYSQLND_HEADER_SIZE这个参数,看名字应该是mysqlnd通讯时的头部

poc测试

image-20220705201741127

image-20220705201752917

image-20220705201810414

poc倒是没有给出shell什么的 但是的确是让服务crash了

环境

1
2
chocolazy@chocolazy:~/php74-dev$ cat /proc/version
Linux version 5.4.0-91-generic (buildd@lcy01-amd64-017) (gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)) #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021
1
2
3
4
5
6
7
8
git clone https://github.com/php/php-src
cd php-src/
git switch PHP-7.4.30
git checkout 55f6895f4b4c677272fd4ee1113acdbd99c4b5ab
cp -R php-src/ php74-
cd php74-dev/
./buildconf
'./configure' '--with-bz2' '--with-zlib' '--with-mysqli=mysqlnd' '--enable-pdo' '--with-pdo-mysql=mysqlnd' '--enable-sockets' '--with-curl'

为了避免麻烦 跟参考文章相比 configure里删了一些没用的 然后就是报错一个安装一个 比如

1
2
configure: error: bison 3.0.0 is required to generate PHP parsers (excluded versions: none).
chocolazy@chocolazy:~/php74-dev$ sudo apt install bison

把优化关了

image-20220708025221804

然后 make -j4 一下 等…

image-20220705185959061

再配置一个clion的调试 https://blog.csdn.net/weixin_42264234/article/details/120937676 完成

image-20220706151937727

分析与调试

我们需要知道的是 文章对漏洞本身的分析一笔带过 而花了很大一部分去布局

抛弃文章的分析 如何定位到问题点

测试脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php
function select($result, $limit = 0)
{
for ($i = 0; (!$limit || $i < $limit) && ($row = $result->fetch_row()); $i++) {
if (!$i) {
echo "<div class='scrollable'><table cellspacing='0' class='nowrap'><thead>";
for ($j = 0; $j < count($row); $j++) {
$field = $result->fetch_field();
$name = $field->name;
$orgtable = $field->orgtable;
$orgname = $field->orgname;
echo "<th" . ($orgtable != "" || $field->name != $orgname ? " title='" . ($orgtable != "" ? "$orgtable." : "") . $orgname . "'" : "") . ">" . $name . '';
}
echo "</thead>";
}

echo "<tr>";
foreach ($row as $key => $val) {
echo "<td>";
echo $val;
echo "</td>";
}
echo "</tr>";
}
echo($i ? "</table></div>" : "");
}

//============================================================================

class MyDB extends MySQLi
{
var $extension = "MySQLi";

function __construct()
{
parent::init();
}

function connect($server = "", $username = "", $password = "", $database = null, $port = null, $socket = null)
{
$return = @$this->real_connect($server, $username, $password, $database, $port);
$this->options(MYSQLI_OPT_LOCAL_INFILE, false);
return $return;
}

}

$s = [
'server' => '192.168.28.1',
'username' => 'root',
'password' => 'hundan',
'db' => 'test',
'port' => 3306,
];
$c = new MyDB();
$c->connect($s['server'], $s['username'], $s['password'], $s['db'], $s['port']);
$c->multi_query("select 1; select 2;");

do {
$result = $c->store_result();
if (is_object($result)) {
select($result);
}
} while ($c->next_result());

1
gdbserver :1234 ../../sapi/cli/php m.php

检查补丁 漏洞点位于 ext/mysqlnd/mysqlnd_wireprotocol.c:774 直接打断点进不去 根据跟踪我们找到了两个入口

1
2
ext/mysqlnd/mysqlnd_auth.c:273
ext/mysqlnd/mysqlnd_auth.c:403

我们选择前者进行分析 其中 use_full_blown_auth_packet 按文章的理解应该是明文登录就可以了 但是还是往上跟踪一下

向上跟踪 ext/mysqlnd/mysqlnd_auth.c:147 有个first_call = FALSE; 根据上下文理解应该不是明文登录 而是可能类似断线重连的操作

我们看到 ext/mysqlnd/mysqlnd_auth.c:163

1
while (ret == FAIL && conn->error_info->error_no == 0 && switch_to_auth_protocol != NULL);

switch_to_auth_protocol需要再跟进去 找到这一段 ext/mysqlnd/mysqlnd_auth.c:334

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (auth_resp_packet.response_code == 0xFE) {
/* old authentication with new server !*/
if (!auth_resp_packet.new_auth_protocol) {
DBG_ERR(mysqlnd_old_passwd);
SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
} else {
*switch_to_auth_protocol = mnd_pestrndup(auth_resp_packet.new_auth_protocol, auth_resp_packet.new_auth_protocol_len, FALSE);
*switch_to_auth_protocol_len = auth_resp_packet.new_auth_protocol_len;
if (auth_resp_packet.new_auth_protocol_data) {
*switch_to_auth_protocol_data_len = auth_resp_packet.new_auth_protocol_data_len;
*switch_to_auth_protocol_data = mnd_emalloc(*switch_to_auth_protocol_data_len);
memcpy(*switch_to_auth_protocol_data, auth_resp_packet.new_auth_protocol_data, *switch_to_auth_protocol_data_len);
} else {
*switch_to_auth_protocol_data = NULL;
*switch_to_auth_protocol_data_len = 0;
}
}
}

我们在登录报文里找到了response code

image-20220707144945681

在mysql文档里面我们找到了关于ok packet的信息 也就是说0xFE代表的是EOF数据包

image-20220707145459247

但我们还是不去纠结这些信息在mysql中代表什么 但是简单来说我们需要在auth user阶段去构造一个eof 我们尝试去构造一个畸形的packet

为了节省额外工作的时间 我们直接去观察一下 rogue_sql_server.py

cve_2022_31626_remote_exploit/rogue_sql_server.py:276

1
2
#switch auth packet
p2 = AuthSwitch()

cve_2022_31626_remote_exploit/rogue_sql_server.py:188

1
2
3
4
5
6
7
8
9
10
11
12
13
class AuthSwitch(Packet):
def __init__(self):
self.status = 0xfe
self.auth_method_name = 'mysql_clear_password'
self.auth_method_data = 'abc'

def get_to_str(self):
r = ''
r += self.pack_1_byte(self.status)
r += self.auth_method_name + '\x00'
r += self.auth_method_data + '\x00'
return r

返回成功后我们进入到漏洞点 ext/mysqlnd/mysqlnd_wireprotocol.c:774

image-20220707174121027

我们仔细观察一下 尝试让代码成立

1
pfc->cmd_buffer.length >= packet->auth_data_len

向上跟踪 当然大概率 cmd_buffer 是写死的 如果 cmd_buffer.length 可控的话 那么将是一个莫大的喜讯 而 auth_data_len 是我们能控制的位置

由于结构体等定义在头文件里无法动态调试 我们又翻阅起了鸟哥的源码解析 https://www.laruence.com/2020/03/23/5605.html (btw认真做事的人总有一些文人情怀 )

到这里我们就能明白 我们很难通过获取数据库服务器去反向攻击代码服务器 更多的是通过类似pma的情况

一些其他备注

Z_OBJ_P zend_object_get_address

XtOffsetOf(zend_string, val)表示计算出zend_string结构体的大小

另外

除了phpmyadmin 以及其他可控数据源以外 我们还可以尝试获取数据库服务器权限 从而去攻击代码服务器


https://www.sudytech.com/_s80/_t690/2018/0729/c3276a26052/page.psp

https://gywbd.github.io/posts/2016/2/debug-php-source-code.html

http://c.biancheng.net/view/446.html

https://blog.csdn.net/weixin_42264234/article/details/120937676#t6

https://www.jiyik.com/tm/xwzj/prolan_290.html

https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html

https://www.cnblogs.com/pingyeaa/p/9688248.html

https://www.codeleading.com/article/3528741432/

https://www.laruence.com/2020/03/23/5605.html

Author: hundan
Link: https://hundan.org/2022/07/04/cve-2022-31626/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.