Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
ExecASLR-ekoparty — Exploit de prueba de concepto que evade ASLR en CPUs de Intel abusando del branch target buffer y de la ejecución especulativa para filtrar direcciones aleatorizadas mediante un canal lateral. | Kitploit
Herramientas/GitHubGitHub/es0j/execaslr-ekoparty
Análisis de VulnerabilidadesExplotaciónSeguridad de HardwareAprendizaje y EducaciónRed TeamingAtaque AdversarioExplotación de Binarios
GitHubes0j/execaslr-ekoparty

ExecASLR-ekoparty

Exploit de prueba de concepto que evade ASLR en CPUs de Intel abusando del branch target buffer y de la ejecución especulativa para filtrar direcciones aleatorizadas mediante un canal lateral.

Ver Repositorio
729hace 3 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

ExecASLR - Abusando de los predictores de bifurcaciones de Intel para evadir ASLR

¿Qué es ASLR?

Address Space Layout Randomization es una mitigación utilizada para dificultar la explotación de ataques de corrupción de memoria. En un escenario de vulnerabilidad de desbordamiento de búfer, por ejemplo, un atacante que intenta realizar un exploit de Programación Orientada a Retorno necesita conocer las direcciones de los gadgets en la cadena. Si el segmento de código del binario explotado está aleatorizado, entonces es mucho más difícil para un atacante elegir la dirección correcta para el exploit, haciendo la explotación inviable.

El siguiente ejemplo muestra cómo se aleatoriza una dirección:

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 ejecución el valor se aleatoriza:

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

Los últimos 12 bits 149 son siempre los mismos, pero la ubicación de la función puede estar aproximadamente en cualquier lugar entre 0x550000000000 y 0x570000000000, lo que significa que 29 bits están aleatorizados, ocupando un espacio de direcciones posible de 0x200 0000 0000 o 2.2 TB de tamaño.

Pipeline de la CPU

El procesamiento de cada instrucción es una tarea compleja. Algunas etapas del procesamiento de una sola instrucción son:

  • Obtener la instrucción;
  • decodificar la instrucción;
  • ejecutar operaciones en la Unidad Aritmético Lógica.

Para aumentar el rendimiento de las instrucciones en la CPU, cada tarea de la instrucción es realizada por una unidad específica del procesador. Con todas las unidades trabajando en paralelo, la CPU puede ejecutar a velocidades de reloj mucho más altas; esa es la idea de un pipeline.

Ejecución de las instrucciones A, B y C a lo largo de los ciclos 1-5. En el ciclo 3, por ejemplo, las unidades de lectura, decodificación y ejecución están activas simultáneamente

Sin embargo, las instrucciones no son completamente independientes entre sí. Por ejemplo, la siguiente secuencia:

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

En este caso, la instrucción A, en el mejor de los casos, solo terminará en el ciclo 3 en la ejecución. Sin embargo, la unidad de captación necesita decidir cuál es la siguiente instrucción a captar de la memoria, si la instrucción C (mov dl,[rsi]) debe omitirse. En este escenario, la CPU tiene la opción de esperar a que la instrucción A termine, lo que solo ocurrirá en el tercer ciclo de reloj, para luego captar la instrucción correcta de la memoria, si la operación add devuelve 0, por ejemplo:

Eso implica un retraso en el pipeline porque la CPU debe esperar a que la instrucción se ejecute. En este ejemplo, el retraso es un solo ciclo de reloj, pero la instrucción add ax,[bx] requiere una operación de memoria que, como se vio antes, puede tomar hasta cientos de ciclos en completarse, lo que conlleva un costo de rendimiento significativo para el procesador.

Una opción más rápida sería intentar "adivinar" la ruta de ejecución correcta. La CPU puede especular si la bifurcación se toma o no. Después de ese punto, la ejecución continúa desde la ruta especulada y los valores solo se confirman si la ruta se demuestra correcta después de que termine la instrucción A. Si la ruta se demuestra incorrecta, los resultados se descartan y el estado se revierte al punto anterior a la especulación.

El único problema al revertir la ruta tomada es que el estado microarquitectónico de la CPU no se puede revertir. Entonces, si la CPU especula ejecutar la instrucción C (mov dl,[rsi]), los datos apuntados por rsi se moverán a la caché. Este efecto se puede medir más tarde usando un ataque de canal lateral.

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

Spectre V2 (Branch Target Injection)

No solo deben predecirse las instrucciones condicionales, sino también las bifurcaciones indirectas. La CPU debe tener un mecanismo para adivinar los destinos de una instrucción como call [rdi].

La vulnerabilidad Spectre v2 muestra que es posible explotar el predictor indirecto para lograr ejecución transitoria en otros procesos: Extraído de https://spectreattack.com/spectre.pdf

Al colocar una instrucción call en el contexto A en la misma dirección virtual que otra call en el contexto B, el atacante puede entrenar a la CPU para que ejecute código en una posición elegida por el atacante en el contexto B, en un ataque de reutilización de código, similar a la Programación Orientada a Retorno (ROP).

