Ir al contenido

El Pipo

Autor
Santiago Chavarro

El código presentado es vulnerable a un ataque de buffer overflow. Aquí tienes una explicación paso a paso, ideal para un write up técnico y claro sobre el funcionamiento, la vulnerabilidad y cómo se explota para leer la flag en lugar de causar un segmentation fault.

Análisis del Código
#

int __fastcall main(int argc, const char **argv, const char **envp)
{
  _QWORD buf[5]; // [rsp+0h] [rbp-30h] BYREF
  char v5; // [rsp+2Fh] [rbp-1h]

  memset(buf, 0, 32);
  v5 = 1;
  read(0, buf, 0x40u);
  if ( v5 == 1 )
  {
    fwrite("Not scary enough.. Boo! :(", 1u, 0x1Au, stdout);
    fflush(stdout);
  }
  else
  {
    read_flag();
  }
  return 0;
}

Paso a paso del funcionamiento
#

  • Se declara un buffer buf como un arreglo de 5 elementos tipo _QWORD, que equivale a 5 x 8 = 40 bytes (en sistemas de 64 bits).
  • Se declara una variable local char v5.
  • El buffer se inicializa en cero con memset.
  • Luego, v5 se establece en 1.
  • La función read(0, buf, 0x40u); lee hasta 64 bytes desde la entrada estándar y los coloca en el buffer buf.
  • El programa luego consulta si v5 sigue siendo igual a 1; si es así, imprime un mensaje. Si no, llama a read_flag() (que asume lee y muestra la flag).

Identificación de la Vulnerabilidad
#

  • El tamaño del buffer es de 40 bytes, pero el read permite escribir hasta 64 bytes. Cualquier dato que sobrepase los primeros 40 bytes sobrescribirá variables que estén a continuación en la pila (stack), como v5.
  • En la estructura del stack, “buf” está antes en memoria que “v5”. Así, los bytes extra sobreescriben “v5” y potencialmente variables más allá.

Aprovechamiento del Buffer Overflow
#

  • Si el atacante escribe 41 bytes (40 para llenar el buffer y 1 byte más), ese byte adicional sobrescribirá el valor de v5.
  • Si el nuevo valor de v5 es distinto de 1 (por ejemplo, 0x00 o cualquier otro valor), se ejecutará la rama del else, provocando la llamada a read_flag() en vez de imprimir el mensaje.
  • De esta forma, es posible controlar el flujo del programa y acceder a la flag: simplemente proporciona como entrada 40 bytes de “padding” (cualquier valor) y el byte 41 debe ser diferente de 1.