Seal
Seal
Difficulty: Medium
Classification: Official
Synopsis
Seal is a medium difficulty Linux machine that features an admin dashboard protected by mutual
authentication. Enumeration of git logs from Gitbucket reveals tomcat manager credentials. Exploitation of
Nginx path normalization leads to mutual authentication bypass which allows tomcat manager access.
Foothold is obtained by deploying a shell on tomcat manager. An ansible playbook found to be running at
intervals and vulnerable to arbitrary file read thus allows us moving laterally. Root shell is gained by
exploiting a sudo entry.
Skills Required
Linux Enumeration
Understanding of Mutual Authentication
OWASP Top 10
Basic Knowledge of Ansible
Skills Learned
Gitbucket Enumeration
Nginx Path Normalization Exploitation
Mutual Authentication Bypass
Abusing Ansible Features
Enumeration
Nmap
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.250 | grep ^[0-9] | cut -d '/' -f 1 | tr
'\n' ',' | sed s/,$//)
nmap -p$ports -sV -sC 10.10.10.250
Nmap scan reveals there are 3 ports open. Let's browse to port 443.
Nginx
We see an e-commerce application running on Nginx server. Its all static content. Let's fuzz the server for
files and directories.
FFUF
ffuf -u https://10.10.10.250/FUZZ -w /usr/share/wordlists/dirb/common.txt
We see few directories which are found commonly on a Tomcat server.
admin
manager
host-manager
GitBucket
Browsing to port 8080 reveals GitBucket which is an open source Git web platform.
From installation we can see the default credentials are root / root . Trying these credentials fail. Let's
register an account and login to the platform.
We have read permission on two repositories. infra reveals ansible templates to configure tomcat.
This doesn't reveal anything. Let's browse to seal_market repository.
This repository has three folders and an open issue. README reveals some info about mutual
authentication .
It highlights that dashboard currently protected with Mutual Authentication . From google we learn what
it is.
Without providing a valid certificate we can't access the /admin/dashboard . Let's explore the repository.
location /manager/html {
if ($ssl_client_verify != SUCCESS) {
return 403;
}
...
location /admin/dashboard {
if ($ssl_client_verify != SUCCESS) {
return 403;
}
...
location /host-manager/html {
if ($ssl_client_verify != SUCCESS) {
return 403;
}
...
We see that /manager and /host-manager also require client authentication. Checking tomcat folder we
see there are 2 commits. One of them revealing tomcat manager credentials.
Foothold
It is also mentioned in the ToDo tasks that the latest tomcat configuration is yet to be deployed. Having this
information we can now look for ways with which we can bypass the client authentication and login to
tomcat manager interface with found credentials.
The most common misconfiguration of Nginx is path normalization which is well explained here. We can
apply below behaviour in this case.
This indeed worked. Login to tomcat manager interface sameway using tomcat / 42MrHBf*z8{Z%
credentials.
/manager;foo=bar/html
Having tomcat manager access, we can upload a war file and gain shell on the server. Generate a
shell.war file by issuing below command.
Upload and deploy the war file. Stand up a listener on port 1234 and access /shell
Browse the shell.war file and intercept the upload request on Burp Suite. Replace /manager/html with
/manager/test/..;/html in the URL.
Forwarding the request will deploy the shell.
It's worth upgrading to a TTY shell, which is more functional and allows us to switch to a different user if
needed.
python3 -c 'import pty;pty.spawn("/bin/bash")'
ctrl+z
stty raw -echo
fg
export TERM=xterm
Lateral Movement
Having foothold we can start exploring filesystem. /opt folder has backups directory. Let's check its
contents.
- hosts: localhost
tasks:
- name: Copy Files
synchronize: src=/https/www.scribd.com/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/
Copy symlinks as the item that they point to (the referent) is copied, rather than the
symlink.
We can abuse this feature if we've write privileges under dashboard folder. Let's check the permissions.
uploads folder is world writable. Checking /opt/backups/archives we see that every 2mins there's an
archive present and its created by luis .
cd /var/lib/tomcat9/webapps/ROOT/admin/dashboard
ln -s /home/luis/.ssh/id_rsa uploads/keys
We see that the archive now has different size. Let's copy it to /tmp folder and extracts the contents.
cd /tmp
tar -xzf backup.gz
cd dashboard/uploads
---
- name: "Root"
hosts: localhost
connection: local
tasks:
- debug: var=output.stdout_lines
We see the command id output root . To obtain root access we can modify root.yml as below.
---
- name: "Root"
hosts: localhost
connection: local
tasks:
- debug: var=output.stdout_lines
Running this playbook sets setuid to /bin/dash . We can now issue below command to get root shell.
This leads to arbitrary file read. Let's try to read contents of /etc/shadow file.
Using this method we can either try to crack the hash or read the root flag.