目录
一、Json Serializer UAF渗透实战
1、打开靶场
2、源码分析
3、蚁剑直接连接
4、虚拟终端
5、蚁剑工具-disable function
(1)disable function插件
(2)Json Serializer UAF插件
(3)获取flag
二、原理分析
1、题目附件
2、PHP Bug #77843 简介
3、原理详解
本文详细讲解CTFHub的Web进阶中disable-functions的Json Serializer UAF关卡的渗透全流程,展示利用PHP JSON序列化组件Bug#77843绕过disable_functions限制的渗透方法。通过蚁剑工具连接靶场后,使用disablefunction插件中的JsonSerializerUAF模式成功执行命令获取flag。该风险源于PHP 7.3.3版本中json_encode处理JsonSerializable接口时的引用计数错误,导致释放后使用(UAF)风险。攻击者通过精心构造的序列化对象触发内存重用,最终实现命令执行。
一、Json Serializer UAF渗透实战
打开“Json Serializer UAF”关卡,页面提示“理论上PHP本地代码执行都可以用来 Bypass disable_function, 比如 GC UAF”,如下所示。

特别注意:本关卡还附带了题目附件,我们将在第二部分讲解。
1、打开靶场
http://challenge-d84982885c2360b7.sandbox.ctfhub.com:10800/

2、源码分析
这是一个基于PHP JsonSerializer组件的UAF(Use-After-Free)风险的利用环境,攻击者通过eval($_REQUEST['ant'])注入恶意代码,旨在绕过PHP的disable_functions安全限制。利用JSON序列化过程中释放内存后未及时清理的指针,通过精心构造的请求触发内存重用,最终实现命令执行和Webshell权限维持,源码如下所示。
本环境来源于AntSword-LabsCTFHub Bypass disable_function —— Json Serializer UAF CTFHub Bypass disable_function —— Json Serializer UAF
本环境来源于AntSword-Labs
3、蚁剑直接连接
http://challenge-d84982885c2360b7.sandbox.ctfhub.com:10800/ 密码ant


4、虚拟终端
进入虚拟终端执行ls和dir命令,如下所示,命令执行失败。


5、蚁剑工具-disable function
(1)disable function插件
我们通过蚁剑工具的disable function插件绕过服务器的限制,具体操作步骤如下所示。

(2)Json Serializer UAF插件
插件选择 Json Serializer UAF模式,如下所示点击开始。

点击开始后弹出新的虚拟终端,具体如下所示。

(3)获取flag
在新的终端中输入ls /、cat /readflag和tac /flag命令成功获取到flag,如下所示。

二、原理分析
1、题目附件
URL地址链接:PHP :: Bug #77843 :: Use after free with json serializer
https://bugs.php.net/bug.php?id=77843

