Seal is a medium linux box. It features a web service on port 443 running Apache Tomcat, and a GitBucket installation running locally, but accessible through the proxy on port 8080 (nginx). The GitBucket allows a user to create an account, which I did. Once inside, I recovered a password in a previous commit in one of the repositories. This credential was accepted by the tomcat admin login page, but access to the panel was blocked by nginx. This was bypassed thanks to a path normalization vulnerability, and the .war
upload used to deploy web applications in tomcat was used to gain code execution on the server.
Once inside, two different exploits targeting ansible-playbook
were used, first to move laterally, and second to gain code execution as root
.
Info
Recon
NMAP
# Nmap 7.70 scan initiated Sat Oct 9 15:30:06 2021 as: nmap -sV -sC -p22,443,8080 -oN nmap.txt 10.10.10.250
Nmap scan report for seal.htb (10.10.10.250)
Host is up (0.71s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
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
| fingerprint-strings:
---[snip]---
| 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).
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 :
---[snip]---
SF:);
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Oct 9 15:30:45 2021 -- 1 IP address (1 host up) scanned in 38.91 seconds
Web Service
The web page looks quite nice for a HTB box, and Wappalyzer detected about 11 web technologies. Going through the links showed that almost all of them are dead.
One thing I noticed is the lack of web service running on port 80, but a HTTPs service on port 443. The NMAP scan identified the web server as nginx 1.18.0, but the server was later identified as Apache Tomcat 9.0.31 during manual probing to determine if the server uses PHP;
The search field in the homepage generate the below GET request;
Continuous fuzzing of the Vegetable
parameter showed above made no difference on response received, indicating the web page might be static.
Bruteforcing with gobuster
failed, citing SSL certificate errors (I later found out that it need the -k
argument to disable TLS validation). ffuf
worked and discovered some interesting pages;
The page /dashboard/
looks promising, but all the links are dead;
The response code of 304, which is for unmodified contents and used for caching, indicate it’s probably just a static page;
Another page of interest is /admin
, which on request redirected me to http://seal.htb/admin/
, which failed because the NMAP scan earlier showed no service running on port 80. Since NMAP previously identified a web proxy on port 8080, I enabled this proxy in Firefox using the FoxyProxy plugin, and gained access to the page;
Guessing common username and passwords didn’t work. Using the create account link, I created an account with the username testuser
and password testpass
, and was able to login;
Using the repository search feature, I discovered a user named root
with 2 repos. Going through the repos of root
, I found another user named alex
;
The seal_market
repo owned by root is of interest as it’s contents match that of the web page at https://seal.htb/. It also contains the name of the box, and some administrative todo list in the README file;
Another user named luis
was also identified while going through this repo, bringing the count of discovered users to 3 (root, luis, and alex).
Going through the users homepages, the user root
has the highest entries in activity log. One commit stands out as it mentioned an update to Tomcat’s configuration file;
Viewing the commit log showed a credential;
Another commit in the seal_market
repo showed some config for the nginx
reverse proxy with the path /manager/html
. Request for /manager
forces redirect to /manager/html
, which showed a 403 Forbidden response;
A bit of googling on the variable $ssl_client_verify
showed it is used by nginx to store the result of an SSL certificate verification for the client. Since I am getting a 403, the above config indicate I may have failed the validation or something else. I am not sure. These are all very interesting info, but I have no clue how to exploit them.
GitBucket
Focusing more on the GitBucker users discovered, I noticed that alex
is the admin of the infra
repo, luis
is a core developer, and root
is well… root.
Earlier I found a credential for the user tomcat
while going through the activity log of the root
user. Testing the password against all the three users found, I gained access to the account of luis
;
No any private repo was found inside Luis’ homepage, and the last activity of the account was on 5 May, which make me believe I am going at it the wrong way.
Seal Market
While requests for https://seal.htb/dashboard/ succeeded, any other request to a path through Burp Suite gave me the error;
Without Burp Suite, request for https://seal.htb/admin/dashboard/ showed 403 Forbidden, while any other path showed the error;
Going back to the /manager/
path discovered earlier. I got this very informative error when requesting a random path;
Requesting the /manager/text
path gave me an authentication prompt;
The Tomcat Manager Application prompt made me remember the previous credential obtained from the GitBucket repository, which is tomcat:42MrHBf*z8{Z%
. I was able to login using the credential, but got the following message;
I imagined the above message is because I am accessing the page from a foreign host, so I tried to use the HTTP proxy on port 8080 to access the page, but it didn’t work.
I then started testing the HTTP proxy for HTTP request smuggling attacks, which is an attack I had to learn on the fly, and it didn’t work as the proxy blocks the use of both Content-Length and Transfer-Encoding headers in a single request, which the method I was trying depends on. Some bypass techniques that include adding a whitespace in front of the header name, and a tab in front of the header value, were also detected by the proxy, and blocked;
With that method down the drain, I started googling on how to bypass that 403 code. I tried quite a few of the methods, some of which were implemented in scripts hosted on Github, and none worked. I was running out of ideas at this point.
I went fully manual using Burp Suite and researching ways to bypass that 403, as I was quite confident this should work due to the presence of the reverse proxy. After lots of trials and errors, I found an article on Acunetix about a path normalization vulnerability when accessing Apache Tomcat using Nginx as a reverse proxy;
Using the path /manager/..;/manager/html
, which the nginx proxy let through as it does not match it’s rule for /manager/html
, and Apache Tomcat normalize to /manager/html
, I was able to bypass the 403 error and access the page. AT LAST!!!
Tomcat Manager
With access to the Tomcat Manager, I gained access to a .war file upload functionality;
Since .war files are used to package .jsp web apps, I found a webshell on Github, uploaded it, and deployed it on the server;
Going to https://seal.htb/webshell gave me a foothold into the box as the tomcat user, which I used to spawn a bash reverse shell back to my attack box;
User
With command execution inside the box as tomcat, it’s time to upgrade to a user account. A local user named luis
was found, and inside his home is the user flag which is not readable to us.
Moving through the filesystem to find something of interest, I found some directories inside /opt/backups
, which are playbook
and arhives
. The archives
contains some .gz
archives, while the playbook
contains a file named run.yml
;
1
2
3
4
5
6
7
8
9
10
11
12
- 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--.gz"
- name: Clean
file:
state: absent
path: /opt/backups/files/
Dumping a list of all running processes indicate the program ansible-playbook
is being executed by a cron job as luis
with the above .yml file as an argument, likely after every 30 seconds judging from the sleep 30
instruction;
After reading up a bit about ansible, the above .yml file begins to make sense; It is used to copy all files inside the directory defined in the src
parameter into dst
, including files pointed to by symbolic links (copy_links=yes
).
The upper/root part of source directory is not writeable to the tomcat user. Looking at the inner files, however, I noticed the uploads
folder is writable to everyone;
Since there is a .ssh
directory in the home of the user luis, it is likely this user has SSH public key authentication configured, so I moved into the writeable uploads directory and create a symlink to the SSH private key, which will be at /home/luis/.ssh/id_rsa
. This is possible because you don’t need any permission on a file before you can create a symlink to it;
I then monitor the /opt/backups/archives
for a new file to pop up, and one did. I immeditaley copied it /dev/shm/.0
and extract it. Inside the extracted uploads directory, I found the id_rsa
file containing the private key of luis;
I shipped the key file to my attack host using netcat
and gained access to the box over SSH as luis;
PrivEsc
Inside the host as luis, I have permission to run /usr/bin/ansible-playbook
with any argument as root using sudo
. Since this is a standard program, I look it up in https://gtfobins.github.io, and got a hit;
Using the above payload, I gained root on the box;
This is my fastest privilege escalation on HackTheBox at the time of writing this.
Summary
- Identified port 22, 443, and 8080 using
nmap
- Bruteforced the web service on port 443 for hidden paths, and found
/dashboard/
- Discovered
/admin/
web service on port 443, which redirect to http://seal.htb/admin/, which lead me to a GitBucket installation using the proxy on port 8080. - Inside GitBucket;
- Found 3 users: root, alex, and luis.
- Found a credential for tomcat user. Using the password, gained access to luis account on the GitBucket server.
- Used the tomcat credential for a web login at https://seal.htb/manager/text, which succeeded, but access was blocked by nginx reverse proxy.
- Expoited a path normalization vulnerability to gain access to
/manager/html
. - Used the
.war
file upload functionality to upload a webshell and gain foothold into the box as the usertomcat
. - Inside the box as
tomcat
;- Identified a cron job that uses
ansible-playbook
and a configuration file to copy files to a directory, resolving all symlinks in the process. - Exploited the copy operation to have
ansible-playbook
fetch a user’s SSH private key, which I used to gain access to the box over SSH as the user luis.
- Identified a cron job that uses
- Inside the box as
luis
;- Identified a sudo permission to run
ansible-playbook
with any argument as root. - Found a privilege escalation exploit on https://gtfobins.github.io, which gave me root access to the box.
- Identified a sudo permission to run