La víctima objetivo debe tener una pieza de código conocida como "spectre gadget" que sea capaz de filtrar un secreto mediante un ataque de canal lateral. Para que un ataque Spectre tenga éxito, el atacante también debe conocer la ubicación del spectre gadget. Por lo tanto, en ataques usuario-usuario, proteger a la víctima con ASLR solía ser una mitigación para este tipo de ataque. Sin embargo, también existen técnicas para extraer ASLR mediante ataques microarquitectónicos como Jump Over ASLR. No obstante, esta técnica tiene algunas limitaciones sobre la cantidad de bits filtrados, ya que se basa en colisiones en el predictor directo para evadir ASLR.

Los mecanismos internos de este predictor se muestran a continuación:

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

Algunos de estos componentes son:

  • El Branch Target Buffer (BTB);
    • El BTB es un componente tipo caché que almacena los destinos para las predicciones. El BTB almacena la dirección completa de 64 bits del destino y el número de entradas disponibles en el BTB depende de la arquitectura.
  • El Branch History Buffer (BHB);
    • El BHB almacena un "hash" del flujo de ejecución reciente. Cada instrucción de bifurcación escribe en el BHB. En las CPU Skylake y anteriores, el BHB puede almacenar el contexto de las últimas 29 bifurcaciones. En Icelake, el BHB almacena hasta ~100 bifurcaciones. Nótese que el BHB solo utiliza los 20 LSB de las bifurcaciones para crear el hash, de los cuales 12 no están aleatorizados.
  • El predictor indirecto;
    • Utiliza solo los 12 LSB de la instrucción de bifurcación indirecta para determinar el destino completo de 64 bits. Exec ASLR filtra el puntero de 64 bits del BTB para recuperar completamente las direcciones de ASLR.
  • El predictor de bifurcaciones directas
    • Utiliza los 30 LSB de la dirección de origen para predecir un valor de 32 bits. La otra mitad de la dirección se reutiliza desde el origen. El ataque Jump Over ASLR explota colisiones en este predictor para encontrar una dirección de origen que colisione con otro contexto, por lo tanto, está limitado a filtrar solo los 30 LSB del contexto de la víctima.

El diseño clásico del ataque Spectre v2 se ve así:

  • El atacante coloca una bifurcación indirecta en la misma posición que la bifurcación de la víctima, pero el destino coincide con un spectre gadget en el contexto de la víctima.
  • Cuando la víctima ejecuta la bifurcación, esta predice incorrectamente y el spectre gadget carga un secreto y realiza un acceso condicional a una región de memoria compartida, como una biblioteca. Por ejemplo, el spectre gadget que ejecuta getenv + secret[0]*4096 puede filtrar el valor del secreto en la posición 0 usando libc como memoria compartida.
  • El atacante recupera entonces el secreto filtrado detectando qué partes de la memoria compartida se movieron a la caché mediante un ataque flush+reload.

Exec ASLR

Exec ASLR (también conocido como Reverse Branch Target Buffer Poisoning) es una técnica novedosa para evadir ASLR usando la vulnerabilidad Spectre-BTI. Este ataque abusa del hecho de que no solo el atacante puede contaminar el BTB en un escenario clásico de Spectre-BTI, sino que las víctimas también pueden provocar una predicción incorrecta de bifurcación en el proceso del atacante, llevando al atacante a saltar especulativamente a una dirección protegida por ASLR. Luego, usando un canal lateral que filtra qué dirección se está ejecutando, un atacante puede recuperar la dirección de destino completa, evadiendo ASLR para el proceso objetivo.

El diseño del ataque Exec ASLR se ve así:

  • La víctima ejecuta una bifurcación indirecta, que escribe su puntero de destino aleatorizado (0x55aabbeef456) en el BTB.
  • El atacante coloca una bifurcación indirecta en una dirección alineada a los 12 LSB. Dado que los 12 LSB no están aleatorizados, esta parte es trivial.
  • El atacante llena todas las ubicaciones posibles de la memoria con un "leak gadget" que le dice al atacante "¡Estoy ejecutándome en esta dirección!" usando probeArray como canal lateral.
  • Cuando el atacante ejecuta la bifurcación indirecta, esta predice incorrectamente hacia uno de los muchos leak gadgets en memoria.
  • El atacante usa un ataque flush+reload para recuperar si ProbeArray fue accedido o no durante la especulación.

En este tipo de ataque, no es necesario encontrar un spectre gadget ni tener una memoria compartida para el canal lateral; el único requisito es que se explote una bifurcación indirecta. Todos los gadgets necesarios de Spectre v2 se colocan dentro del proceso del atacante. El único requisito nuevo para este ataque es poder mapear la dirección de destino de la víctima en tu propio proceso, por lo tanto, este ataque no puede funcionar contra KASLR, por ejemplo. Tampoco es un ataque de fuerza bruta; con un solo intento es posible probar múltiples direcciones al mismo tiempo, sin embargo, hay un límite de cuántos "leak gadgets" puede contener la memoria al mismo tiempo. Esto reduce significativamente el tiempo para realizar el ataque en comparación con Jump Over ASLR, de ~100 direcciones por segundo a unos cientos de miles de millones de direcciones por segundo.

