Ejemplo de una vulnerabilidad de doble libertad en C

0

Espero que este sea el foro correcto para hacer la pregunta que tengo: Actualmente estamos discutiendo las vulnerabilidades de doble libertad en nuestra clase de seguridad de software, por lo que sé que el código que se proporciona a continuación se supone que es un ejemplo de cómo se puede explotar una doble libertad. Ahora, estoy tratando de entender este ejemplo y espero que alguien aquí pueda ayudarme con esto.

Lo primero que se hace en este código es una definición de una autenticación de estructura. Usamos esta estructura definiendo un puntero a dicha estructura: struct auth *auth;

Ok. Creo que una vulnerabilidad solo puede ser donde se han usado malloc o free . Pero, ¿qué podría ser explotado en este código específico? No lo veo Recuerdo de la clase que el problema de aplicar free al mismo puntero dos veces es que ahora el puntero hacia adelante y hacia atrás del fragmento está apuntando a este mismo trozo en el que están almacenados. De eso se trata mi conocimiento.

¡Me encantaría encontrar a alguien aquí, que pueda ayudar!

struct auth {
  char name[32];
  int auth;
};

struct auth *auth;
char *service;

int main(int argc, char **argv)
{
  char line[128];

  while(1) {
      printf("[ auth = %p, service = %p ]\n", auth, service);

      if(fgets(line, sizeof(line), stdin) == NULL) break;

      if(strncmp(line, "auth ", 5) == 0) {
          auth = malloc(sizeof(struct auth));
          memset(auth, 0, sizeof(struct auth));
          if(strlen(line + 5) < 31) {
              strcpy(auth->name, line + 5);
          }
      }
      if(strncmp(line, "reset", 5) == 0) {
          free(auth);
      }
      if(strncmp(line, "service ", 7) == 0) {
          service = strdup(line + 8);
      }
      if(strncmp(line, "login", 5) == 0) {
          if(auth->auth) {
              printf("you have logged in already!\n");
          } else {
              printf("please enter your password\n");
          }
      }
  }
}

Edición pequeña: con las respuestas dadas a la publicación, se me ocurrió una solución. Simplemente escriba las siguientes líneas:

auth me
reset
service AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
login

La entrada escrita después de service es de 36 caracteres. Ahora, ¿qué está pasando en este programa? auth me asigna 36 bytes de memoria en el montón. reset libera esta memoria, sin embargo, no se establece en NULL. Ahora service asigna nuevamente 36 bytes de memoria en el montón. Es muy probable que se asigne la misma memoria que fue asignada antes por auth . En esta memoria todavía podemos encontrar el nombre me . Esto está escrito en los últimos 4 bytes de esta área de memoria.

    
pregunta user503842 27.11.2018 - 20:00
fuente

2 respuestas

0

El programa solicita repetidamente al usuario que realice una operación, tomando como entrada una cadena que debe comenzar con una de "auth", "reset", "service" o "login" (no manejará ninguna otra cuerda muy graciosamente). Suponiendo que la cadena de entrada es aceptable, el programa realizará alguna operación y volverá a solicitarla. En particular, esto significa que puede ingresar el mismo comando dos veces seguidas.

  • "auth" causará la asignación de un struct auth (una de tres cosas con ese nombre, ya sea que el desarrollador sea terrible o el código sea deliberadamente confuso) del montón, y asignará su dirección al puntero auth variable. Llamar a esto más de una vez perderá memoria a menos que el struct auth señalado por auth se libere entre las llamadas.
  • "reset" liberará la memoria apuntada por la variable de puntero auth . Es seguro hacerlo si auth apunta a NULL o si auth apunta a un búfer de memoria válido y asignado (como el struct auth asignado por la operación "auth"). Sin embargo, llamar a free en un puntero no lo restablece a NULL , por lo que si hace una "auth" seguida de two "reset" s (sin otra "auth" en entre), entonces obtendrás una doble gratis . Lo que sucede en ese punto no está definido por la especificación de C, por lo que depende de sus implementaciones particulares de malloc y free , pero en la práctica generalmente es explotable por corrupción de memoria y, por lo tanto, potencialmente por ejecución de código arbitrario.
  • el "servicio" está entretenido con errores (solo comprueba los primeros 7 caracteres, no el espacio, por lo que potencialmente puedes terminar llamando a strdup en la memoria que no tiene bytes nulos antes de llegar a una página sin asignar, en cuyo caso el programa se bloqueará). Además, nunca libera la memoria que asigna strdup , por lo que usar "servicio" más de una vez provocará una pérdida de memoria. Aunque probablemente no sea relevante aquí.
  • "login" intentará anular la referencia a la variable de puntero auth y verificará el valor del campo apuntado a struct auth que también se llama auth y es un número entero. Esto fallará con una violación de segfault / access si la variable de puntero auth es nula o apunta a una dirección inválida (no asignada) (o más bien, si alguno de los bytes 33rd-36th más allá de esa dirección no están asignados). Esto probablemente tampoco sea relevante aquí.

Por lo tanto, ahora ya sabe cómo activar una llamada en este código. Realmente explotando eso queda como un ejercicio para el alumno. Trae un depurador.

    
respondido por el CBHacking 28.11.2018 - 01:27
fuente
0

Ese código tiene algunos problemas que debes corregir.

  1. Si el usuario escribe "restablecer" la primera vez, tiene una copia libre de algo que no asignó, también el puntero debe inicializarse a nulo para ayudar (auth = NULL)

  2. Si el usuario escribe "inicio de sesión" la primera vez, su código generará un SIGSEV en auth- > auth, no asignó la autenticación correctamente.

  3. en el malloc de llamadas, debe verificar que el valor de retorno no sea nulo.

Hay más problemas en el código, pero están más relacionados con malas prácticas de programación que con una seguridad relacionada desde mi punto de vista

    
respondido por el camp0 27.11.2018 - 21:42
fuente

Lea otras preguntas en las etiquetas