Description
ABC Bank's "impossible" login hides a PHP backup. The source shows it hashes username and password with SHA1 and returns the flag when the hashes match but the raw values differ. PHP's sha1() returns false (not a string) when passed an array, and false === false, so passing arrays for both fields bypasses the check.
Setup
Append ~ to impossibleLogin.php (Emacs backup convention) to recover the actual PHP source.
Decode the Base64 constants in the source to learn the POST parameter names (username, pwd) and the SHA1-equality check.
Use Burp Suite (or curl) to intercept the login POST and change username and pwd from strings to arrays.
curl -o login.php.bak http://verbal-sleep.picoctf.net:50313/impossibleLogin.php~# Intercept the login POST with Burp Suite and change the body to:# username[]=a&pwd[]=bSolution
Walk me through it- Step 1Recover the backupEmacs creates backup files by appending a tilde to the filename. Browse impossibleLogin.php~ to download the real PHP source. Decode the Base64 constants inside: they reveal the POST field names username and pwd, and the comparison sha1($username) === sha1($pwd) && $username !== $pwd.
Learn more
Emacs editor backup files are created automatically when Emacs opens a file for editing. The backup gets the same filename with a trailing tilde (
~). When developers edit server-side files directly using Emacs in a web-accessible directory and forget to delete the backups, they become publicly downloadable - exposing source code that was never meant to be served.Common variants include Vim swap files (
.swp,.swo), nano backup files (.save), and.bakor.oldsuffixes left by IDEs. Web servers do not strip these by default, so they must be explicitly blocked in server configuration.The Base64 encoding inside the PHP source is a thin attempt to obscure hardcoded constants. Once the source is obtained, decoding takes a single command. Encoding rather than encrypting gives only the illusion of security.
- Step 2Exploit PHP type juggling with arraysUse Burp Suite to intercept the login POST request. Change the body so that both username and pwd are arrays:
username[]=a&pwd[]=b. In PHP, sha1() of an array returns false (with a warning). Since false === false, the hashes match. The raw values differ (both are arrays but were passed different dummy strings), so the != check passes too. The server returns the flag.bash# 1. Open Burp Suite > turn on Intercept > log in with any username/passwordbash# 2. In the intercepted request change:bash# username=a&pwd=bbash# to:bash# username[]=a&pwd[]=bbash# 3. Forward the requestbashbash# Or with curl directly:bashcurl -X POST -d 'username[]=a&pwd[]=b' http://verbal-sleep.picoctf.net:50313/impossibleLogin.phpLearn more
PHP type juggling arises from PHP's loose type system. Many built-in functions accept any type and silently convert or return a fallback when the input is unexpected. Passing an array to
sha1()triggers a warning and returnsfalse. When the code doessha1($username) === sha1($pwd)and both calls returnfalse, the strict equality===check passes - false equals false. At the same time, the arrays themselves are not equal as values, so the!==check between the raw inputs also passes. The login condition is satisfied without ever providing matching credentials.This technique is well-known in PHP security research. Real-world variants include comparing MD5 hashes of arrays (same behavior), using loose equality
==with certain hash strings that PHP coerces to zero (magic hash / type confusion), and passing NULL or booleans to functions expecting strings. The underlying root cause is that PHP's type system was designed for convenience, not security, and functions that accept any type can produce unexpected results in a security-sensitive context.Burp Suite is the standard web proxy for intercepting and modifying HTTP traffic. The Proxy tab captures requests before they leave the browser, the Repeater tab lets you resend a modified request any number of times, and the Decoder tab converts between Base64, URL encoding, and other formats. See the Burp Suite for picoCTF guide for the full setup workflow.
Flag
picoCTF{w3Ll_d3sErV3d_Ch4mp_5b26...}
Passing arrays instead of strings causes sha1() to return false for both, making false === false evaluate to true.