PHP绕过禁用函数漏洞的原理
这篇文章主要讲解了“PHP绕过禁用函数漏洞的原理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PHP绕过禁用函数漏洞的原理”吧!
公司主营业务:成都网站建设、成都网站设计、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联公司是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联公司推出新田免费做网站回馈大家。
漏洞简介
PHP 发布公告,旧版本的 php_array_merge_recursive 函数中存在UAF风险,被利用可能导致用来绕过禁用函数。
受影响的版本
PHP 7.2 - 7.4.9
安全专家建议用户尽快升级到安全版本,以解决风险。
漏洞原理
一、array_merge_recursive 函数实现
在 array_merge_recursive 函数的实现中,通过遍历源数组键值,如果键值不存在,则将对应的值直接插入目标数组;如果键值存在,则查询相应的目标数组。在目标数组不存在此键值时,将键值与相应的值插入目标数组;如果存在相同的键值,则会尝试将相应的值加入到目标数组中。具体处理如下图,在目标值为 NULL 时,将其转变为数组类型并在数组中加入 NULL,在源数组中的值为对象类型时将其转换为数组类型,尝试为 src_entry 添加引用后将 src_zval 添加到数组中;如果源数组中的值类型为数组则递归调用 php_array_merge_recursive 函数。
二、原理分析
在尝试为源数组中的值添加引用计数的时候错误地调用了 Z_TRY_ADDREF_P(src_entry), src_entry 此时为对源数组中的值的引用,此时引用计数被添加到了引用而不是源数组中的值。
如果在 array_merge_recursive 函数中传入可变的字符串(通过直接赋值获得的字符串不可变,在尝试添加引用计数时会失败),此时 src_zval 即可变字符串的引用计数并没有增加,在数组被销毁时,因为可变字符串的引用计数提前变为 0 导致 UAF。
三、利用分析
注: 以下调试直接在 php 调试而不是在服务器加载 php 调试,但是差别不大。
1、在字符串被释放后,创建一个新的对象占位,进行类型混淆,此时字符串的 len 被新创建对象的 ce 覆盖。ce 是一个地址,所以后续不会影响字符串的写入。
占位前后对比图如下:
字符串对象被释放后,创建对象前:
创建对象后:
2、读取新创建对象的 handlers 方便之后泄露内存信息,handers 的值即为上图的 0x0000000008dfe500,在后面可以达到任意内存读取后可以用来泄露 php 基地址。读取新创建对象中包含堆地址的区域,获取被释放的字符串地址,例如可以读取 0x7ffffb080540 中的堆地址,减去 0xc8 即为字符串对象中的字符串地址 hex(0x00007ffffb0805b0 - 0xc8) = 0x7ffffb0804e8 即为字符串对象的 val 属性的地址。
3、将新创建对象的一个属性的值指向的类型改写为引用,引用的地址为一个伪造的引用字符串对象。可以将新创建对象的第一个属性即 properties_table 数组中的第一个元素的类型改为引用,地址改为伪造的引用字符串对象的地址。地址0x7ffffb0804f8 保存的即为新创建对象的第一个属性的地址,地址0x7ffffb080500 中存储的 0xa 代表引用类型。
其指向的地址 0x00007ffffb080548 保存的为伪造引用对象的地址,伪造的对象的第三个八字节需置为 6 (引用对象的类型)。引用字符串对象的内存布局如下图。可以看到,引用中保存类型为 0x6 代表字符串类型,但是地址为 0x0,之后可以通过写入任意地址来达到内存读取。
4、通过修改伪造的字符串的起始地址来达到任意内存读取,利用之前泄露的 handlers 地址来获取 elf 基址,之后遍历内存获取 zif_system 函数的地址。
5、伪造一个闭包对象,从一个真实存在的闭包对象拷贝其存储的值,修改函数类型为内置函数类型,has_dimension 属性地址为 zif_system,修改后如下图。
6、修改对象的一个属性地址为伪造的闭包对象的地址,调用对象的属性函数即可完成禁用函数的绕过。
漏洞验证
一、在7.4.5 版本中进行攻击尝试
在目标服务器上传利用脚本,执行命令。
(视频地址:https://v.qq.com/x/page/c31651dla6g.html)
二、7.4.10 版本修复分析
修改 Z_TRY_ADDREF_P(src_entry) 为 Z_TRY_ADDREF_P(src_zval)。
感谢各位的阅读,以上就是“PHP绕过禁用函数漏洞的原理”的内容了,经过本文的学习后,相信大家对PHP绕过禁用函数漏洞的原理这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!
本文名称:PHP绕过禁用函数漏洞的原理
文章起源:http://pwwzsj.com/article/ggccgg.html