Solución Reto Overflow CTF


KTaneR

Activo muy miembro
Burgués de Nodo
Noderador
Nodero
Noder
El reto que planteabamos era el siguiente : https://www.nodo313.net/index.php?threads/reto-overflow-ctf.7524/#post-72133

Y como de costumbre en los temas relacionados con la tématica del foro el interés generado ha sido escaso, creo que el único usuario interesado ha sido @Galaxyytbr, y como me ha ido preguntado dudas y me ha pedido la solución se la voy a subir ya, porque este tema caerá en el olvido imagino.

La solución la haré enfocada a las dudas de este usuario, que eran bastante básicas, así que, intentaré obviar partes muy técnicas y enseñarle a llegar a la solución de manera sencilla.

- El primer paso es descargarse el .c y el ejecutable.

- Ahora procedemos a ver el codigo en cualquier editor de texto y veremos algo como esto :

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"

#define BUFFSIZE 64
#define FLAGSIZE 64

void flag() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}

void vuln(){
  char buf[BUFFSIZE];
  gets(buf);

  printf("Woah, were jumping to 0x%x !\n", get_return_address());
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  puts("Give me a string and lets see what happens: ");
  vuln();
  return 0;
}

Según el título del reto, lo que nos tiene que llamar la atención del código es lo siguiente :

#define BUFFSIZE 64
gets(buf);

Vemos el tamaño 64 y una función que presenta esto en su documentación
gets() reads a line from stdin into the buffer pointed to by s until either a terminating newline or EOF, which it replaces with a null byte (aq\0aq). No check for buffer overrun is performed (see BUGS below).

Y el objetivo parece ser llegar a la función flag(), veremos como lo hacemos:

- Bien pues lo primero que haremos es probar el ejecutable a ver que sucede:

1589812590972.png


Vemos que nos pide la entrada, luego la imprime, y después nos da la dirección de retorno, la siguiente dirección a donde va a saltar el programa. (Como vemos no hacía falta ni saber c para comprender el programa ya que es muy simple.)

