首页
社区
课程
招聘
[原创]php-fpm Remote Code Execution复现&&内核分析 (CVE-2019-11043)
发表于: 2019-10-28 11:53 1047

[原创]php-fpm Remote Code Execution复现&&内核分析 (CVE-2019-11043)

2019-10-28 11:53
1047

国外安全研究员 Andrew Danau发现向服务器请求的URL中包含%0a 符号时,服务返回异常,疑似存在漏洞。

Nginx+php-fpm的环境中,若Nginx上的fastcgi_split_path_info指令配置不当,在处理带包含%0a的URL时会导致正则匹配失效。而PATH_INFO的结果为空。

当Nginx将包含PATH_INFO为空的fastcgi传递给后端php-fpm时,php-fpm接受处理的过程存在逻辑问题,通过精心构造恶意请求可以对php-fpm进行内存污染,进一步可以复写内存并修改php-fpm配置,实现远程代码执行。

该漏洞结合Web与bin,手法十分巧妙,值得深入学习。
其中涉及到不少fpm变量、生命周期的知识,描述可能有所欠缺,请谅解,可以参考PHP内核分析-FPM和disable_function安全问题

自己搭建的方便调试,推荐

安装调试工具gdb

下载php源码:

然后对./configure 的配置如下

这里只安装必要的debug模块+fpm模块,其他模块视需求安装。

CFLAGS="-g3 -gdwarf-4"是对编译参数进行额外配置,关闭所有的编译优化机制,产生 gdb所必要的符号信息(符号表),并设置dwarf调试信息格式。PHP内核中定义了很多宏,gdb调试中可以通过macro expand xxxx命令比较方便的展开宏。

编译安装php

bin目录下包含常用的php命令行解释器

图片描述

sbin目录下包含fpm,还需要运行的配置文件。

指定fpm的配置文件,从编译后的目录复制php-fpm.conf.default并重命名为php-fpm.conf

指定php的配置文件,从源码目录中复制php.ini-development并重命名为php.ini

自行配置php.ini,这里主要配置php-fpm.conf

php-fpm为多进程模型,一个master进程,多个worker进程。

master进程负责管理调度,worker进程负责处理客户端(nginx)的请求。

master进程对work进程管理一共有三种模式:

ondemand,按需模式,当有请求时才会启动worker

static,静态模式,启动采用固定大小数量的worker

dynamic,动态模式,初始化一些worker,运行过程中动态调整worker数量

让fpm的工作模式为static,并且work进程只有一个,方便进行调试,设置配置文件如下:

运行fpm

ps可以发现work进程如期只启动一个:

图片描述

apt就行,比较关键的配置文件

要是嫌麻烦也可以直接抄P老板作业,很方便

https://github.com/vulhub/vulhub/tree/master/php/CVE-2019-11043

因为不会go语言,因此没有研究exp,通过Wireshark抓包可以发现关键的攻击数据包如下:

图片描述

分析http请求,实现远程代码执行的方法很容易猜测和理解:

通过PATH_INFO为空的fastcgi多次修改php-fpm的ini配置选项,设置error_log的地址为/tmp/a,并将一句话木马写入,然后设置include_path等,再通过auto_prepend_file包含完成远程代码执行。

修改php-fpm的ini就是漏洞的关键,选一条靠后的成型的http请求进行测试和验证:

使用phpinfo查看结果,error_reporting已经被修改。

图片描述

fpm中从fastcgi中解析处理ini的源码位置如下

sapi/fpm/fpm/fpm_main.c

图片描述

通过FCGI_GETENV获取request中存储在PHP_VALUE中的ini配置,然后通过zend_parse_ini_string将配置应用ini。

发送恶意http请求,使用GDB动态跟踪,发现request已经被污染,会解析恶意ini。
图片描述