Bug #77843 Use after free with json serializer
Submitted: 2019-04-04 06:59 UTC Modified: 2019-04-18 14:42 UTC
Votes: 1
Avg. Score: 3.0 ± 0.0
Reproduced: 0 of 0 (0.0%)
From: hanno at hboeck dot de Assigned: nikic (profile)
Status: Closed Package: JSON related
PHP Version: 7.3.3 OS: Linux
Private report: No CVE-ID: None
ViewDeveloperEdit[2019-04-04 06:59 UTC] hanno at hboeck dot de
Description:
------------
Together with a recent apache vulnerability
https://cfreal.github.io/carpe-diem-cve-2019-0211-apache-local-root.html
a use after free 0day bug in PHP was disclosed.
Just want to make sure you're aware of it. Compiling PHP 7.3.3 with ASAN gives me this stack trace:
==22468==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000006288 at pc 0x000001b53104 bp 0x7ffc38a68850 sp 0x7ffc38a68848
READ of size 8 at 0x606000006288 thread T0#0 0x1b53103 in ZEND_FETCH_OBJ_R_SPEC_UNUSED_CONST_HANDLER /f/php-7.3.3/Zend/zend_vm_execute.h:31199:8#1 0x19ef40c in execute_ex /f/php-7.3.3/Zend/zend_vm_execute.h:55334:7#2 0x183aa71 in zend_call_function /f/php-7.3.3/Zend/zend_execute_API.c:756:3#3 0x1839366 in _call_user_function_ex /f/php-7.3.3/Zend/zend_execute_API.c:598:9#4 0x1197b9a in php_json_encode_serializable_object /f/php-7.3.3/ext/json/json_encoder.c:490:17#5 0x1197b9a in php_json_encode_zval /f/php-7.3.3/ext/json/json_encoder.c:567#6 0x11a0491 in php_json_encode_array /f/php-7.3.3/ext/json/json_encoder.c:218:8#7 0x1197e92 in php_json_encode_zval /f/php-7.3.3/ext/json/json_encoder.c:571:11#8 0x11a0491 in php_json_encode_array /f/php-7.3.3/ext/json/json_encoder.c:218:8#9 0x1197e92 in php_json_encode_zval /f/php-7.3.3/ext/json/json_encoder.c:571:11#10 0x119528c in zif_json_encode /f/php-7.3.3/ext/json/json.c:286:2#11 0x1bbbb10 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER /f/php-7.3.3/Zend/zend_vm_execute.h:645:2#12 0x19ef40c in execute_ex /f/php-7.3.3/Zend/zend_vm_execute.h:55334:7#13 0x19efcdf in zend_execute /f/php-7.3.3/Zend/zend_vm_execute.h:60881:2#14 0x1889d94 in zend_execute_scripts /f/php-7.3.3/Zend/zend.c:1568:4#15 0x16990b7 in php_execute_script /f/php-7.3.3/main/main.c:2630:14#16 0x1cc58b3 in do_cli /f/php-7.3.3/sapi/cli/php_cli.c:997:5#17 0x1cc23e2 in main /f/php-7.3.3/sapi/cli/php_cli.c:1392:18#18 0x7faa220d64fa in __libc_start_main (/lib64/libc.so.6+0x244fa)#19 0x424419 in _start (/f/php-7.3.3/sapi/cli/php+0x424419)
Test script:
---------------
y;return $this;}
}
function get_aslr()
{global $p, $y;$p = 0;$y = [new X('PT1S')];json_encode([1234 => &$y]);print("ADDRESS: 0x" . dechex($p) . "\n");return $p;
}
get_aslr();
Patches
Pull Requests
History
AllCommentsChangesGit/SVN commitsRelated reports[2019-04-04 07:07 UTC] stas@php.net
-Type: Security
+Type: Bug
-Package: Reproducible crash
+Package: JSON related[2019-04-04 07:07 UTC] stas@php.net
This looks like it requires specially crafted code, therefore not a security issue.[2019-04-18 14:42 UTC] nikic@php.net
-Assigned To:
+Assigned To: nikic[2019-04-18 14:42 UTC] nikic@php.net
Slightly simplified test code (valgrind):
class X implements JsonSerializable {public $prop = "value";public function jsonSerialize() {global $arr;unset($arr[0]);var_dump($this);return $this;}
}
$arr = [new X()];
var_dump(json_encode([&$arr]));
We need to make sure a ref is kept when calling jsonSerialize() and probably also when recursing over arrays/objects in general (as something may be unset at a higher level).[2019-04-23 10:44 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=4831e150c5ada631c1480098b8a42cbf024d8899
Log: Fixed bug #77843[2019-04-23 10:44 UTC] nikic@php.net
-Status: Assigned
+Status: Closed
2、PHP Bug #77843 简介
PHP Bug #77843 是 2019 年 4 月披露的、存在于 PHP 7.3.3 版本中与 JSON 序列化相关的释放后使用(Use After Free)的风险,由用户 hanno at hboeck dot de 报告,可通过构造实现JsonSerializable接口的类(如自定义X类继承DateInterval并重写jsonSerialize方法)触发,在json_encode处理含引用的数组时,因未保留对象引用导致内存被释放后仍被访问,进而产生堆内存错误;官方最初将其归类为 “Bug” 而非安全问题,最终由 nikic 分配处理并于 2019 年 4 月 23 日通过提交修复,该风险无 CVE 编号,复现率为 0%,投票数 1,平均评分 3.0±0.0。
| 字段 | 详情 |
|---|---|
| Bug ID | #77843 |
| 标题 | Use after free with json serializer(JSON 序列化器相关的释放后使用) |
| 报告时间 | 2019 年 4 月 4 日 06:59 UTC |
| 报告者 | hanno at hboeck dot de |
| 处理状态 | 已关闭(Closed) |
| 分配处理人 | nikic(PHP 核心开发者) |
| 所属包 | JSON related(JSON 相关模块) |
| 影响 PHP 版本 | 7.3.3 |
| 运行操作系统 | Linux |
| 私有报告标识 | No(非私有报告,内容公开) |
| CVE 编号 | None(未分配 CVE) |
| 社区投票 | 1 票 |
| 平均评分 | 3.0 ± 0.0(满分 5 分,影响程度中等) |
| 复现率 | 0 of 0(0.0%,无有效复现记录) |
3、原理详解
核心原因是json_encode在处理实现JsonSerializable接口的对象时,未正确保留对象引用:
- 当通过
json_encode处理含引用的数组时,进入自定义jsonSerialize方法; - 方法内部执行
unset操作删除数组中的对象元素,导致对象内存被标记为可释放并被回收; - 后续代码仍试图访问已释放的对象属性(如
$this->y),触发堆内存读取错误(heap-use-after-free)。