Secret - HackTheBox


Secret Machine(10.10.11.120)

Info:

This machine had pretty sweet learning curve for new comers, exploiting command injection to get foothold and core-dump abuse to get root on machine.

Secret

Recon:

Starting with portscan, we get 3 open ports.

PORT     STATE SERVICE REASON  VERSION
22/tcp   open  ssh     syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    syn-ack nginx 1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: DUMB Docs
3000/tcp open  http    syn-ack Node.js (Express middleware)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: DUMB Docs
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

on port 3000 node js application is running and port 80 has docs for same application. And there is source-code avialable for downlaod.

Screenshot from 2022-03-26 13-27-24

Docs shows how using API we can register new user and login it will then give JWT token for that user. there is theadmin user which is admin. Directory fuzzing  reveal already known paths only.

Screenshot from 2022-03-26 13-32-59

Foothold: Command Injection

Reading docs let's register a user by sending post requests to /api/user/register.

Screenshot from 2022-03-26 13-39-00

Login to get auth-token

Screenshot from 2022-03-26 13-39-54

A JWT token is set as our auth-token and using this we can make request to /api/priv

Screenshot from 2022-03-26 13-40-58

And it tells we are normal user. Let's decode our jwt token at jwt.io

Screenshot from 2022-03-26 13-41-54

Finding vulnerable route

Looking into source code we downloaded. There is an interesting function in /routes/private.js file


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);
        })
    }

The endpoint /api/logs is vulnerable to command injection as user input file is directly passed into exec command. But for that we have to somehow become theadmin user. But we don't have any secret to forge JWT token. One i tried using was secret=secret as listed in .env file but that didn't work.

Finding .git folder

Let's examine downloaded source-code once again.

Screenshot from 2022-03-26 14-22-52

There is folder .git which we didn't notice earlier. Let's change directory and see what it offers.

using git log command we can list all the commits that happened.

Screenshot from 2022-03-26 14-26-18

second commit is interesting as it says removed .env where our secret is stored let's look into that using git show <commit_id>.

Screenshot from 2022-03-26 14-28-28

As it shows, older JWT secret is replaced with secret. Let's use this to sign our new auth-token and get admin.

gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE

As code only checks username from jwt token, we just have to change that to theadmin and give it secret obtained.

2022-03-26_14-34

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MjNlYzk2NGFiN2I1YzA0NTkxOGJkOTIiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJpYXQiOjE2NDgyODE5ODB9.fjQzAdpsLN1B7_0gnLv_hWN_E2LAG7KuIMdJhjkm0vM

Let's put this new JWT into request and verify.

Screenshot from 2022-03-26 14-35-27

Command injection:

Screenshot from 2022-03-26 14-37-12

As it requires a file name to show git logs. Let's do that

Screenshot from 2022-03-26 14-38-34

As shown our input "ip" is concatenated in command. Let's get code execution with "ip;id"

Screenshot from 2022-03-26 14-39-48

Let's get shell from here

Screenshot from 2022-03-26 14-43-51

Screenshot from 2022-03-26 14-43-33

Privilege escalation: Abuse Core-Dump to read files

In /opt there is a suid binary count which counts number of lines, characters, words in a file. Being suid binary it can also read privileged files. we just have to find a way to extract what it reads from memory. If you try to run suid binaries with some external tool like gdb, suid privilege will drop.

There is also code.c file given for the binary. One important thing i noticed was this

Screenshot from 2022-03-26 15-48-23

PR_SET_DUMPABLE will decide whether to generate core-dump when crashing. And this crash can also contain sensitive info. Google core dump privilege escalation gave this blog.

Which states that which type of process kill signals will generate core_dump.

Screenshot from 2022-03-26 15-51-05

Get another shell in another pane to kill the process after reading the sensitive file.

Dumping core:

Run the binary from one pane

Screenshot from 2022-03-26 15-54-15

Now kill this process from another pane, this blog has detailed explanation on how to send kill signals.

using SIGBUS signal we kill the process , killall -s SIGBUS count.

Screenshot from 2022-03-26 15-56-31

and it kills the process in another pane & generates the core dump in /var/crash

Screenshot from 2022-03-26 15-57-31

Screenshot from 2022-03-26 15-58-33

Now this .crash file has all the information we need but we can't just read it from here, as i tried decoding base64 value in it. it doesn't work.

Little bit of google gave this, using apport-unpack, which is luckily installed on system, we can generate useful Human redable information.

apport-unpack _opt_count.1000.crash crash will generate crash directory with all information.

Screenshot from 2022-03-26 16-02-10

and in CoreDump file we can see the contents of file we read.

Screenshot from 2022-03-26 16-03-18

To get shell let's read root's ssh keys. or  crack the password obtained from /etc/shadow or directly read root flag,totally your choice.

Let's again create the core-dump after reading /root/.ssh/id_rsa & read the CoreDump content.

Screenshot from 2022-03-26 16-06-15

and using this key we can login as root.

ssh -i id_rsa root@10.10.11.120

Screenshot from 2022-03-26 16-09-52

That's how we get root on this machine and don't forget to remove your scripts and crash dump from machine before leaving.

Thank you for reading.

Twitter: Avinashkroy

Comments

Popular posts from this blog

Epsilon - HackTheBox

Pandora - HackTheBox

Driver - HackTheBox