Jump Ahead: Enum – Getting a Foothold – User – Root – Resources
To solve this machine, we begin by enumerating open ports – finding ports
8080 open. From port
443, we find the backend webserver is
Apache Tomcat based on an error message. On port
8080, we find
GitBucket, and find a pair of credentials for Apache Tomcat. Due to protections of the frontend webserver, we are unable to use the credentials to log in. After some research, we are able to evade the frontend protections to gain access to Tomcat. From here, we are able to upload and get a reverse shell as
tomcat. After monitoring processes for scheduled jobs, we find the system uses an automation platform. After exploiting the automation platform, we are able to get the SSH private key of
luis, as well as read
user.txt. After minimal local enumeration as
luis, we learn we are able to exploit the automation platform again to get a shell as
root – thus granting access to
Like all machines, we begin by enumerating open ports using
nmap – finding ports
$ sudo nmap -v- --min-rate 3000 -p- $RHOST [...] $ sudo nmap -sV -A -p 22,443,8080 -oA enum/nmap/tcp-scripts $RHOST # Nmap 7.91 scan initiated Sun Jul 11 22:01:50 2021 as: nmap -sV -A -p 22,443,8080 -oA enum/nmap/tcp-scripts 10.129.182.60 Nmap scan report for 10.129.182.60 Host is up (0.047s 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 | fingerprint-strings: | FourOhFourRequest: | HTTP/1.1 401 Unauthorized | Date: Mon, 12 Jul 2021 03:02:03 GMT | Set-Cookie: JSESSIONID=node0v5t0xmmz1ocg15f3v0v24qozy3.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: Mon, 12 Jul 2021 03:02:02 GMT | Set-Cookie: JSESSIONID=node0ixdhunkvp0jhqhld08ztydqk1.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: Mon, 12 Jul 2021 03:02:02 GMT | Set-Cookie: JSESSIONID=node01r1jhx98vfzk71raz8i17rtk882.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> | 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 : SF-Port8080-TCP:V=7.91%I=7%D=7/11%Time=60EBB0AB%P=x86_64-pc-linux-gnu%r(Ge SF:tRequest,F3,"HTTP/1\.1\x20401\x20Unauthorized\r\nDate:\x20Mon,\x2012\x2 SF:0Jul\x202021\x2003:02:02\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node0ixdhu SF:nkvp0jhqhld08ztydqk1\.node0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu, SF:\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent-Type:\x20text/html; SF:charset=utf-8\r\nContent-Length:\x200\r\n\r\n")%r(HTTPOptions,109,"HTTP SF:/1\.1\x20200\x20OK\r\nDate:\x20Mon,\x2012\x20Jul\x202021\x2003:02:02\x2 SF:0GMT\r\nSet-Cookie:\x20JSESSIONID=node01r1jhx98vfzk71raz8i17rtk882\.nod SF:e0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x20 SF:00:00:00\x20GMT\r\nContent-Type:\x20text/html;charset=utf-8\r\nAllow:\x SF:20GET,HEAD,POST,OPTIONS\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequest SF:,AD,"HTTP/1\.1\x20505\x20Unknown\x20Version\r\nContent-Type:\x20text/ht SF:ml;charset=iso-8859-1\r\nContent-Length:\x2058\r\nConnection:\x20close\ SF:r\n\r\n<h1>Bad\x20Message\x20505</h1><pre>reason:\x20Unknown\x20Version SF:</pre>")%r(FourOhFourRequest,F4,"HTTP/1\.1\x20401\x20Unauthorized\r\nDa SF:te:\x20Mon,\x2012\x20Jul\x202021\x2003:02:03\x20GMT\r\nSet-Cookie:\x20J SF:SESSIONID=node0v5t0xmmz1ocg15f3v0v24qozy3\.node0;\x20Path=/;\x20HttpOnl SF:y\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nConten SF:t-Type:\x20text/html;charset=utf-8\r\nContent-Length:\x200\r\n\r\n")%r( SF:Socks5,C3,"HTTP/1\.1\x20400\x20Illegal\x20character\x20CNTL=0x5\r\nCont SF:ent-Type:\x20text/html;charset=iso-8859-1\r\nContent-Length:\x2069\r\nC SF:onnection:\x20close\r\n\r\n<h1>Bad\x20Message\x20400</h1><pre>reason:\x SF:20Illegal\x20character\x20CNTL=0x5</pre>")%r(Socks4,C3,"HTTP/1\.1\x2040 SF:0\x20Illegal\x20character\x20CNTL=0x4\r\nContent-Type:\x20text/html;cha SF:rset=iso-8859-1\r\nContent-Length:\x2069\r\nConnection:\x20close\r\n\r\ SF:n<h1>Bad\x20Message\x20400</h1><pre>reason:\x20Illegal\x20character\x20 SF:CNTL=0x4</pre>")%r(RPCCheck,C7,"HTTP/1\.1\x20400\x20Illegal\x20characte SF:r\x20OTEXT=0x80\r\nContent-Type:\x20text/html;charset=iso-8859-1\r\nCon SF:tent-Length:\x2071\r\nConnection:\x20close\r\n\r\n<h1>Bad\x20Message\x2 SF:0400</h1><pre>reason:\x20Illegal\x20character\x20OTEXT=0x80</pre>"); Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port Aggressive OS guesses: Linux 4.15 - 5.6 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 5.0 (93%) No exact OS matches for host (test conditions non-ideal). Network Distance: 2 hops Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel TRACEROUTE (using port 8080/tcp) HOP RTT ADDRESS 1 47.12 ms 10.10.14.1 2 47.18 ms 10.129.182.60 OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . # Nmap done at Sun Jul 11 22:02:23 2021 -- 1 IP address (1 host up) scanned in 32.42 seconds
nikto to enumerate the webserver on port
443, we find the TLS certificate is configured for the domain name
seal.htb (which we add to
/etc/hosts). Additionally, we see that
Nginx 1.18.0 is the platform used for the webserver.
$ nikto -h https://$RHOST [...] - Nikto v2.1.6/2.1.5 + Target Host: 10.129.182.60 + Target Port: 443 + GET The anti-clickjacking X-Frame-Options header is not present. + GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS + GET The site uses SSL and the Strict-Transport-Security HTTP header is not defined. + GET The site uses SSL and Expect-CT header is not present. + GET The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type + GET The Content-Encoding header is set to "deflate" this may mean that the server is vulnerable to the BREACH attack. + GET Hostname '10.129.182.60' does not match certificate's names: seal.htb + OPTIONS Allowed HTTP Methods: OPTIONS, GET, HEAD, POST + GET /manager/status: Default Tomcat Server Status interface found + GET The anti-clickjacking X-Frame-Options header is not present. + GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS + GET The site uses SSL and the Strict-Transport-Security HTTP header is not defined. + GET The site uses SSL and Expect-CT header is not present.
gobuster to enumerate the webserver, we find a few interesting directories, however, when we attempt to navigate to them, we are redirected to use cleartext http (port 80, which is not open). Going to
https://seal.htb in the browser, we are given the same index page as if we accessed the webserver via its IP. This indicates vHosts may not be implemented for the webserver.
While trying to enumerate the types of files in use by the webserver, we get an error page that reveals the webserver is actually
Apache Tomcat 9.0.31. This means that the directories we previously found were likely Tomcat related.
https://seal.htb/manager/manager reveals possible Tomcat endpoints.
When we attempt to use
BurpSuite to bruteforce the credentials, we are unsuccessful. Lastly, going to the webserver on port
8080 reveals it is running GitBucket. Unfortunately, we aren’t allowed to see anything unless we use a valid account.
Getting a Foothold
Having found GitBucket running on port
8080, we create an account so that we may see if there are any repositories that we may access. After logging in, we are presented with a couple repositories – “seal_market” and “infra”.
Looking around the “seal_market” repo, we learn a few things. From the
README.md file, we learn it may contain configuration files for the webserver on port
443, mutual authentication may be enabled for a few areas of the website, the deployed instance of Tomcat may not be up-to-date, and Tomcat manager and host-manager may be enabled.
Looking at the commit history, we see a commit titled “Adding Tomcat configuration”. Next, we select that commit to view the files it added/changed, and find potential Tomcat credentials in the
tomcat/tomcat-users.xml file. Looking at the roles, the user should have access to the manager and admin GUIs.
When we try to access the GUIs at
https://seal.htb/host-manager/html, we are prevented by Nginx. Looking at the Nginx configuration file, we see that mutual authentication is the reason we are being blocked from viewing the pages.
As we would need a valid user certificate to access the Tomcat GUIs, we will need to find a way to bypass this. To do this, we start by Googling “tomcat nginx reverse proxy vulnerability”. From this search, we find this BlackHat presentation by Orange Tsai. After reading through it, we learn that we can evade the Nginx mutual authentication check by supplying a ‘;’ and some text in the middle of the URL path. This works because Tomcat and Nginx parse URLs differently. Nginx treats the URL literally, whereas Tomcat treats the ‘;’ similarly to a comment.
When you add
;(ignored) to the URL path, we are able to evade Nginx, and get access to the Tomcat Manager.
As we’ve done in previous labs, we generate a malicious ‘.war’ file (reverse shell), and upload it to Tomcat.
In order to execute the reverse shell, we need to know the file name of the ‘.jsp’ file that contains the reverse shell. To find it, we use
unzip to list the contents of the ‘.war’ file, as it is basically a rebranded ZIP archive.
Lastly, we start a netcat listener to handle the connection back to us, and navigate to the ‘.jsp’ page. Once we have it open, we get a connection back as the
Now that we have a shell on the machine, we begin our initial enumerations. Looking around for credentials to the database GitBucket uses, we find the database credentials in
Next, we download the GitBucket database at
/home/luis/.gitbucket/data.mv.db to our local machine to enumerate it. Using
dbeaver, we are able to connect to the database, and find usernames and password hashes in the “Public.Account` table.
We attempt to crack the password hashes with
hashcat, however, we are unable to crack them in a reasonable time frame due to the hashing algorithm used. Next, we try to run
sudo -l to see if Tomcat can run any commands as other users, however, we need a password. Since these quick checks were unsuccessful, we switch to automated enumeration with
LinPEAS. Unfortunately, this does not yield any valuable results, so we upload and run
pspy to enumerate potential scheduled tasks. From this, we see that
ansible-playbook is being executed regularly.
Next, we look at the
run.yml file it executes, and learn it copies files in
/var/lib/tomcat9/webapps/ROOT/admin/dashboard (including symbolic links) to
/opt/backups/files/. Once files are copied, it creates an archive of them, and stores the archive in
/opt/backups/archives/. After the archive is made, it deletes the files in
Looking at the
/var/lib/tomcat9/webapps/ROOT/admin/dashboard directory, we see that it is owned by
root, however, the
uploads/ directory within it is world-writable. Due to this, we should be able to exploit the
ansible-playbook cronjob to extract the contents of a user’s directories. Since
ansible-playbook is being run as
luis, he will be our target user. Since ansible is configured to also copy symbolic links, we create a link to
luis‘s home directory and store it in the
Next, we wait about a minute for the archive to be created, then we copy it to another directory, and extract it.
Looking into the extracted contents, we do see
luis‘s home directory, and within it, we have access to read
We see the
.ssh/ directory is also present, so we are able to extract his private SSH key, and connect to the machine via SSH.
Having gained a shell on the machine as
luis, we begin our initial enumeration. One of the first commands we run is
sudo -l. From it, we see that we are able to run
GTFOBins, we see that we are able to exploit
ansible-playbook to get a shell as
root. Following the instructions, we get a shell as
root, and can now read
Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!