It's been quite some time since my last post on the osCommerce forum. Since then I had conversations with people and long term customers asking me the security measures that are important for their sites. Since 2007 we have examined the original framework including MS2 and the later RC versions (RC1 and RC2) and we were able to see several security issues explained below.
From the results we strongly recommend the use of the MS2.2 060817 release over the RC2 and RC2a online merchant. Not because the MS2.2 does not have problems but the issues identified with the RC versions are critical due to additional files and new code added in the osCommerce framework. While the MS2.2 060817 does not include the new vulnerable code.
The flaws, exploits and vulnerabilities reported here, can be replicated regardless of register globals or other PHP and server settings. These issues are independent of contributions integrated, as the vanilla osCommerce packages were used with php 5.x, MySql 5.x and Apache 2.x.
All problems apply to the catalog front end of the web-engine. The only recommendation we have for the admin end is to password protect the entire admin folder from the host cpanel and of course the computer system you use to access the admin pane must be clean. If either of these is compromised an attacker can access any part of the framework. The RC versions give the false impression that the admin end is secure, because they include an application based password script. Such scripts do not secure your eshop.
And a final note before going through the flaws and exploits in the vanilla framework. The various so called "security add-ons" discussed on the osCommerce forums do little to protect you from these problems. Subject to the sever software they may break the functionality of your store, can ruin the site's SEO and marketing and finally introduce additional security holes, so beware, you have been warned. It's beyond the scope of this topic to discuss various modules outside the stock framework.
1. Path disclosure vulnerability Passing the appropriate parameters via the /GET array can force an "illegal offset warning" disclosing the server path, script and line of operation.
http://example.com/product_info.php?products_id[0]=00000008
This is due to the failure of the application to verify the data type. The parameters also infiltrate the session contents as they pass through the navigation history class that handles a history of the /GET array See item-3 and also Filtering Incoming Parameters.
2. Adding random products to cart (they show as the same product but acquire different slots and cause havoc) The shopping cart functionality does not cross-reference products with different identifiers against the database. Any product can be added in the shopping cart and acquire different slots in the $cart->products array.
http://example.com/products_new.php?action=buy_now&products_id=000000008 http://example.com/products_new.php?action=buy_now&products_id=0000000008 http://example.com/products_new.php?action=buy_now&products_id=00000000008
Same approach may apply with attributes. Any product can have any set of attributes because of lack of attributes validation in the shopping cart class.
http://example.com/products_new.php?action=buy_now&products_id=8{-1}0
3. Parameter propagation Parameters can propagate with the various scripts via the tep_get_all_get_params function. This vulnerability was earlier reported with the "Filtering Incoming Parameters" blog entry:
http://example.com/products_new.php?my_param=joe Do you see the buy now and next page links what they contain? http://example.com/products_new.php?my_param=joe&page=2 http://example.com/products_new.php?my_param=joe&page=3
4. Session hijacking
The concept is old and the Session Regeneration module covers the details of this issue. Someone sets up an osCsid value of his choice and then maintains its value against the victim's site. Eg: example.com/index.php?osCsid=5 (By default, it takes 24 minutes for the session to expire if and only if is not accessed, but an attacker will make sure it is maintained by accessing a link with the identifier periodically with the help of a bot or a simple automated script). It is interesting that some suggest to switch on, the "session recreate" on the admin end. The session recreate switch, does nothing to regenerate a new session, as the identifier is the same and the referenced data are still stored within the sessions database table.
Moving on, the attacker can then publish the link with the session, on one or more popular sites, forums, blogs etc. In turn the identifier is common for anyone who clicks these links including spiders. This causes chaos as accounts and carts may end up mixed up among many other things while the attacker maintains full visibility of visitors and their actions. I've created the session regeneration (it's still available from the osCommerce contributions if you want to install it yourselves), especially for this purpose, to at least avoid this mess, when customers login to their accounts. The later versions we deploy of the Session Regeneration module can be also configured with a timer to terminate a session once a predefined period is reached. Nevertheless, the contribution had little attention and mostly negative, it seems people still don't get it.
5. E-Mail Spam flooding This issue, relates to several forms that generate emails, the most vulnerable of which, is the tell_a_friend.php script. Regardless of configuration settings that can restrict guests from sending directly, an attacker can first create a fake account and then use the form to send spam emails. A simple script can be structured that creates accounts and sends mails as the form-bot demonstrated during out tests.
$counter = 0; while($counter < 100 ) { $form_data = array( 'to_email_address' => $tx_email, 'to_name' => $name1, 'from_email_address' => $rx_email, 'from_name' => $name2, 'message'=> $message, );
$post_string = ''; foreach($form_data as $key => $val){ $post_string .= urlencode($key) . "=" . urlencode($val) . '&'; } $post_string = substr($post_string, 0, -1); $buf = sendToHost('example.com', 'POST', 'tell_a_friend.php?action=process&products_id=1', $post_string); $counter++; }
This is a code sample taken from the php generated, demonstrating the issue. The customer account creation form can also be injected in the same manner. The tell_a_frind.php script also adds the products links to the email. But the products_id is not filtered thus making that part of the code a prime target for spam. Consider the following code from the file that builds the email body.
$email_body .= sprintf(TEXT_EMAIL_LINK, tep_href_link(FILENAME_PRODUCT_INFO, 'products_id=' . $HTTP_GET_VARS['products_id'], 'NONSSL', false)) . "\n\n" . sprintf(TEXT_EMAIL_SIGNATURE, STORE_NAME . "\n" . HTTP_SERVER . DIR_WS_CATALOG . "\n"); The $HTTP_GET_VARS['products_id'] passes without filtering through therefore any string can be injected and thereafter sent to the victim as part of the link. Something like this could undermine the store because an attacker can expose the flaw to others while the site owner will be totally unaware of it. The earlier db check for the product is of no use as someone can always prefix the string with a valid product identifier.
6. Indirect Data Inclusion An attacker may utilize the reviews facility of the web engine to store arbitrary content in the database. The attacker can create an account using an automated script and then store arbitrary code that can bypass the filtering mechanisms of the database. This can be achieved using encoding or compression functions. The compressed content can be stored in the database and used by an external entity for 2 main reasons. a) The reviews are not administrator approved. b) A review can be accessed via the product reviews script (eg: product_review_info.php?products_id=1&reviews_id=1) via an external link to coordinate a larger scale attack, where the parameter values of this example, are arbitrary numbers demonstrating the weakness.
The arbitrary parameter injection also applies to the /POST array. Our form-bot indicates that attackers may flood some of the database tables, like the product notification, as there are no restrictions other than having an account. The customer account tables can also be flooded in the same way. We strongly recommend to use security measures like the ones of the anti-bot system, where the html is structured such that the form processing code verify human presence.
All the issues are completely transparent to any filtering or security oscommerce contributions known as of the time of this article (Oct. 2008). They will fall through the engine because all characters passed via /GET and /POST are valid. To rectify these issues, the merchant must update the web-engine a) to specifically ignore all parameters apart those that are used by the store's forms and b) validate the data parameters for the /GET array by type and content, those passed via the tep_href_link function.
7. Bypass checkout procedure - Update 11/16/2009 After doing additional tests here, another flaw on the RC version of osCommerce has been identified where an attacker can bypass the checkout procedure regardless of payment method selected. The problem is located in the checkout_process.php and checkout_confirmation.php files that blindly process the $payment variable without payment class verification.
The following code was set with the RC versions to fix unsuccessfully this problem from the MS2.2 releases.
if ( ( is_array($payment_modules->modules) && (sizeof($payment_modules->modules) > 1) && !is_object($$payment) ) || (is_object($$payment) && ($$payment->enabled == false)) ) { tep_redirect(tep_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(ERROR_NO_PAYMENT_MODULE_SELECTED), 'SSL')); }
This method however can still be bypassed. All it takes is a valid class object the framework has in place that is instantiated before the check and with a member variable called enabled and set to true. With the stock osCommerce RC versions this is available from all shipping modules. Each shipping module has the enabled variable and for those enabled it is set to true.
An attacker can modify the checkout_payment.php form by changing the selected radio field of the payment method to one of the enabled shipping methods. The $$payment check will be satisfied that is an object and has the enabled member variable set to true and no redirect will take place.
A correct validation procedure would be to check the object's class against the payment modules and not against any module. Also note that many modules use classes with the enabled member present that are instantiated before the code above. These can also be used to bypass the payment check.
The blind check can also be used to generate path disclosure weaknesses depending on the object's nature, because the base code does not know the type of the object->enabled member.
8. Creating Duplicates of Customer Accounts - Update 11/17/2009 An attacker can create multiple customer accounts forcing the same email address via the create customer account page. The RC versions of osCommerce allow an email address to be upto 96 characters when stored in the database.
By using buffer overflow techniques an attacker can input email addresses with length greater than 96 characters. Repeating the create account process the accounts will be created with the same email address which can be completely invalid and stored in the database.
The framework should first validate the email input by its length for a maximum to match the database storage size allocated.
9. Customer Accounts without Address Book Entries - Update 11/17/2009 An attacker can create an account and then delete all address entries associated with the account before checking out. The address_book_process.php script fails to identify if the address book of a customer is going to be empty before deleting the last entry.
if (isset($HTTP_GET_VARS['action']) && ($HTTP_GET_VARS['action'] == 'deleteconfirm') && isset($HTTP_GET_VARS['delete']) && is_numeric($HTTP_GET_VARS['delete'])) { tep_db_query("delete from " . TABLE_ADDRESS_BOOK . " where address_book_id = '" . (int)$HTTP_GET_VARS['delete'] . "' and customers_id = '" . (int)$customer_id . "'");
$messageStack->add_session('addressbook', SUCCESS_ADDRESS_BOOK_ENTRY_DELETED, 'success');
tep_redirect(tep_href_link(FILENAME_ADDRESS_BOOK, '', 'SSL')); }
The above code is located in the address_book_process.php directly following the customer presence check. Therefore someone could set the action and delete parameters of the URL to the last address book entry having an account without addresses.
Performing a checkout will likely force the shipping modules to return errors or incorrect quotes. On the admin end these accounts are visible but cannot be selected as the customers.php script expects at least one valid address book entry for each customer account. Attempts to edit the accounts may cause errors as they customers table customers_default_address_id column contains a non-existing address book identifier.
10. SQL Injection via the checkout_payment_address.php - Update 11/17/2009 With the RC versions is possible for an attacker to inject arbitrary content for the MySQL queries performed within the catalog/checkout_payment_address.php script.
The following code: $billto = $HTTP_POST_VARS['address'];
$check_address_query = tep_db_query("select count(*) as total from " . TABLE_ADDRESS_BOOK . " where customers_id = '" . $customer_id . "' and address_book_id = '" . $billto . "'");
Fails to sanitize the input parameter address. The query executerd afterwards does not filter the $billto variable at all. In addition the $billto is a session variable so an attacker can set it to whatever value he wants. Sessions are typically stored in the database. Tested with osCommerce RC2a and RC. Failure to rectify this issue can compromise the entire database and application scripts. The osC framework makes use of the eval function for the address_format dbase table. An attacker can inject code in the table and thereafter gain full control of the store.
11. Arbitrary Order Manipulation - Update 11/18/2009 An attacker can manipulate the order history of any order using the code of the paypal IPN with the stock osCommerce RC versions.
The script is located in the catalog/ext/modules/payment/paypal/standard_ipn.php. An attacker can use a fake form and post the following parameters in the script mentioned here.
- invoice
- custom
- reason_code
- payment_status
The script does not verify: If the order was placed via Paypal, if the connection to paypal was successful in terms of the order request, neither if the incoming request is from Paypal. Therefore the parameters listed here are processed and the order history is updated. The only check that is performed is the following:
if (isset($HTTP_POST_VARS['invoice']) && is_numeric($HTTP_POST_VARS['invoice']) && ($HTTP_POST_VARS['invoice'] > 0)) { Which only tests if the order id is numeric and greater than zero.
As a result, on the administration end the store owner will see the status updates the attacker wants. Note the Paypal IPN does not need to be enabled or even installed for this hack to take place. As long as the the Paypal callback handler is present this vulnerability is present.
12. Arbitrary Customers Accounts Control - Update 11/18/2009 Tested with the stock RC2a version an attacker can gain control of any customer account by setting the kunden_var_1 parameter via the catalog/ext/modules/payment/sofortueberweisung/callback.php script after creating an account. The script blindly overrides the customer_id session variable and so the new customer account the attacker creates can now be used to monitor or access other customer accounts. The following code:
if (isset($HTTP_GET_VARS['kunden_var_1'])) { $customer_id = $HTTP_GET_VARS['kunden_var_1']; } elseif (isset($HTTP_POST_VARS['kunden_var_1'])) { $customer_id = $HTTP_POST_VARS['kunden_var_1']; } Performs this process accepting the kunden_var_1 either via the $_POST or $_GET superglobals and copying it over to the $customer_id session variable. Therefore an attacker can change the customer id to whatever value he wants and then access the normal osCommerce scripts from where he can browse/change/delete various account details of customers from the store or place orders on behalf of other customers. In addition he can retrieve the customer emails.
The problem happens because the customer_id session variable is used throughout the framework. The stock payment script should not treat session variables as globals. To fix this critical problem, rename all references of $customer_id within the script or completely remove the payment module files.
Failure to rectify the issue can lead to fatal side effects for orders processed. For instance the attacker can monitor the account details and shopping cart using a bot and modify the shipping address during order processing or impersonate the customer by using his email address which is exposed using the hack for subsequent email exchange with the store owner. The sofortueberweisung payment module does not need to be enabled or installed from the admin end, for this issue to take place. |