- Ahora siguendo la documentación de la función gets, el cual nos dice que no tiene ningun tipo de comprobacion en la entrada, es decir va a aceptar todo lo que le metamos, sin importar el tamaño de la variable.
(Recordemos : #define BUFFSIZE 64 )

Así que vamos a ver que pasa si nos pasamos de ese tamaño.
(Vamos a hacer todos estos paso de forma manual, sin ningun tipo de herramienta para complicar lo menos posible la solución)

1589812827848.png


Vemos que hemos superado el tamaño máximo de la variable, y nos ha dado un error.

Y si nos fijamos un poco hemos sobrescrito la dirección de retorno!!!!
Hemos pasao de 0x8048705 a 0x41414141.

Con una simple conversión online podemos ver que significa el nuevo numero que tenemos.
1589813044795.png


Como vemos hemos sobrescrito la dirección de retorno con las As que le hemos pasado como input!

- Ahora debemos comprobar exactamente cuantas As hacen falta para llegar a ese punto, para que podamos tener control total del retorno y llegar a la función flag().

Como haremos esto? Pues existen diversas técnicas, pero como el objetivo es hacer esta explicación apta para todo el mundo, vamos a hacerlo con python para comodidad pero el proceso será puramente manual. Añadiremos ahora unas cuantas As + 4Bs hasta conseguir que nuestra dirección de retorno sea todo 42(como vimos antes las As son 41, y la B es 42)

1589813450304.png


Bueno no voy a comentar demasiado del comando, y como veis podemos hacerlo de forma sencilla solo con ir probando(en este caso simple claro xD)

BIEN, sabemos que ingresando exactamente 76 As, lo siguiente que ingresemos será la dirección de retorno, como podemos ver por nuestras 4Bs (42) saliendo por pantalla.

- Que nos queda? simplemente que esa dirección de retorno que tenemos ya controlada apunte a nuestra función flag().

Otra vez hay muchas formas de hacerlo, pero no vamos a entrar en ver la memoria guardad en la pila ni nada que pueda complicar mas el asunto, vamos a tirar un simple comando que os vais a creer que funciona y el cual podeis investigar en internet, o buscar otras formas de llegar a la dirección de la función deseada.

1589813787910.png


Bien ya tenemos la dirección de nuestra función flag(). Solo nos quedaría añadirla tras exactamente las 76As (o cualquier caracter) para que la dirección de retorno sea la función deseada.

Nota: No entraremos en esto tampoco pero la dirección debe escribirse en little endian (google) por lo que nos quedaría : 080485e6 --> '\xe6\x85\x04\08'

- Por lo que como último paso solo tendremos que concatenar esa dirección en vez de las 4Bs que teníamos ya saltándonos por pantalla :

1589814001696.png


Como vemos saltamos a la función deseada, pero al no tener el txt con la flag obtenemos este mensaje, pero hemos superado el reto !!!

Espero que os guste y hayáis aprendido algo con todo esto. Yo seguiré haciendo retillos y compartiendo lo que aprenda!
 

Adjuntos

  • 1589812928220.png
    1589812928220.png
    80,8 KB · Visitas: 12
Última edición:

Sadsu

後輩
Noderador
Nodero
Noder
pero que pedazo post de verdad, porfin se ven cosas realmente ineresante gracias katana por tremendo hilo, no entendi despues de que te pasas de 64 que solo sale una A ¿Podrias explicarme un poco mejor lo que esta sucediendo?
 
  • Maravilloso
Reacciones : KTaneR

KTaneR

Activo muy miembro
Burgués de Nodo
Noderador
Nodero
Noder
pero que pedazo post de verdad, porfin se ven cosas realmente ineresante gracias katana por tremendo hilo, no entendi despues de que te pasas de 64 que solo sale una A ¿Podrias explicarme un poco mejor lo que esta sucediendo?
SI te fijas el programa cada vez que lo ejecutas te dice una dirección a la que esta saltando, y despues de meter muchas As Hemos pasao de 0x8048705 a 0x41414141.

Bien eso significa que si A = 41, y tenemos 41414141 significa que nos hemos pasado tanto que hemos llegado a meter (A(41)A(41)A(41)A(41)) en la direccion de retorno, y en el siguiente paso comproabremos cuantas As exactamente son las necesarias
 

Sadsu

後輩
Noderador
Nodero
Noder
SI te fijas el programa cada vez que lo ejecutas te dice una dirección a la que esta saltando, y despues de meter muchas As Hemos pasao de 0x8048705 a 0x41414141.

Bien eso significa que si A = 41, y tenemos 41414141 significa que nos hemos pasado tanto que hemos llegado a meter (A(41)A(41)A(41)A(41)) en la direccion de retorno, y en el siguiente paso comproabremos cuantas As exactamente son las necesarias
y realmente por que interesa sacar ese flag? osea me refiero que es lo que hace que quieras coger esa bandera exactamente? que fuuncion quieres sacar de ello?
 
  • Like
Reacciones : KTaneR

KTaneR

Activo muy miembro
Burgués de Nodo
Noderador
Nodero
Noder
y realmente por que interesa sacar ese flag? osea me refiero que es lo que hace que quieras coger esa bandera exactamente? que fuuncion quieres sacar de ello?
es un reto simplemente, hay muchos de diversos tipos, en los que sacas una flag como prueba de que has consguido solucionarlo, y suelen hacer falta diversas tecnicas para conseguir los retos, en este caso aprender como funciona el buffer overflow, con el cual en vez de As podemos meter codigo malicioso que por ejemplo ejecute un shell o lo que quieras, y mandar la direccion de retorno a nuestro codigo en vez de a otra funcion
 
  • Like
Reacciones : destapeman y Sadsu

Sadsu

後輩
Noderador
Nodero
Noder
es un reto simplemente, hay muchos de diversos tipos, en los que sacas una flag como prueba de que has consguido solucionarlo, y suelen hacer falta diversas tecnicas para conseguir los retos, en este caso aprender como funciona el buffer overflow, con el cual en vez de As podemos meter codigo malicioso que por ejemplo ejecute un shell o lo que quieras, y mandar la direccion de retorno a nuestro codigo en vez de a otra funcion
pedazo currazo vale gracias!
 
  • Maravilloso
Reacciones : KTaneR

Ivansuito

Miembro muy activo
Nodero
Noder
El reto que planteabamos era el siguiente : https://www.nodo313.net/index.php?threads/reto-overflow-ctf.7524/#post-72133

Y como de costumbre en los temas relacionados con la tématica del foro el interés generado ha sido escaso, creo que el único usuario interesado ha sido @Galaxyytbr, y como me ha ido preguntado dudas y me ha pedido la solución se la voy a subir ya, porque este tema caerá en el olvido imagino.

(@Thegjv te daré un voto de confianza y seguiré subiendo mierda aunque sea solo para un chaval con ganas de aprender como en este caso)

La solución la haré enfocada a las dudas de este usuario, que eran bastante básicas, así que, intentaré obviar partes muy técnicas y enseñarle a llegar a la solución de manera sencilla.

- El primer paso es descargarse el .c y el ejecutable.

- Ahora procedemos a ver el codigo en cualquier editor de texto y veremos algo como esto :

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"

#define BUFFSIZE 64
#define FLAGSIZE 64

void flag() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}

void vuln(){
  char buf[BUFFSIZE];
  gets(buf);

  printf("Woah, were jumping to 0x%x !\n", get_return_address());
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  gid_t gid = getegid();
  setresgid(gid, gid, gid);
  puts("Give me a string and lets see what happens: ");
  vuln();
  return 0;
}

Según el título del reto, lo que nos tiene que llamar la atención del código es lo siguiente :

#define BUFFSIZE 64
gets(buf);

Vemos el tamaño 64 y una función que presenta esto en su documentación
gets() reads a line from stdin into the buffer pointed to by s until either a terminating newline or EOF, which it replaces with a null byte (aq\0aq). No check for buffer overrun is performed (see BUGS below).

Y el objetivo parece ser llegar a la función flag(), veremos como lo hacemos:

- Bien pues lo primero que haremos es probar el ejecutable a ver que sucede:

Ver el archivo adjunto 4259

Vemos que nos pide la entrada, luego la imprime, y después nos da la dirección de retorno, la siguiente dirección a donde va a saltar el programa. (Como vemos no hacía falta ni saber c para comprender el programa ya que es muy simple.)

- Ahora siguendo la documentación de la función gets, el cual nos dice que no tiene ningun tipo de comprobacion en la entrada, es decir va a aceptar todo lo que le metamos, sin importar el tamaño de la variable.
(Recordemos : #define BUFFSIZE 64 )

Así que vamos a ver que pasa si nos pasamos de ese tamaño.
(Vamos a hacer todos estos paso de forma manual, sin ningun tipo de herramienta para complicar lo menos posible la solución)

Ver el archivo adjunto 4260

Vemos que hemos superado el tamaño máximo de la variable, y nos ha dado un error.

Y si nos fijamos un poco hemos sobrescrito la dirección de retorno!!!!
Hemos pasao de 0x8048705 a 0x41414141.

Con una simple conversión online podemos ver que significa el nuevo numero que tenemos.
Ver el archivo adjunto 4263

Como vemos hemos sobrescrito la dirección de retorno con las As que le hemos pasado como input!

- Ahora debemos comprobar exactamente cuantas As hacen falta para llegar a ese punto, para que podamos tener control total del retorno y llegar a la función flag().

Como haremos esto? Pues existen diversas técnicas, pero como el objetivo es hacer esta explicación apta para todo el mundo, vamos a hacerlo con python para comodidad pero el proceso será puramente manual. Añadiremos ahora unas cuantas As + 4Bs hasta conseguir que nuestra dirección de retorno sea todo 42(como vimos antes las As son 41, y la B es 42)

Ver el archivo adjunto 4264

Bueno no voy a comentar demasiado del comando, y como veis podemos hacerlo de forma sencilla solo con ir probando(en este caso simple claro xD)

BIEN, sabemos que ingresando exactamente 76 As, lo siguiente que ingresemos será la dirección de retorno, como podemos ver por nuestras 4Bs (42) saliendo por pantalla.

- Que nos queda? simplemente que esa dirección de retorno que tenemos ya controlada apunte a nuestra función flag().

Otra vez hay muchas formas de hacerlo, pero no vamos a entrar en ver la memoria guardad en la pila ni nada que pueda complicar mas el asunto, vamos a tirar un simple comando que os vais a creer que funciona y el cual podeis investigar en internet, o buscar otras formas de llegar a la dirección de la función deseada.

Ver el archivo adjunto 4265

Bien ya tenemos la dirección de nuestra función flag(). Solo nos quedaría añadirla tras exactamente las 76As (o cualquier caracter) para que la dirección de retorno sea la función deseada.

Nota: No entraremos en esto tampoco pero la dirección debe escribirse en little endian (google) por lo que nos quedaría : 080485e6 --> '\xe6\x85\x04\08'

- Por lo que como último paso solo tendremos que concatenar esa dirección en vez de las 4Bs que teníamos ya saltándonos por pantalla :

Ver el archivo adjunto 4266

Como vemos saltamos a la función deseada, pero al no tener el txt con la flag obtenemos este mensaje, pero hemos superado el reto !!!

Espero que os guste y hayáis aprendido algo con todo esto. Yo seguiré haciendo retillos y compartiendo lo que aprenda!
Vaya puto pedazo de post. Grandisimo, muchas gracias!!
 
  • Maravilloso
Reacciones : KTaneR

Thegjv

Moder fav <3
Noderador
Nodero
Noder
SI te fijas el programa cada vez que lo ejecutas te dice una dirección a la que esta saltando, y despues de meter muchas As Hemos pasao de 0x8048705 a 0x41414141.

Bien eso significa que si A = 41, y tenemos 41414141 significa que nos hemos pasado tanto que hemos llegado a meter (A(41)A(41)A(41)A(41)) en la direccion de retorno, y en el siguiente paso comproabremos cuantas As exactamente son las necesarias
Gracias, este es el espitiru del foro <3
 
  • Maravilloso
Reacciones : KTaneR

konde_morr

Destape del HACENDADO
Noderador
Nodero
Noder
Y el primer archivo servía de algo? Lo intentaba abrir y no tenía con que programa hacerlo
 

KTaneR

Activo muy miembro
Burgués de Nodo
Noderador
Nodero
Noder
Y el primer archivo servía de algo? Lo intentaba abrir y no tenía con que programa hacerlo
Hay dos : vuln.c es el codigo que hay ahi pegado, y despues el ejecutable(vuln) , que es el .c compilado y listo para ejecutar

El .c lo puedes abrir en la consola con un cat cualquier comando del estilo o cualquier editor de texto, desde el bloc de notas al geany al sublime al que quieras y el ejecutable como ves en las capturas se ejecuta