这里获取服务器权限的方式和php-fpm未授权访问的方式相似,都是fastcgi中的PHP_VALUE修改php-fpm的ini,但是php-fpm未授权访问是发送包含PHP_VALUE的fastcgi请求,而本漏洞则是fpm处理恶意fastcgi请求逻辑错误导致被覆盖为PHP_VALUE

下面从头分析修改的error_reporting的http请求

main/fastcgi.c

fcgi_accept_request函数中通过accept函数接受来自客户端的socket连接,并赋给req->fd

图片描述

然后通过fcgi_read_request读取解析整个fastcgi请求,存储在req

图片描述

通过外层while循环,不停地调用fcgi_accept_request函数,接受连接并读取请求。

图片描述

request变量包含fastcgi请求的信息,结构如下

同时request存到全局变量,SG(server_context)中,宏定义如下:

进入init_request_info函数:

图片描述

首先从SG(server_context)中取出request,然后通过FCGI_GETENV从request更多的fastcgi请求的信息。

FCGI_GETENV宏如下

图片描述

调用fcgi_quick_getenv函数,其中FCGI_HASH_FUNC则是根据信息名称计算hash

图片描述

继续调用fcgi_hash_get函数,此时传入了重要的&req->env

图片描述

通过hash_value & FCGI_HASH_TABLE_MASK与运算的到索引idx,FCGI_HASH_TABLE_MASK宏如下

图片描述

然后通过h->hash_table[idx]的元素指针,也就是request->env->hash_table取出信息,体结构如下

这里有比较关键的char *env_path_info = FCGI_GETENV(request, "PATH_INFO");

env_path_info为指针,不为空,指向的值为空。

继续跟进到重要的path_info变量部分

图片描述

path_info = env_path_info + pilen - slen ,跟踪每个涉及的变量

env_path_info指向空字符串,所以pilen为0。

slen的计算稍微复杂一些,计算的是xxx.php?之间内容的相差部分/PHP_VALUE%0Aerror_reporting=9;;;;;;的长度

具体信息如下,slen的长度为34,此时path_info的值是env_path_info的指针向前偏移34位。

图片描述

两个字符串相差的内容和长度可以任意构造,path_info指针根据偏移的到,因此path_info指向的位置也是可控。

path_info指向的前两个字节被改为00,然后使用FCGI_PUTENV完成对request对象的污染。

待写入的orig_script_name的值为/test.php/PHP_VALUE\nerror_reporting=9;;;;;;

更改前:

图片描述

更改后:

图片描述

这里还需要关注request.env.data.pos变化,slen的长度为34,是为了让path_info指向request.env.data.pos,能够修改最低字节为00

图片描述

该变量具体作用跟进FCGI_PUTENV即可一目了然。

图片描述

调用fcgi_quick_putenv函数,参数相比fcgi_quick_getenv多了value,其余参数计算相同。

图片描述

将request.env等参数传递给fcgi_hash_set,计算idx并得到地址p

图片描述

接着调用fcgi_hash_strndup函数,根据request.env.data.pos的值确定/test.php/PHP_VALUE\nerror_reporting=9;;;;;;的写入位置

图片描述

写入的区域是根据request.env.data.data作为起始,再根据写入长度数据重新设置request.env.data.pos的值确定下次写入位置。

memcpy写入前:

图片描述

memcpy写入后:

图片描述

继续跟进到已经提过的ini获取部分,发现根据PHP_VALUE字符串得到的索引为105。

在内存污染前查看该部分,发现已经通过payload占位。

图片描述

污染后已经变为恶意ini。

图片描述

通过精心构造url、参数、header,使得path_info首先指向&request.env.data.pos附近,再利用slen进一步精准指向&request.env.data.pos,通过path_info[0]修改request.env.data.pos,使得FCGI_PUTENV写入特定位置,污染为PHP_VALUE,修改fpm的ini。

写的比较仓促,如有错误欢迎指正。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-11-5 20:52 被Rai4over编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 26205
活跃值: (63302)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
2
感谢分享!
2019-10-28 15:36
0
游客
登录 | 注册 方可回帖
返回
//