| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> PHP知识库 -> 利用PHP垃圾回收机制构造POP链 -> 正文阅读 |
|
[PHP知识库]利用PHP垃圾回收机制构造POP链 |
这本来是第四届浙江省赛的题目,有很多解法,但在赛后受歪四大佬指点。一个很“怪”的解法出现了,可能是我见识少。先放原题和一种常规解法。 原题
由于赛后没有环境,所以在phpstudy里复现的,把getFlag里的cat语句修改为了包含flag.php,并且输出flag。其实成功调用那个getFlag方法就可以。 常规思路如何调用getFlag?在类Fun中call_user_func函数可以做到,所以只需调用Fun里的 注意: exp:
payload:
强制触发垃圾回收机制思路在常规思路中我们的pop链是B→A→Fun→Test,可是B里的
在常规思路中destruct是隐式销毁触发的,当然这里使用强行GC 首先我们要简单了解垃圾回收是什么,就是把内存中不需要使用的量给清除掉,收回它所占用的空间。 旧的GC在PHP5.3版本之前,使用的垃圾回收机制是单纯的“引用计数”。即: 这个时候就出现了问题,我自己引用我自己,自身一个,自己又被引用,所以计数器是2,但我将它销毁,才减1,此时明明已销毁,但还是1,所以无法进行回收,产生了内存泄漏。 新的GC每个php变量存在一个叫"zval"的变量容器中。一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息。 第一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。通过这个字节,php引擎才能把普通变量和引用变量区分开来,由于php允许用户通过使用&来使用自定义引用,zval变量容器中还有一个内部引用计数机制,来优化内存使用。 第二个额外字节是"refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。所有的符号存在一个符号表中,其中每个符号都有作用域(scope)。简单的理解如下图所示: 具体的代码示例,网上的太多了。装个Xdebug插件就可以测试,这里就不赘述了。 触发垃圾回收该算法的实现可以在“Zend/zend_gc.c”( https://github.com/php/php-src/blob/PHP-5.6.0/Zend/zend_gc.c )中找到。每当zval被销毁时(例如:在该zval上调用unset时),垃圾回收算法会检查其是否为数组或对象。除了数组和对象外,所有其他原始数据类型都不能包含循环引用。这一检查过程通过调用gc_zval_possible_root函数来实现。任何这种潜在的zval都被称为根(Root),并会被添加到一个名为gc_root_buffer的列表中。 由于现实环境的种种限制,手动调用gc_collect_cycles()并不现实。也就是说,我们要强行触发gc,要靠填满垃圾存储空间 反序列化中触发垃圾回收以及问题解决这个涉及太多php底层内容,搞了好久也只是一知半解,我这里将原理以及遇到的问题简单点说,具体示例以及资料我会放在文章末尾 由于反序列化过程允许一遍又一遍地传递相同的索引,所以不断填充空间。一旦重新使用数组的索引,旧元素的引用计数器就会递减。在反序列化过程中将会调用zend_hash_update,它将调用旧元素的析构函数(Destructor)。每当zval被销毁时,都会涉及到垃圾回收算法。这也就意味着,所有创建的数组都会开始填充垃圾缓冲区,直至超出其空间导致对gc_collect_cycles的调用。 但是问题也来了,反序列化期间所有元素的引用计数器值都大于完成后的值。这是为啥?因为反序列化过程会跟踪所有未序列化的元素,以允许设置引用。全部条目都存储在列表var_hash中。一旦反序列化过程即将完成,就会破坏函数var_destroy中的条目。 所以针对每个在特定元素上的附加引用,我们必须让引用计数增加2。大佬给出了一种方法: ArrayObject的反序列化函数接受对另一个数组的引用,以用于初始化的目的。这也就意味着,一旦我们对一个ArrayObject进行反序列化后,就可以引用任何之前已经被反序列化过的数组。此外,这还将允许我们将整个哈希表中的所有条目递减两次。具体步骤如下: 虽然能够清零任意目标zval的引用计数器,但垃圾回收算法依然没有释放,但这太高深的东西我已经头疼了,资料就是这些,知道大致原理,我们回归到题目上来。 例子看一段代码
我们假如要执行 所以我们需要强制让php的GC(垃圾回收机制)去进行该对象的回收。上面的原理已经说了方法:需要反序列化一个数组,然后再利用第一个索引,来触发GC
得到 回到正题,这个用垃圾回收机制的题解也就出来了
多添加几次第一个索引达到多次触发gc更好,再用空格隔开更好,于是最后三行可以修改为如下:
结果都是一样的 大佬坠入Java深渊,忘记了这个GC。只能自己找、自己理解了。搞了好久查了好多的资料,还读不懂,谷歌的都是英文。本文引用了一些文章内容,还有自己的总结以及理解,如有错误,请各位指出,定会及时修改。 资料:
|
|
PHP知识库 最新文章 |
Laravel 下实现 Google 2fa 验证 |
UUCTF WP |
DASCTF10月 web |
XAMPP任意命令执行提升权限漏洞(CVE-2020- |
[GYCTF2020]Easyphp |
iwebsec靶场 代码执行关卡通关笔记 |
多个线程同步执行,多个线程依次执行,多个 |
php 没事记录下常用方法 (TP5.1) |
php之jwt |
2021-09-18 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 11:45:38- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |