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
ExecASLR-ekoparty — Prova de conceito de exploit que contorna a ASLR em CPUs Intel ao abusar do branch target buffer e da execução especulativa para vazar endereços randomizados via canal lateral. | Kitploit
Ferramentas/GitHubGitHub/es0j/execaslr-ekoparty
Análise de VulnerabilidadesExploraçãoSegurança de HardwareAprendizado e EducaçãoRed TeamingAtaque AdversárioExploração de Binários
GitHubes0j/execaslr-ekoparty

ExecASLR-ekoparty

Prova de conceito de exploit que contorna a ASLR em CPUs Intel ao abusar do branch target buffer e da execução especulativa para vazar endereços randomizados via canal lateral.

Ver Repositório
729há 3 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

ExecASLR - Abusando de preditores de desvio da Intel para contornar o ASLR

O que é ASLR

A Randomização do Layout do Espaço de Endereçamento é uma mitigação usada para dificultar ataques de corrupção de memória. Em um cenário de vulnerabilidade de buffer overflow, por exemplo, um atacante que tenta fazer um exploit de Return Oriented Programming precisa conhecer os endereços dos gadgets na cadeia. Se o segmento de código do binário explorado é randomizado, então é muito mais difícil para um atacante escolher o endereço correto para o exploit, tornando a exploração inviável.

O exemplo a seguir mostra como um endereço é randomizado:

root@kitploit:~
#include <stdio.h>
void DoNothing();
void (*codePtr)() = DoNothing;

void DoNothing(){}

int main(int argc,char **argv){

    printf("Destination %p\n",codePtr);
    DoNothing();
}


Cada execução o valor é randomizado:

root@kitploit:~
Destination 0x563714256149
Destination 0x556d8e2f1149
Destination 0x5618c8bdd149
Destination 0x55ee623b0149

Os últimos 12 bits 149 são sempre os mesmos, mas a localização da função pode estar aproximadamente em qualquer lugar entre 0x550000000000 e 0x570000000000, o que significa que 29 bits são randomizados, ocupando um espaço de endereçamento possível de 0x200 0000 0000 ou 2,2 TB de tamanho.

Pipeline da CPU

O processamento de cada instrução é uma tarefa árdua. Algumas etapas do processamento de uma única instrução são:

  • Buscar a instrução;
  • decodificar a instrução;
  • Executar operações na Unidade Lógica Aritmética

Para aumentar a vazão de instruções na CPU, cada tarefa da instrução é executada por uma unidade específica do processador. Com todas as unidades trabalhando em paralelo, isso permite que a CPU execute em velocidades de clock muito mais altas; essa é a ideia de um pipeline.

Execução das instruções A, B e C ao longo dos ciclos 1-5. No ciclo 3, por exemplo, as unidades de leitura, decodificação e execução estão simultaneamente ativas

No entanto, as instruções não são completamente independentes umas das outras. Por exemplo, a seguinte sequência:

root@kitploit:~
A. add ax,[bx]
B. jz $+1
C. mov dl,[rsi]  
D. nop

Neste caso, a instrução A no melhor caso só terminará no ciclo 3, na execução. No entanto, a unidade de busca precisa decidir qual é a próxima instrução a ser buscada da memória, se a instrução C (mov dl,[rsi]) deve ser ignorada. Nesse cenário, a CPU tem a opção de esperar a instrução A terminar, o que só acontecerá no terceiro ciclo de clock, para então buscar a instrução correta na memória, se a operação de adição retornar 0, por exemplo:

Isso implica em um atraso no pipeline porque a CPU deve esperar a instrução ser executada. Neste exemplo o atraso é um único ciclo de clock, mas a instrução add ax,[bx] requer uma operação de memória, que, como visto antes, pode levar centenas de ciclos para ser concluída, gerando assim um custo de desempenho significativo no processador.

Uma opção mais rápida seria tentar "adivinhar" o caminho de execução correto. A CPU pode especular se o desvio é tomado ou não. Após esse ponto, a execução continua a partir do caminho especulado e os valores só são confirmados se o caminho for comprovado correto após o término da instrução A. Se o caminho for comprovado errado, os resultados são descartados e o estado é revertido para antes do ponto especulado.

O único problema em reverter o caminho tomado é que o estado microarquitetural da CPU não pode ser revertido. Então, se a CPU especular executar a instrução C (mov dl,[rsi]), o dado apontado por rsi será movido para o cache. Esse efeito pode ser medido posteriormente usando um ataque de canal lateral.

Preditor condicional de 2 bits. https://en.wikipedia.org/wiki/Branch_predictor

Spectre V2 (Injeção de Alvo de Desvio)

Não apenas instruções condicionais devem ser previstas, mas também desvios indiretos. A CPU deve ter um mecanismo para adivinhar os destinos de uma instrução como call [rdi].

A vulnerabilidade Spectre V2 mostra que é possível explorar o preditor indireto para alcançar execução transiente em outros processos: Extraído de https://spectreattack.com/spectre.pdf

Ao colocar uma instrução de chamada no contexto A no mesmo endereço virtual de outra chamada no contexto B, o atacante pode treinar a CPU para executar código em uma posição escolhida pelo atacante no contexto B, em um ataque de reutilização de código, semelhante ao Return Oriented Programming (ROP).

A vítima alvo deve ter um trecho de código conhecido como "spectre gadget" que seja capaz de vazar um segredo usando um ataque de canal lateral. Para um ataque Spectre bem-sucedido, o atacante também deve saber a localização do spectre gadget. Portanto, em ataques usuário-usuário, proteger a vítima com ASLR costumava ser uma mitigação para esse tipo de ataque. No entanto, também existem técnicas para extrair ASLR usando ataques microarquiteturais, como o Jump Over ASLR. Contudo, essa técnica tem algumas limitações sobre a quantidade de bits vazados, pois depende de colisão no preditor direto para contornar o ASLR.

Os mecanismos internos desse preditor são mostrados abaixo:

Extraído de https://spectreattack.com/spectre.pdf

Alguns desses componentes são:

  • O Branch Target Buffer (BTB);
    • O BTB é um componente semelhante a um cache que armazena os destinos para as previsões. O BTB armazena o endereço completo de 64 bits do destino e o número de entradas disponíveis no BTB depende da arquitetura.
  • O Branch History Buffer (BHB);
    • O BHB armazena um "hash" do fluxo de execução recente. Cada instrução de desvio escreve no BHB. Em CPUs Skylake e anteriores, o BHB pode armazenar o contexto dos últimos 29 desvios. No Icelake, o BHB armazena até ~100 desvios. Observe que o BHB usa apenas os 20 bits menos significativos dos desvios para criar o hash, dos quais 12 não são randomizados.
  • O preditor indireto;
    • Usa apenas os 12 bits menos significativos da instrução de desvio indireto para determinar o destino completo de 64 bits. O Exec ASLR vaza o ponteiro de 64 bits do BTB para recuperar completamente os endereços do ASLR.
  • O preditor de desvio direto
    • Usa os 30 bits menos significativos do endereço de origem para prever um valor de 32 bits. A outra metade do endereço é reutilizada da origem. O ataque Jump Over ASLR explora colisões nesse preditor para encontrar um endereço de origem que colida com outro contexto, portanto é limitado a vazar apenas os 30 bits menos significativos do contexto da vítima.

O layout clássico do ataque Spectre V2 se parece com isto:

  • O atacante coloca um desvio indireto na mesma posição do desvio da vítima, mas o destino corresponde a um spectre gadget no contexto da vítima
  • Quando a vítima executa o desvio, ele prevê erroneamente e o spectre gadget carrega um segredo e faz um acesso condicional a uma região de memória compartilhada, como uma biblioteca. Por exemplo, o spectre gadget que executa getenv + secret[0]*4096 pode vazar o valor do segredo na posição 0 usando a libc como memória compartilhada.
  • O atacante então recupera o segredo vazado detectando quais partes da memória compartilhada foram movidas para o cache usando um ataque de flush+reload

Exec ASLR

Exec ASLR (também conhecido como Reverse Branch Target Buffer Poisoning) é uma nova técnica para contornar o ASLR usando a vulnerabilidade Spectre-BTI. Esse ataque abusa do fato de que não apenas o atacante pode poluir o BTB em um cenário clássico de Spectre-BTI, mas as vítimas também podem disparar uma previsão errônea de desvio no processo do atacante, levando o atacante a um salto especulativo para um endereço protegido por ASLR. Então, usando um canal lateral que vaza qual endereço está sendo executado, um atacante pode recuperar o endereço de destino completo, contornando o ASLR para o processo alvo.

O layout do ataque Exec ASLR se parece com isto:

  • A vítima executa um desvio indireto, que escreve seu ponteiro de destino randomizado (0x55aabbeef456) no BTB
  • O atacante coloca um desvio indireto em um endereço alinhado aos 12 bits menos significativos. Como os 12 bits menos significativos não são randomizados, essa parte é trivial.
  • O atacante preenche todas as posições possíveis da memória com um "leak gadget" que diz ao atacante "Estou executando neste endereço!" usando probeArray como canal lateral.
  • Quando o atacante executa o desvio indireto, ele prevê erroneamente para um dos muitos leak gadgets na memória
  • O atacante usa um ataque de flush+reload para recuperar se o ProbeArray foi acessado ou não ao especular.

