Luke — Hackthebox Writeup
Nmap shows us that there’s an FTP service running with anonymous login allowed, good place to start! Only one folder “webapp” is visible, with a text file containing a message from Derry to Chihiro.
It doesn’t tell me much, but I note down two possible usernames “Chihiro” and “Derry” and that I’ll probably find some website source files during enumeration.
I notice that if I click “Up to a higher level directory” in my browser, a “../” is added on the end of the FTP filepath. Unfortunately, I’m not able to do any directory traversal though.
I move on to the website running on port 80. It’s very basic and I can’t find anything in the page source. If I need to diff any of the stock javascript (jquery, bootstrap, jquery.easing, scrolling-nav), I will later.
At the very least, I find the email address “contact@luke.io”. Luke goes in to my list of usernames, and the domain luke.io is recorded as well (I’ve already got 10.10.10.137 in my hosts file as luke.htb).
Nmap implies that it isn’t sure what service is running on port 22. I try to log ssh in to root@luke.htb and am asked for a password, so it at least looks like an SSH server. I don’t have a password so I move on.
I set gobuster loose on port 80 and quickly check out port 8000.
What is Ajenti?
Ajenti is a Linux & BSD web admin panel.
I don’t have any credentials yet and searchsploit doesn’t have much for Ajenti, so I move on to port 3000 which is running Node.js Express.
The headers don’t contain any information that catches my eye. I don’t know anything about Node.js Express so I guess that this will be my heavy reading subject for this machine.
Gobuster finishes with port 80, yielding quite a lot of good pages:
/index.html (Status: 200)
/login.php (Status: 200)
/member (Status: 301)
/management (Status: 401)
/css (Status: 301)
/js (Status: 301)
/vendor (Status: 301)
/config.php (Status: 200)
So I have two more login pages at login.php and management/, some db credentials at config.php, and a few directories containing css/js.
I try the password on all three login pages and SSH, using Derry/Chihiro/root/admin etc, but don’t have any luck.
I notice that when I visit login.php, my browser sends another GET request to /js/bootstrap.min.js which fails as the file doesn’t exist. I don’t know what to do with this (the script is located at http://luke.htb/vendor/bootstrap/js/bootstrap.min.js), but note it down and return to port 3000.
The message says “Auth token is not supplied”. I need to figure out how to generate one. I run gobuster on this port as well while I read a very helpful guide about JWT.
https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
The results are:
/login (Status: 200)
/users (Status: 200)
/Login (Status: 200)
/Users (Status: 200)
/LogIn (Status: 200)
/LOGIN (Status: 200)
This matches what I’m reading, the authentication page that I need to send a POST request with credentials to is ‘login’, and if I can authenticate myself, I can find a list of users by making a GET request to ‘users’.
Unfortunately gobuster doesn’t find any authentication forms, so I’m not sure about the format of the POST request. I find another article that tells me everything I need to know.
https://medium.com/@nieldw/using-curl-to-authenticate-with-jwt-bearer-tokens-55b7fac506bd
I try using the credentials from config.php with the example provided in the medium article above, but receive the response “forbidden”. I try authenticating as Derry, Chihiro, Luke, and eventually admin works.
Just in case it seems like I got the token too quickly, I spent about an hour trying different credentials, syntax, headers, data, and forgetting to specify port 3000.
I use https://jwt.io to examine the token’s claims.
Cool! Continuing on with the medium article, I present my token and request the information on the ‘users’ page:
curl -H ‘Accept: application/json’ -H “Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYxNTI2MzE0LCJleHAiOjE1NjE2MTI3MTR9.9LjptgwXC4OEESC9FqEsfIMkQcDOKX-MwyxY69nCza4” http://luke.htb:3000/users
{“ID”:”1",”name”:”Admin”,”Role”:”Superuser”},{“ID”:”2",”name”:”Derry”,”Role”:”Web Admin”},{“ID”:”3",”name”:”Yuri”,”Role”:”Beta Tester”},{“ID”:”4",”name”:”Dory”,”Role”:”Supporter”}
My username list now consists of:
Derry
Chihiro
Yuri
Dory
I try logging in to all three login pages using each username and the root password, but don’t gain access. I keep poking at the Node.js Express server and find out that the ‘users’ directory is a directory. I’m able to get passwords for each user since I’ve got an admin token.
{“name”:”Admin”,”password”:”WX5b7)>/rp$U)FW”}{“name”:”Derry”,”password”:”rZ86wwLvx7jUxtch”}{“name”:”Yuri”,”password”:”bet@tester87"}{“name”:”Dory”,”password”:”5y:!xa=ybfe)/QD”}
The first thing I do is try to log in to ‘login.php’ with Yuri’s credentials, since the page says it’s a beta version, and Yuri’s a beta tester. Nope.
On a similar vein, I try to log in to Ajenti, the web server software, with Derry’s credentials, since he’s a web admin, but that doesn’t work either.
After much trial and error, I log in to the /management page as Derry using the credentials we just got.
config.json has what I want.
The ‘root’ user has a password in plain text. I use this to log in to Ajenti.
I haven’t used Ajenti before but “Terminal” seems like a good place to start. I start a terminal session and get the root flag, finishing the machine.
Wait a minute, we don’t even have the user flag yet. So I just go over and get that too.
It’s very strange that there was no privesc, and I could do everything I needed through Ajenti’s terminal. I guess it’s a lesson about the dangers of giving an application root access?
This machine was pretty easy, and would have been a good opportunity for first blood to be scored on the root flag before the user flag…
Here are my takeaways:
- When I’m out of ideas, enumerate some more. I haven’t needed to run gobuster more than once on each port/directory before. I had to vary my wordlists, extensions, AND errors.
Honestly, directory busting isn’t fun for me. So I learned from this machine to do it anyway, and do it well. - HTTP 401 errors are ignored by default by gobuster. I think I’ll include 401 in the future, because not being authenticated to access a page doesn’t mean I don’t want to know about it.
- I want to work on some harder machines. I’m kind of sick of admins leaving credentials laying around. I get that it happens, and that negligence will always open a door to a system, but everything I’ve done so far has involved something like that.
- How JWT works, its strengths and weaknesses, and that I can throw something like jeanphorn’s username wordlist at the ‘users’ directory (if I can find it).