c - seguridad - desbordamiento de pila en la linea 690
Ataque de desbordamiento de bĂșfer (4)
Ahora, lo que quiero es saltar a la función ''confused ()'' desde victim_func () desbordando el búfer allí, y sobrescribiendo la dirección de retorno a la dirección de confused () ...
En las plataformas modernas de Linux, también deberá asegurarse de que dos funciones de seguridad estén desactivadas para las pruebas. Primero en NX-stacks, y segundo es Stack Protectors.
Para desactivar las pilas NX, use -Wl,z,execstack
(a diferencia de -Wl,z,noexecstack
). Para desactivar los Protectores de pila, use -fno-stack-protector
(a diferencia de -fstack-protector
o -fstack-protector-all
).
Hay una tercera protección que deberías desactivar. Esa protección es FORTIFY_SOURCE. FORTIFY_SOURCE usa variantes "más seguras" de funciones de alto riesgo como memcpy
y strcpy
. El compilador utiliza las variantes más seguras cuando puede deducir el tamaño del búfer de destino. Si la copia superaría el tamaño del búfer de destino, el programa llama a abort()
. Para deshabilitar FORTIFY_SOURCE, compile el programa con -U_FORTIFY_SOURCE
o -D_FORTIFY_SOURCE=0
.
Las funciones de seguridad están activadas de forma predeterminada porque ha habido muchos problemas en el pasado. En general, es bueno porque detiene muchos problemas (como con el que está experimentando).
Estoy tratando de ejecutar un ataque de desbordamiento de búfer muy simple. Soy casi un novato en esto. Entonces, si esta pregunta es estúpida, por favor discúlpeme :-)
El código:
#include<stdio.h>
#include<stdlib.h>
int i, n;
void confused(int i)
{
printf("**Who called me? Why am I here?? *** %x/n ", i);
}
void shell_call(char *c)
{
printf(" ***Now calling /"%s/" shell command *** /n", c);
system(c);
}
void victim_func()
{
int a[4];
printf("Enter n: "); scanf("%d",&n);
printf("~~~~~~~~~~~~~ values and address of n locations ~~~~~~~~~~");
for (i = 0;i <n ;i++)
printf ("/n a[%d] = %x, address = %x", i, a[i], &a[i]);
printf("/nEnter %d HEX Values /n", n);
// Buffer Overflow vulnerability HERE!
for (i=0;i<n;i++) scanf("%x",&a[i]);
printf("Done reading junk numbers/n");
}
int main()
{
victim_func();
printf(“/n done”);
return 0;
}
Cuando uso objdump para obtener las direcciones de funciones, tengo lo siguiente:
main(): 0x804854d
Address of main() where printf() is called: 0x8048563
victim_func(): 0x8048455
confused(): 0x8048414
Ahora, lo que quiero es saltar a la función ''confused ()'' desde victim_func () desbordando el búfer allí, y sobrescribiendo la dirección de retorno a la dirección de confused (). Y quiero volver de confused () a la instrucción printf () en main, y salir normalmente. Por lo tanto, proporciono la siguiente entrada
Enter n: 7
Enter 7 HEX values:
1
2
3
4
5
8048414 (This is to jump to confused)
8048563 (this is to jump to printf() in main)
Aunque el programa imprime "Hecho" de esa declaración de printf, está saltando de nuevo a victim_func () e imprime "Enter n:"
¿Qué estoy haciendo mal? Cualquier ayuda sería muy apreciada!
PD: No estoy seguro si he hecho la pregunta correcta. Por favor, hágamelo saber, si se necesita más información.
En primer lugar, me parece que no debe ingresar el número 5 en su entrada de muestra. Su matriz se declara como [4], por lo que tiene elementos indexados 0-3, por lo que su entrada de ataque me parece incorrecta.
También me parece que su programa asume varias cosas sobre la arquitectura:
- sizof (int) == sizeof (dirección de memoria)
- La dirección de crecimiento y el mecanismo de la implementación de la pila de entornos.
Si una de estas suposiciones no es cierta, nunca funcionará.
Esto parece una tarea de trabajo muy duro.
Hay ejemplos más fáciles de ataques de desbordamiento de búfer que cambiar el flujo de control del código. Por ejemplo, es posible que pueda sobrescribir otro dato que se supone que está protegido del usuario (como una configuración de seguridad)
No nos mostró la salida del programa con las direcciones de [i]. Sospecho que el compilador está haciendo algo como alinear los datos en la pila a 16. Podría ser mucho más lejos de lo esperado de la dirección de retorno.
Un ataque de desbordamiento de búfer es mucho más complejo que esto. En primer lugar, es necesario comprender el ensamblador para realizar esto. Después de desarmar el programa y la función a la que desea dirigirse, debe determinar el diseño de la pila al ejecutar esa función. Aquí hay una muestra de un desbordamiento de búfer que está usando Visual Studio pero el principio es el mismo.
#include "stdafx.h"
#include <math.h>
volatile double test;
double function3()
{
test++;
return exp(test);
}
double function2()
{
return log(test);
}
double function1()
{
int a[5] = {0};
a[7] = (int)&function3;
return exp(function2());
}
int _tmain(int argc, _TCHAR* argv[])
{
double a = function1();
test = a;
return a;
}
Gracias al desmontaje, sabemos que una función in1 se asigna antes de que la función guardara el puntero del marco de pila. El valor posterior a ese es la dirección de retorno a la que debe ir la función1 si está terminada.
00401090 55 push ebp <- we save the stack pointer
00401091 8B EC mov ebp,esp
00401093 83 EC 1C sub esp,1Ch <- save space to allocate a[5]
00401096 B8 CC CC CC CC mov eax,0CCCCCCCCh
0040109B 89 45 E4 mov dword ptr [ebp-1Ch],eax <- crt debug init a[5]
0040109E 89 45 E8 mov dword ptr [ebp-18h],eax
004010A1 89 45 EC mov dword ptr [ebp-14h],eax
004010A4 89 45 F0 mov dword ptr [ebp-10h],eax
004010A7 89 45 F4 mov dword ptr [ebp-0Ch],eax
004010AA 89 45 F8 mov dword ptr [ebp-8],eax
004010AD 89 45 FC mov dword ptr [ebp-4],eax
De esto podemos concluir si sobrescribimos un [7] con una dirección diferente, la función regresará no a main sino a cualquier dirección que escribimos en un [7].
Espero que esto ayude.