Nesse tipo de ataque, não há necessidade de encontrar um spectre gadget nem de ter uma memória compartilhada para o canal lateral; o único requisito é um desvio indireto a ser explorado, todos os gadgets necessários de um Spectre V2 estão dentro do processo do atacante. O único novo requisito para esse ataque é ser capaz de mapear o endereço de destino da vítima em seu próprio processo; portanto, esse ataque não funciona contra KASLR, por exemplo. Este também não é um ataque de força bruta; com uma única tentativa é possível testar vários endereços ao mesmo tempo, no entanto, há um limite de quantos "leak gadgets" a memória pode conter ao mesmo tempo. Isso diminui significativamente o tempo para realizar o ataque em comparação com o Jump Over ASLR, de ~100 endereços por segundo para algumas centenas de bilhões de endereços por segundo.

Leak gadget

O leak gadget usa probeArray para informar ao atacante onde o próprio gadget é executado. Ele recebe probeArray e o índice do RIP a ser vazado como argumento e executa uma espécie de programação sem desvios para decidir se probeArray[0] ou probeArray[4096] deve ser acessado.

root@kitploit:~
lea rax,[rip - 7]      ;load current address
shr rax,cl             ;selects the bit using cl arg
and rax,1
shl rax,12             ;loads probearray
mov dl,[rsi+rax]       ;or probearray+4096

Controlando o BHB e o código da vítima alvo

Como visto antes, o BHB é usado para selecionar uma entrada do BTB. Para encontrar uma colisão no BTB e explorar essa vulnerabilidade, um atacante deve conhecer os últimos N (29 se <skylake) desvios executados. Em nossos testes, usamos um loop for para definir o estado do BHB para um valor conhecido antes da chamada indireta. Aqui está um exemplo vulnerável de código da vítima:

root@kitploit:~
#include <stdio.h>

void DoNothing();
void (*codePtr)() = DoNothing;

void DoNothing(){
    return;
}

int main(){
    printf("Destination = %p\n",codePtr);
    while(1){
	for(int i=0;i<200;i++){}
    	codePtr();
    }
}

Para garantir que o estado do BHB seja o mesmo em ambos os contextos, o atacante copia os bytes correspondentes ao loop for e à chamada da vítima em forma de shellcode. O shellcode é copiado para todas as 256 posições possíveis que podem corresponder ao alinhamento de 20 bits menos significativos necessário para que o estado do BHB seja o mesmo.

root@kitploit:~
Victim Code

0x5594c566a152 <+28>:    mov    eax,0xc8
0x5594c566a157 <+33>:    dec    eax
0x5594c566a159 <+35>:    jne    0x1157 <main+33>
0x5594c566a15b <+37>:    nop
0x5594c566a15c <+38>:    nop
0x5594c566a15d <+39>:    nop
0x5594c566a15e <+40>:    lea    rdi,[rip+0x2ecb]
0x5594c566a165 <+47>:    call   QWORD PTR [rdi]

--> Executes to
0x5594c5669135:    ret

root@kitploit:~
Attacker Code

… //eax=200 rsi=probeArray, cl=0 
0x6a157    dec    eax
0x6a159    jne    0x455555500157
…
0x6a165    jmp    QWORD PTR [rdi]

--> Misspredicts to
0x5594c566a135:    lea rax,[rip - 7]
0x5594c566a13c:    shr rax,cl
0x5594c566a13f:    and rax,1
0x5594c566a133:    shl rax,12
0x5594c566a137:    mov dl,[rsi+rax]

Desafios

Há um problema ao tentar colocar um gadget em todas as posições possíveis ao mesmo tempo. Em nossos testes, o ASLR coloca o destino em algum lugar entre 0x550000000000 e 0x570000000000. Isso significa que há 2,2 TB de endereço virtual possível a ser mapeado, ou 537 milhões de leak gadgets. Mas o sistema tem apenas 8 GB de RAM. Além de ser possível mapear 2 TB de RAM usando COW, não tivemos muito sucesso com essa abordagem. Suponho que ela cria pressão demais no Translation Lookaside Buffer (TLB), tornando a especulação para um endereço não traduzido lenta demais. Nos testes, criamos uma página de 1 GB na memória e a preenchemos com os leak gadgets. Então deslocamos a página pelo intervalo de 2 TB usando a syscall remap. Outro problema observado foi o fato de que o endereço especulado provavelmente não estava presente no TLB, já que nunca havia sido realmente executado. Mas o manual da Intel afirma:

  • "O processador pode armazenar em cache traduções necessárias para prefetches e para acessos que são resultado de execução especulativa que nunca ocorreriam de fato no caminho de código executado" - ISA

