type-juggling

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.

By yaklang · 2,948 installs

npx skills add yaklang/hack-skills --skill type-juggling

Source repository · Upstream listing

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) Minimal PHP probes (local or php r in lab) Routing hints Clue Next step Source code uses == to compare passwords, tokens, or HMAC values Go to Sections 1 3 md5($a) == md5($b) or loose sha1 comparison Section 2 magic hashes hash hmac(...) != '0' or compared with "0" Section 3 strcmp 、 json decode(..., true) 、 intval Section 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) Expression Result Mechanism (short) '0010e2' == '1e3' 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”) '0e462097431906509019562988736854' == '0e830400451993494058024219903391' true Both parse as 0.0 in scientific notation '123a' == 123 true String cast to int stops at first non digit → 123 'abc' == 0 true (PHP 7.x and earlier ) Non numeric string compared to int → string becomes 0 '' == 0 true Empty string → 0 '' == false true both “falsy” in loose rules false == NULL true loose equality 0 == false true loose equality '' == 0 == false == NULL true (chain) Each adjacent pair is true under == ( ''==0 , 0==false , false==NULL ) — classic “falsy” chain '0' == false true String '0' is the only non empty string that compares as false to boolean 'php' == 0 false (PHP 8+ ) PHP 8: non numeric string no longer equals 0 1.2 PHP 5 vs 7 vs 8 (high signal deltas) Topic PHP 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 == paths Same idea for numeric strings; non numeric vs int fixed as above md5([]) / sha1([]) May warn / NULL like behavior in older patterns TypeError 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) 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) Algorithm Example input Digest (starts with 0e + all decimal digits) MD5 240610708 0e462097431906509019562988736854 MD5 QNKCDZO 0e830400451993494058024219903391 SHA 1 10932435112 0e07766915004133176347055865026311692244 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 2.3 Payload sketch (pair hunting) 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: 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) Concept Example Message type Unix timestamp, incrementing id, millisecond clock Timestamp brute force pattern Tutorials 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. Goal Find $data such that hash hmac('md5', $data, $key) matches ^0e[0 9]+$ Note Without knowing $key , you may still brute $data if algorithm/output are visible in a oracle; CTFs often leak or fix key 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. Call Typical PHP 7/8 behavior md5([]) PHP 8: TypeError ; older: warnings / not reliable across versions sha1([]) Same Idea If error handler or custom wrapper converts failures to NULL , then NULL == NULL or NULL == sha1("x") if other side is also NULL 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 Payload: 5.2 intval bypass 5.3 json decode + true for associative array auth 5.4 is numeric + loose compare 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 Tool references Tool Use Local php CLI Reproduce == behavior for target major version Static code review Grep == , != on crypto outputs; find missing hash equals CTF frameworks Payload 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.