Leak gadget

El leak gadget usa probeArray para informar al atacante dónde se ejecuta el propio gadget. Recibe probeArray y el índice del RIP a filtrar como argumento y realiza una especie de programación sin bifurcaciones para decidir si se debe acceder a probeArray[0] o a probeArray[4096].

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 el BHB y el código de la víctima objetivo

Como se vio antes, el BHB se usa para seleccionar una entrada del BTB. Para encontrar una colisión en el BTB y explotar esta vulnerabilidad, un atacante debe conocer las últimas N (29 si <skylake) bifurcaciones tomadas. En nuestras pruebas, usamos un bucle for para establecer el estado del BHB a un valor conocido antes de la llamada indirecta. Aquí hay un ejemplo vulnerable de código de víctima:

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 asegurar que el estado del BHB sea el mismo en ambos contextos, el atacante copia los bytes correspondientes al bucle for y a la llamada de la víctima en forma de shellcode. El shellcode se copia en las 256 posiciones posibles que pueden coincidir con la alineación de 20 LSB requerida para que el estado del BHB sea el mismo.

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]

Desafíos

Hay un problema al intentar colocar un gadget en todas las posiciones posibles al mismo tiempo. En nuestras pruebas, ASLR coloca el destino en algún lugar entre 0x550000000000 y 0x570000000000. Eso significa que hay 2.2 TB de dirección virtual posible para mapear o 537 millones de leak gadgets. Pero el sistema solo tiene 8 GB de RAM. Aunque es posible mapear 2 TB de RAM usando COW, no tuvimos mucho éxito con este enfoque. Supongo que crea demasiada presión sobre el Translation Lookaside Buffer (TLB), lo que hace que la especulación hacia una dirección no traducida sea demasiado lenta. En las pruebas creamos una página de 1 GB en memoria y la llenamos con los gadgets de filtración. Luego desplazamos la página a lo largo del rango de 2 TB usando la syscall remap. Otro problema observado fue el hecho de que la dirección especulada probablemente no estaba presente en el TLB, ya que en realidad nunca había sido ejecutada. Pero el manual de Intel dice:

  • "El procesador puede almacenar en caché las traducciones necesarias para prefetches y para accesos que son el resultado de ejecución especulativa que nunca ocurriría realmente en la ruta de código ejecutada" - ISA

Por lo tanto, para aumentar las posibilidades de un pagewalk "inducido por especulación", intentamos hacer lo más difícil posible que la dirección correcta se resuelva. Esto se hace usando una cadena de punteros para la dirección de destino. La idea es que el frontend de la CPU especule el destino de la bifurcación y la unidad de reordenamiento ejecute el leak gadget antes de terminar la lectura de la cadena de punteros.

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

Esta técnica de ejecución Fuera de Orden + Especulativa mostró una mejora en las tasas de predicción incorrecta deseadas en el ataque.

Planificación y STIBP

Para realizar un ataque Spectre V2, el atacante debe ejecutar código en el mismo núcleo que la víctima, de modo que compartan la misma Unidad de Predicción de Bifurcaciones (BPU). En CPU <= skylake observamos que es posible lograr la coresidencia de núcleos usando hyperthreading. Las CPU Icelake y Cascade Lake implementan una mitigación llamada Single Thread Indirect Branch Predictor, que separa la BPU entre subprocesos. Por lo tanto, es necesario ejecutar a la víctima y al atacante en el mismo subproceso y usar usleep para alternar entre el proceso de la víctima y el del atacante, lo que haría más lento al atacante en estas CPU si no fuera por el hecho de que las cachés (y probablemente también el TLB) son muy buenas en esas generaciones, permitiendo almacenar muchos más gadgets al mismo tiempo.

Resultados

Esta técnica fue probada en todas las CPU Intel disponibles en Google Cloud, tanto en las generaciones N1 como N2:

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

Además de tener algunas diferencias en los exploits para Cascade e Ice Lake, todas las pruebas pueden recuperar las direcciones con una precisión >99% en menos de 10 segundos.

Mitigaciones

Las mitigaciones son las mismas que Spectre V2 para mitigar ataques usuario-usuario. La barrera de predicción de bifurcaciones indirectas (IBPB) permite el vaciado de la BPU y puede usarse en cambios de contexto. En Linux, el IBPB se puede usar mediante la syscall prctl con la opción PR_SET_SPECULATION_CTRL. No tengo idea de cuál es la mitigación equivalente para Windows, por favor dímelo.


Artículo:

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

Charla de Ekoparty:

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

Diapositivas:

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

Referencias:

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

Descargar herramienta
Operación \ ciclo de reloj12345
CaptaciónABC
DecodificaciónABC
EjecuciónABC
Operación \ ciclo de reloj123456
CaptaciónABD
DecodificaciónABD
EjecuciónABD
Operación \ ciclo de reloj123456
CaptaciónAB(S) C
DecodificaciónAB(S) C
EjecuciónAB(S) C