HTB - Seal

Basic Nmap scan
Nmap Command: nmap -Pn -n -sC -sV -oN 10.10.10.250-d-scan 10.10.10.250
Nmap scan report for 10.10.10.250
Host is up (0.15s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 4b894739673d07315e3f4c27411ff967 (RSA)
| 256 04a74f399565c5b08dd5492ed8440036 (ECDSA)
|_ 256 b45e8393c54249de7125927123b18554 (ED25519)
443/tcp open ssl/http nginx 1.18.0 (Ubuntu)
| tls-alpn:
|_ http/1.1
|_http-server-header: nginx/1.18.0 (Ubuntu)
| tls-nextprotoneg:
|_ http/1.1
|_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
|_ssl-date: TLS randomness does not represent time
8080/tcp open http-proxy
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Server returned status 401 but no WWW-Authenticate header.
|_http-title: Site doesn't have a title (text/html;charset=utf-8).
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 401 Unauthorized
| Date: Thu, 20 Oct 2022 04:12:15 GMT
| Set-Cookie: JSESSIONID=node01sqwxjtfptte1ar3carw6raxd2.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 0
| GetRequest:
| HTTP/1.1 401 Unauthorized
| Date: Thu, 20 Oct 2022 04:12:13 GMT
| Set-Cookie: JSESSIONID=node0137rclvnco4znpxjpee5lk4e60.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 0
| HTTPOptions:
| HTTP/1.1 200 OK
| Date: Thu, 20 Oct 2022 04:12:14 GMT
| Set-Cookie: JSESSIONID=node03dc6v9slx69a1dlrz9m5pweia1.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Allow: GET,HEAD,POST,OPTIONS
| Content-Length: 0
| RPCCheck:
| HTTP/1.1 400 Illegal character OTEXT=0x80
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 71
| Connection: close
| <h1>Bad Message 400</h1><pre>reason: Illegal character OTEXT=0x80</pre>
| RTSPRequest:
| HTTP/1.1 505 Unknown Version
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 58
| Connection: close
| <h1>Bad Message 505</h1><pre>reason: Unknown Version</pre>
| Socks4:
| HTTP/1.1 400 Illegal character CNTL=0x4
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 69
| Connection: close
| <h1>Bad Message 400</h1><pre>reason: Illegal character CNTL=0x4</pre>
| Socks5:
| HTTP/1.1 400 Illegal character CNTL=0x5
| Content-Type: text/html;charset=iso-8859-1
| Content-Length: 69
| Connection: close
|_ <h1>Bad Message 400</h1><pre>reason: Illegal character CNTL=0x5</pre>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8080-TCP:V=7.93%I=7%D=10/20%Time=6350CA9E%P=x86_64-unknown-linux-gn
SF:u%r(GetRequest,F4,"HTTP/1\.1\x20401\x20Unauthorized\r\nDate:\x20Thu,\x2
SF:020\x20Oct\x202022\x2004:12:13\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node
SF:0137rclvnco4znpxjpee5lk4e60\.node0;\x20Path=/;\x20HttpOnly\r\nExpires:\
SF:x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent-Type:\x20tex
SF:t/html;charset=utf-8\r\nContent-Length:\x200\r\n\r\n")%r(HTTPOptions,10
SF:8,"HTTP/1\.1\x20200\x20OK\r\nDate:\x20Thu,\x2020\x20Oct\x202022\x2004:1
SF:2:14\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node03dc6v9slx69a1dlrz9m5pweia
SF:1\.node0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu,\x2001\x20Jan\x2019
SF:70\x2000:00:00\x20GMT\r\nContent-Type:\x20text/html;charset=utf-8\r\nAl
SF:low:\x20GET,HEAD,POST,OPTIONS\r\nContent-Length:\x200\r\n\r\n")%r(RTSPR
SF:equest,AD,"HTTP/1\.1\x20505\x20Unknown\x20Version\r\nContent-Type:\x20t
SF:ext/html;charset=iso-8859-1\r\nContent-Length:\x2058\r\nConnection:\x20
SF:close\r\n\r\n<h1>Bad\x20Message\x20505</h1><pre>reason:\x20Unknown\x20V
SF:ersion</pre>")%r(FourOhFourRequest,F4,"HTTP/1\.1\x20401\x20Unauthorized
SF:\r\nDate:\x20Thu,\x2020\x20Oct\x202022\x2004:12:15\x20GMT\r\nSet-Cookie
SF::\x20JSESSIONID=node01sqwxjtfptte1ar3carw6raxd2\.node0;\x20Path=/;\x20H
SF:ttpOnly\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\n
SF:Content-Type:\x20text/html;charset=utf-8\r\nContent-Length:\x200\r\n\r\
SF:n")%r(Socks5,C3,"HTTP/1\.1\x20400\x20Illegal\x20character\x20CNTL=0x5\r
SF:\nContent-Type:\x20text/html;charset=iso-8859-1\r\nContent-Length:\x206
SF:9\r\nConnection:\x20close\r\n\r\n<h1>Bad\x20Message\x20400</h1><pre>rea
SF:son:\x20Illegal\x20character\x20CNTL=0x5</pre>")%r(Socks4,C3,"HTTP/1\.1
SF:\x20400\x20Illegal\x20character\x20CNTL=0x4\r\nContent-Type:\x20text/ht
SF:ml;charset=iso-8859-1\r\nContent-Length:\x2069\r\nConnection:\x20close\
SF:r\n\r\n<h1>Bad\x20Message\x20400</h1><pre>reason:\x20Illegal\x20charact
SF:er\x20CNTL=0x4</pre>")%r(RPCCheck,C7,"HTTP/1\.1\x20400\x20Illegal\x20ch
SF:aracter\x20OTEXT=0x80\r\nContent-Type:\x20text/html;charset=iso-8859-1\
SF:r\nContent-Length:\x2071\r\nConnection:\x20close\r\n\r\n<h1>Bad\x20Mess
SF:age\x20400</h1><pre>reason:\x20Illegal\x20character\x20OTEXT=0x80</pre>
SF:");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Open ports : 22,443,8080
| PORT | SERVICE | PRODUCT | VERSION | EXTRAINFO |
|---|---|---|---|---|
| 22 | ssh | OpenSSH | 8.2p1 Ubuntu 4ubuntu0.2 | Ubuntu Linux; protocol 2.0 |
| 443 | http | nginx | 1.18.0 | Ubuntu |
| 8080 | http-proxy |
Enum 443

Investigating the certificate we find the hostname info as seal.htb

Enum 8080

There is an option to create an account in Gitbucket.

Created an Gitbucket account sammy/Passw0rd

Discover tomcat creds
Upon exploring the gitbucket repository we found credentials for tomcat user in the tomcat-user.xml file.

gobuster discovery
gobuster has found few folder with a 302 status. It has found admin and server is redirecting to admin/. This redirection is happening either nginx or at tomcat.

nginx enum
The configuration file in nginx sites-enabled/default file points to few more urls /manager/html and /admin/dashboard

Trying to access /admin/dashboard is blocked by nginx

but when trying to access /admin we get an error from tomcat.

Looks like nginx is blocking the url before reaching tomcat. We need break the parser to reach the tomcat.
nginx - breaking parser logic Exploit
reference to Breaking parser logic - pdf

updating /admin/dashboard to /admin;name=orange/dashboard in request and we are able to successfully bypass nginx filter.

Not much information is on this url, lets check /manager/html

using the tomcat credentials found earlier we will attempt to login and we able to successfully login.

Now, we can generate a reverse shell war file and upload it.
Reverse shell

uploading the war file and catch the reverse shell.

got a 403 error. Let investigate with burpsuite. Most likely it could be the url parsing issue.

Inspecting the request in the burpsuite show that when deploy button is clicked. The request is sent to the default upload url as show below

Updating the request with /;name=orange logic, we are able to successfully upload the file and deploy.

Deployed shell

Accessing the reverse shell.

Privilege escalation
Downloading our monitoring script and executing the script for running processes


ansible exploitation
Looks like there a cron job running every minute. It is an ansible playbook executing rum.yml file.


Analyzing run.yml file, we identify that there is back files are created from the source file /var/lib/tomcat9/webapps/ROOT/admin/dashboard to the destination /opt/backups/files and also links in the source folder are copied. But critical loophole is, the symbolic links are copied as items into the archived file. We shell exploit this loophole by creating a symbolic link to ssh file of the luis user in the writable folder of source.
Symbolic file create
creating the symbolic the file to ssh file in the writable folder

the backup file in the archives folder

The cron job should create a backup file

Move the backup file and extract the backup file. This extracted folder should contain the ssh file.


ssh file for luis

Luis ssh

user flag
escalating to root
Exploiting the sudo privileges. luis has sudo privileges to execute ansible playbook.

Create playbook to return a reverse shell.

Execute the playbook

