Secret is an easy machine on HackTheBox created by z9fr. For the user part we will find the source code of a webapp which reveals a command injection vulnerability. This command injection can only be performed as admin user but with the jwt key in the git history we are able to create our own token. After getting a shell we will abuse a suid binary in two different ways to obtain root’s ssh key.
User
Nmap
As usual we start our enumeration of with a nmap scan against all ports followed by a script and version detection scan to get an initial overview of the attack surface.
All ports
1 |
|
Script and version
1 |
|
JWT
Going over to port 80 in our web browser we see the documentation of “DUMBDocs”. Scrolling down the page we can also download the source code.
Scrolling down the page we can also download the source code.
Looking at the routes/private.js
we can identify a command injection vulnerability in the /logs
route. To access this feature we however need a valid jwt with the value of theadmin
for the name key.
routes/private.js
1 |
|
Looking at routes/verifytoken.js
we see that the secret is read from the enviroment.
routes/verifytoken.js
1 |
|
Checking the git history of the project there is an interesting commit stating removed .env for security reasons
.
1 |
|
Diffing this commit with the previous one we are able to obtain the jwt token secret.
1 |
|
We can now forge our own JWT’s. To do this we first obtain a valid one. Going over to the documentation we can check how to register a new user and perform the request using burp.
Afterwards we can refer to the docs again to log the user in and obtain a JWT.
The docs also show that we can use the Access Private Route functionality to test if we have admin access and a bit further up it is also show how the valid JWT is supposed to look.
We take the obtained JWT and paste it and the secret into jwt.io where we switch the username to theadmin
.
Testing our newly generated JWT against the /priv
route we see that we have obtained admin access.
Now we are able to abuse the command injection in the /logs
route. The page takes a files parameter and directly passes it to a system command. We can use ;
to make sure our command get’s executed and verify the RCE in burp.
Next we set up a ncat listener and send an url encoded reverse shell payload with burp.
1 |
|
We get a reverse shell back on our listener which we upgrade using python and are able to grab the user flag.
1 |
|
Root
Looking around there is a custom suid binary.
1 |
|
The same directory also seems to contain the source code of the binary.
code.c
1 |
|
Running /opt/count
it prints the same message as in the source so it seems highly likely that the binary got compiled from it.
1 |
|
The executable takes a filename as input reads the content of that file outputs a statistical summary and then asks if you want to safe the summary to disk. The interesting thing is the prctl(PR_SET_DUMPABLE, 1);
which enables us to access the process content.
Coredump
One way to go about this is to dump the process and then read the contents of the file from the dump. For this to work /proc/sys/fs/suid_dumpable
has to be set to 2 which it indeed is.
1 |
|
Looking at /proc/sys/kernel/core_pattern
we see that the dump wil get piped to /usr/share/apport/apport
for further processing.
1 |
|
With this knowledge we can now run the binary and check if root’s private ssh key exists. This is indeed the case meaning the key is now inside the processe’s memory. All that is left to do now is to send a signal to the process that triggers a core dump. One possible way here is SIGQUIT which can be sent with CTRL + \
.
1 |
|
To find the dump we look in the /var
directory for files that got created in the last minute, which returns /var/lib/apport/coredump/core._opt_count.1000.7541fd7b-4a83-42d7-a1f9-8aec0a5180dd.2214.795094
1 |
|
This core dump which is owned by us contains root’s ssh key.
1 |
|
.viminfo
The other option to obtain the ssh key was to read the .viminfo
file with /opt/count
and then cat the file descriptor. This was the originally intended method but it seems a bit more guessy to me, especially since with normal permission of a .viminfo
file(600
) we wouldn’t even be able to read the file descriptor. To perform the attack we run /opt/count
and specify /root/.viminfo
as the filename.
1 |
|
Now we grep for the process id and cat /fd/3
.
1 |
|
This also reveals the root users ssh key.
1 |
|
Now that we have root’s ssh key we just have to set the correct permissions on it, ssh into the machine and add the root flag to our collection.
1 |
|