Portanto, para aumentar as chances de um pagewalk "induzido por especulação", tentamos tornar o mais difícil possível a resolução do endereço correto. Isso é feito usando uma cadeia de ponteiros para o endereço de destino. A ideia é que o frontend da CPU especule o destino do desvio e a unidade de reordenação execute o leak gadget antes de terminar a leitura da cadeia de ponteiros.

root@kitploit:~
Improved Caller - Frontend fetched instructions
mov rcx,%1       ;mask arg for gadget
lea rsi,[%2]     ;probe array ptr arg
lea rdx,[%0]
mov rdx,[rdx]    ;pointer chain
mov rdx,[rdx]
mov rdx,[rdx]
...
mov rdx,[rdx]
mov rdx,[rdx]
check [rdx]      ;mispredicts to gadget

lea rax,[rip - 7];speculative execution
shr rax,cl
and rax,1
shl rax,12
mov dl,[rsi+rax]

root@kitploit:~
Improved Caller - Reorder unit scheduled instructions
mov rcx,%1    ;mask arg for gadget
lea rsi,[%2]  ;probe array ptr arg
lea rdx,[%0]
mov rdx,[rdx] ;pointer chain
mov rdx,[rdx]
; <pagewalk occurs some where here>
... ;Out of order + speculation
lea rax,[rip - 7]
shr rax,cl
and rax,1
shl rax,12
mov dl,[rsi+rax]
...
mov rdx,[rdx]
mov rdx,[rdx]
check [rdx] ;the execution path reverted

Essa técnica de execução fora de ordem + especulativa mostrou uma melhoria nas taxas desejadas de previsão errônea no ataque.

Agendamento e STIBP

Para realizar um ataque Spectre V2, o atacante deve executar código no mesmo núcleo que a vítima, para que compartilhem a mesma Unidade de Predição de Desvios (BPU). Em CPUs <= skylake, observamos que é possível alcançar a coresidência de núcleo usando hyperthreading. CPUs Icelake e Cascade Lake implementam uma mitigação chamada Single Thread Indirect Branch Predictor, que separa a BPU entre as threads. Portanto, é necessário executar a vítima e o atacante na mesma thread e usar o usleep para alternar entre o processo da vítima e o do atacante, o que tornaria o atacante mais lento nessas CPUs se não fosse o fato de que os caches (e provavelmente o TLB também) são muito bons nessas gerações, permitindo armazenar em cache muito mais gadgets ao mesmo tempo.

Resultados

Essa técnica foi testada em todas as CPUs Intel disponíveis no Google Cloud, tanto nas gerações N1 quanto N2:

  • Sandy Bridge
  • Ivy Bridge
  • Haswell
  • Broadwell
  • Skylake
  • Cascadelake
  • Icelake

Além de haver alguma diferença nos exploits para Cascade e Ice Lake, todos os testes conseguiram recuperar os endereços com >99% de precisão em menos de 10s.

Mitigações

As mitigações são as mesmas do Spectre V2 para mitigar ataques usuário-usuário. A barreira de predição de desvio indireto (IBPB) permite o flushing da BPU e pode ser usada em trocas de contexto. No Linux, o IBPB pode ser usado através da syscall prctl com a opção PR_SET_SPECULATION_CTRL. Não faço ideia de qual é a mitigação equivalente para Windows, por favor me digam.


Artigo:

https://cos.ufrj.br/uploadfile/publicacao/3061.pdf

Palestra Ekoparty:

https://www.youtube.com/watch?v=Qj4z-KvnkxU

Slides:

https://docs.google.com/presentation/d/10t-oo-c26x9ydx1_FYgmhy204rxfmQ92eboPlCnA2y4/edit?usp=sharing

Referências:

https://googleprojectzero.blogspot.com/2018/01/reading-privileged-memory-with-side.html https://eprint.iacr.org/2013/448.pdf https://spectreattack.com/spectre.pdf https://www.cs.ucr.edu/~nael/pubs/micro16.pdf http://download.vusec.net/papers/bhi-spectre-bhb_sec22.pdf https://www.kernel.org/doc/html/latest/userspace-api/spec_ctrl.html Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3. Santa Clara, USA: Intel Corporation, 2016, iSBN 325384-060US

Baixar ferramenta
Operação \ ciclo de clock12345
FetchABC
DecodingABC
ExecutionABC
Operação \ ciclo de clock123456
FetchABD
DecodingABD
ExecutionABD
Operação \ ciclo de clock123456
FetchAB(S) C
DecodingAB(S) C
ExecutionAB(S) C