we can see we have three ports open: 22, 80, 3000.
It seems like the webserver runs from a node js application. But also, it seems like ports 80 and 3000 are running the same header.
Since port 80 runs HTTP, we must have a webpage. i looked at it and we were prompted with this page.
nothing seemed interesting apart from the download button at the bottom.
We also get the same result with port 3000
We can do a further enumeration with gobuster to scan for available directories
As we can see we have four main endpoints. I tried to look into them. The download path seemed not to be working. I had to go back to the home page at port 3000 and look at the download button.
clicking on it, we download a zip file.
After unziping it, we find it contains a folder with the sites source code
The next move is to inspect each and all of these source codes.
I happened to notice this one file at routes/verifytoken.js
this was after almost losing hope. I noticed that it seems to look at a JSON web token algorithm (JWT) which is not specified. This shows a possibility of modifying it and using a none algorithm to bypass validation.
I also inspected the /routes/auth.js
and i noticed there is a user registration endpoint. It seemed to be using POST requests and the GET requests were not allowed.
I decided to test it with curl and see if iit was valid. Here](https://gist.github.com/subfuzion/08c5d85437d5d4f00e58)
So lets look around and see what is expected of us to register a new user since we now know that we have an active register endpoint.
Looking back to the validation.js
we see that we have to provide a name, email,password to register a user.
Also if we can remember, in the website on the API documentation, we had a register user module
With all this info in place, we can come up with an attack plan that will enable us to get an RCE to the machine.
our attack plan will be:
/api/priv
route, which when we try accessing, we get Access denied
Looking at the documentation under the user registration, we can see that the user email must contain @dasith.works
to be valid.
we can see that we have successfuly created a user testuser
. Now its time to login and try locate our JWT validation and modify it.
Now as you can see, we are successfully logged in. So let us take our jwt and try decoding it using jwt.io.
So I decided to use the none
alg technique. I tried with none
, NONE
and None
but they didn't seem to work.
With this technique failing, I had to think of another way. After a long time of research, I figured out that there were two hidden files in the download folder .env
and .git
. It just came to my mind that there must be something interesting there since even the challenge name is secret
.
I started with the .git
by looking at the history by running git log
command.
I realized an interesting commit message:
removed .env for security reasons
So I was interested to know what was happening. I went back to the working try and decided to view information of this commit git diff HEAD~2
I tried using this by going back to jwt.io and changing the username to theadmin
and testing the generated JWT against /api/priv
endpoint, to verify if the bypass worked.
Yeet it worked.
Now with access to the admin page, we can use it to look at the /api/logs
endpoint and gain access to the server.
We can chain several bash commands like id
to know the user running the application, /etc/passwd
in order to obtain the user passwords and file
in order curl to accept Get parameter. So the URL will look like this : 10.10.11.120/api/logs?file=index.js;id;cat+ /etc/ passwd
This was successful since it dumped all the info we wanted. Now it's time to utilize port 22 and ssh to the machine.
We can generate a new ssh key which we will use to login into the machine and avoid using our main ssh key.
ssh-keygen -t rsa -b 4096 -C 'drt@htb' -f secret.htb -P ''
As we can see, in my case I had another key that I have overwritten. This was created when I first tried solving this machine.
The command generates a new SSH public and private key in the current directory named secret.htb.
To ensure that the public key is added, we can use these commands in a root shell.
mkdir -p /home/dasith/.ssh
echo $PUBLIC_KEY >> /home/dasith/.ssh/authorized_keys
Now we can store the content of our public key in a variable for easy adding.
export PUBLIC_KEY=$(cat secret.htb.pub)
So now we can execute our last curl command to add our keys to the server for easy SSH.
We received a 200 OK, meaning it worked. Yaay
Now we can SSH to the machine and get that user hash
Now it's time to root this machine.
Trying linpeas and linEnum, they failed, so i tried exploiting SUID binaries find / -type f -perm -u=s 2>/dev/null
.
We find this interesting file /opt/count
. looking at the dir, we find that we are also provided with a source code.
Looking at the binary with some dynamic analysis, we see that when run, it asks for a directory name and displays the content in it. So I provided it with /root/root.txt as shown below
I decide to crash the program and try to read the crash file which most of the time is saved in /var/crash in Linux distro. May it will display the content of the file in /root/root.txt.Reference here. Let's GO!!!
It's now time we look at the /var/crash dir and see what we got.
we use the apport-unpack
command to unpack and dump the content of the crash file in the /tmp/crash-report directory.
We can use strings to see the contents in CoreDump where we believe that our root hash is. Taking a close look, we find our root hash in the strings results. I'll exclude it in the screenshot.
we submit the hash and
yaay!!!