Overview

I found this box on vulnhub when searching for some JWT practice for my Pentest+ studies. This was a simple box with just a single flag.

Recon and Enumeration

First I see what I’m dealing with with an nmap scan

┌──(astronuat㉿corvus)-[~/Machines/MoneyHeist]
└─$ sudo nmap -A 192.168.255.15 -oA MH_Aggressive

# Nmap 7.98 scan initiated Fri Jan 30 07:55:36 2026 as: /usr/lib/nmap/nmap -A -oA MH_Agressive 192.168.255.15
Nmap scan report for 192.168.255.15
Host is up (0.00024s latency).
Not shown: 995 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 8c:34:e2:5b:7f:7b:4c:63:6c:d8:03:e6:d3:3a:33:9a (RSA)
|   256 6e:34:78:f9:b5:c2:16:d6:29:dc:f5:cd:73:76:b5:25 (ECDSA)
|_  256 30:51:f3:eb:ea:0d:d8:f8:57:97:cd:e0:ea:a1:a4:cc (ED25519)
53/tcp   open  domain  ISC BIND 9.10.3-P4 (Ubuntu Linux)
| dns-nsid:
|_  bind.version: 9.10.3-P4-Ubuntu
80/tcp   open  http
|_http-title: MONEY HEIST
| fingerprint-strings:
|   FourOhFourRequest:
|     HTTP/1.1 404 Not Found
|     Content-Security-Policy: default-src 'self'
|     X-Content-Type-Options: nosniff
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 174
|     Date: Fri, 30 Jan 2026 12:55:42 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error</title>
|     </head>
|     <body>
|     <pre>Cannot GET /nice%20ports%2C/Tri%6Eity.txt%2ebak</pre>
|     </body>
|     </html>
|   GetRequest:
|     HTTP/1.1 200 OK
|     Accept-Ranges: bytes
|     Cache-Control: public, max-age=0
|     Last-Modified: Fri, 09 Oct 2020 08:29:01 GMT
|     ETag: W/"1f98-1750c7a44f5"
|     Content-Type: text/html; charset=UTF-8
|     Content-Length: 8088
|     Date: Fri, 30 Jan 2026 12:55:42 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html ng-app="money_heist_module">
|     <head>
|     <meta charset="UTF-8">
|     <meta name="viewport" content="width=device-width, initial-scale=1.0">
|     <title>MONEY HEIST</title>
|     <link rel="stylesheet" type="text/css" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
|     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"/>
|     <link rel="stylesheet" type="text/css" href="css/index.css">
|     </head>
|     <body ng-controller="money_heist_controller as money_heist">
|     <div class="container-fluid">
|     <nav class="navbar navbar-expand-l
|   HTTPOptions:
|     HTTP/1.1 404 Not Found
|     Content-Security-Policy: default-src 'self'
|     X-Content-Type-Options: nosniff
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 143
|     Date: Fri, 30 Jan 2026 12:55:42 GMT
|     Connection: close
|     <!DOCTYPE html>
|     <html lang="en">
|     <head>
|     <meta charset="utf-8">
|     <title>Error</title>
|     </head>
|     <body>
|     <pre>Cannot OPTIONS /</pre>
|     </body>
|_    </html>
3000/tcp open  http    Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
3001/tcp open  nessus?
| fingerprint-strings:
|   GetRequest:
|     HTTP/1.1 200 OK
|     Content-Type: text/html
|     Content-Encoding: gzip
|     Date: Fri, 30 Jan 2026 12:55:47 GMT
|     Connection: close
|     no~x
|     oiO_~
|_    ocQ>
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port80-TCP:V=7.98%I=7%D=1/30%Time=697CAA4E%P=x86_64-pc-linux-gnu%r(GetR
SF:equest,20A3,"HTTP/1\.1\x20200\x20OK\r\nAccept-Ranges:\x20bytes\r\nCache
SF:-Control:\x20public,\x20max-age=0\r\nLast-Modified:\x20Fri,\x2009\x20Oc
SF:t\x202020\x2008:29:01\x20GMT\r\nETag:\x20W/\"1f98-1750c7a44f5\"\r\nCont
SF:ent-Type:\x20text/html;\x20charset=UTF-8\r\nContent-Length:\x208088\r\n
SF:Date:\x20Fri,\x2030\x20Jan\x202026\x2012:55:42\x20GMT\r\nConnection:\x2
SF:0close\r\n\r\n<!DOCTYPE\x20html>\r\n<html\x20ng-app=\"money_heist_modul
SF:e\">\r\n\r\n<head>\r\n\x20\x20\x20\x20<meta\x20charset=\"UTF-8\">\r\n\x
SF:20\x20\x20\x20<meta\x20name=\"viewport\"\x20content=\"width=device-widt
SF:h,\x20initial-scale=1\.0\">\r\n\x20\x20\x20\x20<title>MONEY\x20HEIST</t
SF:itle>\r\n\r\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20type=\"text
SF:/css\"\x20href=\"node_modules/bootstrap/dist/css/bootstrap\.min\.css\">
SF:\r\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"https://cdnjs
SF:\.cloudflare\.com/ajax/libs/font-awesome/5\.14\.0/css/all\.min\.css\"/>
SF:\r\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20type=\"text/css\"\x2
SF:0href=\"css/index\.css\">\r\n</head>\r\n\r\n<body\x20ng-controller=\"mo
SF:ney_heist_controller\x20as\x20money_heist\">\r\n\r\n\x20\x20\x20\x20<di
SF:v\x20class=\"container-fluid\">\r\n\x20\x20\x20\x20\x20\x20\x20\x20<nav
SF:\x20class=\"navbar\x20navbar-expand-l")%r(HTTPOptions,16C,"HTTP/1\.1\x2
SF:0404\x20Not\x20Found\r\nContent-Security-Policy:\x20default-src\x20'sel
SF:f'\r\nX-Content-Type-Options:\x20nosniff\r\nContent-Type:\x20text/html;
SF:\x20charset=utf-8\r\nContent-Length:\x20143\r\nDate:\x20Fri,\x2030\x20J
SF:an\x202026\x2012:55:42\x20GMT\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\
SF:x20html>\n<html\x20lang=\"en\">\n<head>\n<meta\x20charset=\"utf-8\">\n<
SF:title>Error</title>\n</head>\n<body>\n<pre>Cannot\x20OPTIONS\x20/</pre>
SF:\n</body>\n</html>\n")%r(FourOhFourRequest,18B,"HTTP/1\.1\x20404\x20Not
SF:\x20Found\r\nContent-Security-Policy:\x20default-src\x20'self'\r\nX-Con
SF:tent-Type-Options:\x20nosniff\r\nContent-Type:\x20text/html;\x20charset
SF:=utf-8\r\nContent-Length:\x20174\r\nDate:\x20Fri,\x2030\x20Jan\x202026\
SF:x2012:55:42\x20GMT\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<
SF:html\x20lang=\"en\">\n<head>\n<meta\x20charset=\"utf-8\">\n<title>Error
SF:</title>\n</head>\n<body>\n<pre>Cannot\x20GET\x20/nice%20ports%2C/Tri%6
SF:Eity\.txt%2ebak</pre>\n</body>\n</html>\n");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port3001-TCP:V=7.98%I=7%D=1/30%Time=697CAA53%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,3890,"HTTP/1\.1\x20200\x20OK\r\nContent-Type:\x20text/html\r\n
SF:Content-Encoding:\x20gzip\r\nDate:\x20Fri,\x2030\x20Jan\x202026\x2012:5
SF:5:47\x20GMT\r\nConnection:\x20close\r\n\r\n\x1f\x8b\x08\0\0\0\0\0\0\x03
SF:\xdc\xbd\xdb\xb2%\xc7q%\xf8\xde_\xb1\x07\xcf\x9d\x89\x8c{\xa4\x8cP\xdb\
SF:xa8\$k\xb6\x198\xd3f\xec\xc6\xcc<B\x1b%\x9e\xb2\xde\x05pP\xe0\xa1X_\xdf
SF:\xeek-\x8f\xdc\x05\x16E\xf4\x8czL6\x12q\xce\xa9}\xc9\x8c\x8c\xf0\xf0\xc
SF:b\xf2\xe5\x1e\xbf\xfa_\xfe\xfe\x7f\x7f\xf3_\xfe\xaf\xff\xfc\x0f\xb7\x97
SF:\x9f\xde\?\xfe\xf6\xdf\xfd\*~\xbd\xfd\xf6\xbb\xbf\xfdw7\xfb\xbf_\xfd\xf
SF:4\xee\xa7\xc7\xdb\xbf\xfd\xbb\x1f\x7f\xf8\xe3\x87\xb7\?~\xf8\xd3\xf7\xf
SF:7_}\xc9\x97\xf8\xf6\xfb\xb7\?}{\xbb\xbf\|\xfb\xe3\x87\xb7\?}\xf5\xc5\x1
SF:f~\xfa\xa7m~q\xfb\xf2\xf9\xcd\x97\x9f~\xfa\xfd\xf6\xf6\xff\xfe\xc3\xbb\
SF:xd7\xaf\xbe\xf8\?\xb7\xff\xfa\xbfno~x\xff\xfbo\x7fz\xf7\x8f\x8f\xb7_\xd
SF:c\xee\?\|\xff\xd3\xdb\xef\xed\x9b\xff\xe9\x1f\xbez\xfb\xdd\xef\xde\xfe\
SF:xfb\xfb\xcb\x8f\?\xbc\x7f\xfbU\xfa\xd9E\xbe\xff\xd6\^\xfc\xe2\xbb\xb7\x
SF:1f\xee\?\xbe\xfb\xfdO\xef~\xf8\xfe\xe9\xab_\xfc\xf9\x07_\xdf\xbd\xfd\xe
SF:3\xef\x7f\xf8\xf1\xa7\xa7O\xfd\xf1\xddw\?\xbd\|\xf5\xdd\xdb\xd7w\xf7\xb
SF:7\x1b\xfe\xf1\xefo\xef\xbe\x7f\xf7\xd3\xbbo\x1f\xdb\x87\xfb\xb7\x0f\xbb
SF:\xe7~\xc4\xa5\x1e\xef\xbe\xffo\xb7\x1f\xdf>\xbe\xfa\xe2\xc3O\x7fz\xbc\x
SF:fd\xf0\xf2\xf6\xad\]\xeb\xe5\xc7\xb7\xff\xf4\xd5\x17\xf7\x0f\x1f\xbe\xb
SF:c\xff\xf0\xe3\xdb\xfd\xfd\xbb\xefw\xfb\xc7\x17_>\x7f\x89\x9f\xf9\xa7o\x
SF:ed6\?\|\xbf\xdb\x8f/t\x9d\x17\x1b\xce\xfd\x0f\?\xdd\xfc\xf5/n\?\xfd\xe9
SF:\xf76\xccw\xef\xbf\xfd\xdd\xdb/\xfdC6\xe7_r\xd2\x7f\xf5\x8f\?\|\xf7\xa7
SF:\xdb\xf7\xbf\xdb\xbe\xfd\xfd\xef\xbf\xfaB\xf3\xfe\[\x9bw\xfb\x0c\xef\xf
SF:3\x1f\xfe\xf9\xfd\xe3\xf6j\x8ba\xd3\xf0\xd5\x17>\xea\xdb\xdb\xef\xef\?\
SF:|\xf7\xee\xfb\xdf\xc5\n\xfc\x07\xbb\xceZ\xda\x0f\xaf\xbf\xbb\xfd\xe7\xf
SF:f\xfaw_\xff\xa77\xb7/\xb6/\xbf\xfc\?\xca\x9b/\xbf\xfc\xfb\xff\xf2\xf7\x
SF:b7\xdf~\xf3\x1foiO_~\xf9\x0f\xff\xdb\x17\xb7/\|\x99\xfe\xe6\xcb/\xff\xf
SF:8\xc7\?\xee\x7f,\xfb\x0f\?\xfe\xee\xcb\xff\xf8\xe3\xb7\xbf\x7fyw\xff\xf
SF:0\xa5}\xf0K\xff\xa0}\xe9K\xbbXJ\xfbw\?}\xe7C\xf6\+\xdb`\xbe\xff\xf0\xd5
SF:g\xbe\x9e\x8f\xe3\xf0\x8f\x7f\xc1\x8f\xfc\xcd\?\xfb\xfc\|\xee\x83\xe9<\
SF:xcf/\xf1\xee\x177L\xb7-\xf4\xbb\x0f\xbf\x7f\|\xfb\xa7\xbf\xb9}\xff\xc3\
SF:xf7ocQ>\xfc\xe9\xfd\?\xfe\xf0\xb8\xbd\xfb\xcef\xf3\xf5w\xdb\?\xbe\xb3y\
SF:xf4\x85\xfe\xbb\x1f\xfe\xf9\xab/\x8e\xdbq\xeb\xd5\xfe\x87O\xff\xca\x04\
SF:xec\xe5f\x1f\xfcM\+\xb7\xf3\xd7e~\xd3\xef\xc7\x96\xf6\xde\x86\xfd,\xb5l
SF:\xf8\xff\x97\xad\xdf\xf9\xea\xed\xd8\xcaM\xef\xdc\xcak\xf9uJ\x7f\xe1\x9
SF:d\x97:_\xb7\xf2\xb9\xab}\xfcMJ\xb76\xef\xc7\x8d_\xc4\[7\xfc\xffK\xe9w\]
SF:\xedV6\xbd\xb1\x95o\xd2\xb4\x1b\xbd\xd6\xe3\xe3\xfbb\xb7Iq\xd5\xeb~\[\x
SF:f9P\xae\x0b\xbd\xe6\x16W\xbf\.r\+\x1f\xb6r\x8d\xe3\x9b<>\xbe\xdfR\xbe");
MAC Address: BC:24:11:EB:A8:54 (Proxmox Server Solutions GmbH)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.10 - 4.11, Linux 3.13 - 4.4
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   0.24 ms 192.168.255.15

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Jan 30 07:56:02 2026 -- 1 IP address (1 host up) scanned in 26.42 seconds

Okay, I start with checking out the http site. I’ll do this in BurpSuite to get a site map I can look around too and anything else I want to do there. Here’s what I see on the landing page: Image Description

Let’s try just a test login and see if we get anything: Image Description Okay, I get the following error, so let me try registering: Image Description

Okay, registering shows me some info, but let me see if I can still login with the account I just made: Image Description

And I still get the same error in BurpSuite about needing to register. Let me take a look in the Target Site map in BurpSuite and see if I see anything interesting. I see a JWT here: Image Description And the response shows we don’t have the flag with our current access: Image Description Navigating to the browser I see I need to get admin: Image Description

I throw this in the JWT debugger and see what I get: Image Description I’m also going to throw this in John to try to crack the secret and get that pretty fast: Image Description Alright, let’s try re-encoding the JWT with this secret and see if we can get ourselves admin privs. After some playing around with some different JSON objects, I find the one that works: Image Description Image Description And looks like we got a message: Image Description Let’s try ssh with these creds: Image Description

And just like that, we’ve got the flag!