El desbordamiento de búfer funciona en gdb pero no sin él

9 minutos de lectura

avatar de usuario
hombre del tiempo

Estoy en CentOS 6.4 de 32 bits y estoy tratando de causar un desbordamiento de búfer en un programa. Dentro de GDB funciona. Aquí está la salida:

[[email protected] bufferoverflow]# gdb stack
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/bufferoverflow/stack...done.
(gdb) r
Starting program: /root/bufferoverflow/stack
process 6003 is executing new program: /bin/bash
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6_4.2.i686
sh-4.1#

Sin embargo, cuando ejecuto la pila del programa solo, falla. ¿Por qué podría ser esto?

  • seg faults se debe a un desbordamiento de búfer, lo ha hecho, correcto. Cuando ejecuta su código OS, envíe SIGSEGV a su proceso (= programa en ejecución) en violación de memoria que le da una falla de segmentación de mensajes: esta señal se debe a que está haciendo un acceso no válido a la memoria válida. (Supongo que está tratando de escribir/modificar en "constantstring" al final)

    –Grijesh Chauhan

    21 de julio de 2013 a las 17:58


  • …Yo sé eso. Se supone que debe ejecutar un shell. En GDB ejecuta el shell. Cuando ejecuto el programa fuera de GDB, no ejecuta el shell, de ahí el error de segmento

    – hombre del tiempo

    21 de julio de 2013 a las 18:01

  • esto se debe a que cuando ejecuta su código fuera de GDB, tiene un comportamiento indefinido en el estándar C. Mientras que GDB maneja la señal SIGSEGV para que pueda señalarle una falla de segmentación

    –Grijesh Chauhan

    21 de julio de 2013 a las 18:04


  • @GrijeshChauhan: GDB manejaría el SIGSEGV y reportar que sucedió. No hay tal informe aquí. Lo esperaría completamente después bash regresa, pero la falla de segmento ocurriría incluso antes de que comience

    – chao

    21 de julio de 2013 a las 19:46


  • @cHao 🙁 🙂 (: 🙂 Ni idea, no sé, tengo que probar un experimento yo mismo.

    –Grijesh Chauhan

    21 de julio de 2013 a las 20:10

avatar de usuario
señora

El desarrollo de exploits puede provocar serios dolores de cabeza si no se tienen en cuenta adecuadamente los factores que introducen no determinismo en el proceso de depuración. En particular, las direcciones de la pila en el depurador pueden no coincidir con las direcciones durante la ejecución normal. Este artefacto ocurre porque el cargador del sistema operativo coloca variables de entorno y argumentos de programa antes de el comienzo de la pila:

Diseño del proceso

Dado que su programa vulnerable no acepta ningún argumento, es probable que las variables de entorno sean las culpables. Asegúrese de que sean iguales en ambas invocaciones, en el shell y en el depurador. Con este fin, puede envolver su invocación en env:

env - /path/to/stack

Y con el depurador:

env - gdb /path/to/stack
($) show env
LINES=24
COLUMNS=80

En el ejemplo anterior, hay dos variables de entorno establecidas por gdb, que puede deshabilitar aún más:

unset env LINES
unset env COLUMNS

Ahora show env debería devolver una lista vacía. En este punto, puede iniciar el proceso de depuración para encontrar la dirección de pila absoluta a la que prevé saltar (por ejemplo, 0xbffffa8b) y codificarlo en su exploit.

Otro detalle sutil pero importante: hay una diferencia entre llamar ./stack y /path/to/stack: ya que argv[0] mantiene el programa exactamente como lo invocó, debe asegurarse de que las cadenas de invocación sean iguales. Es por eso que usé /path/to/stack en los ejemplos anteriores y no solo ./stack y gdb stack.

Cuando aprenda a explotar las vulnerabilidades de seguridad de la memoria, recomiendo usar el programa contenedor a continuación, que hace el trabajo pesado y garantiza compensaciones de pila iguales:

$ invoke stack         # just call the executable
$ invoke -d stack      # run the executable in GDB

Aquí está el guión:

#!/bin/sh

while getopts "dte:h?" opt ; do
  case "$opt" in
    h|\?)
      printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0)
      exit 0
      ;;
    t)
      tty=1
      gdb=1
      ;;
    d)
      gdb=1
      ;;
    e)
      env=$OPTARG
      ;;
  esac
done

shift $(expr $OPTIND - 1)
prog=$(readlink -f $1)
shift
if [ -n "$gdb" ] ; then
  if [ -n "$tty" ]; then
    touch /tmp/gdb-debug-pty
    exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args $prog "[email protected]"
  else
    exec env - $env TERM=screen PWD=$PWD gdb --args $prog "[email protected]"
  fi
else
  exec env - $env TERM=screen PWD=$PWD $prog "[email protected]"
fi

  • Hice lo que sugirió y ejecuté el programa como /root/bufferflow/stack y funcionó correctamente. Gracias

    – hombre del tiempo

    21 de julio de 2013 a las 21:05

  • El ejemplo está mal. En lugar de ‘–gdb’ debería haber ‘-d’.

    – molnarg

    27 mayo 2014 a las 19:56

  • @molnarg: Gracias, solucionado.

    – señora

    4 de junio de 2014 a las 8:43

  • ¡Información muy útil! Gracias por compartir también el guión.

    – alecov

    10 de noviembre de 2015 a las 18:47

  • Para mí, esto no funciona. Primero intento eliminar las variables de entorno y no funciona, luego utilicé el script publicado en este formulario: ./invoke -d exploitme y luego (en gdb) run MY_SHELLCODE Puedo ejecutar mi shelcode en gdb, pero cuando ejecuto ./invoke exploitme MY_SHELLCODE No puedo ejecutar el shellcode, obtengo Welcome ��^�1��F�F � ����V 1ۉ�@�����/bin/shP��� [1] 13626 segmentation fault (core dumped) ./invoke exploitme donde MY_SHELLCODE es mi cadena de shellcode.

    – RdlP

    12 oct 2016 a las 15:09


avatar de usuario
york

La dirección del puntero del marco de pila cuando se ejecuta el código en gdb es diferente de ejecutarlo normalmente. Por lo tanto, puede corromper la dirección de retorno directamente en el modo gdb, pero puede que no funcione correctamente cuando se ejecuta en el modo normal. La razón principal de esto es que las variables ambientales difieren entre las dos situaciones.

Como esto es solo una demostración, puede cambiar el código de la víctima e imprimir la dirección del búfer. Luego cambie su dirección de retorno a offset+dirección del búfer.

En realidad, sin embargo, debe adivinar la dirección del remitente. trineo NOP antes de su código malicioso. Y puede adivinar varias veces para obtener una dirección correcta, ya que su suposición puede ser incorrecta.

Espero que esto le pueda ayudar.

avatar de usuario
Aralox

Aquí hay una forma sencilla de ejecutar su programa con pilas idénticas en la terminal y en gdb:

Primero, asegúrese de que su programa esté compilado sin protección de pila,

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

y ASLR está deshabilitado:

echo 0 > /proc/sys/kernel/randomize_va_space

NOTA: el valor predeterminado en mi máquina era 2, tenga en cuenta el suyo antes de cambiarlo.

Luego ejecute su programa así (terminal y gdb respectivamente):

env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 /root/Documents/MSec/shelltest
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 gdb /root/Documents/MSec/shelltest

Dentro de gdbasegurate que unset LINES y COLUMNS.

Nota: obtuve esas variables de entorno jugando con un Programa de prueba.

Esas dos ejecuciones le darán punteros idénticos a la parte superior de la pila, por lo que no es necesario realizar travesuras de secuencias de comandos remotas si está tratando de explotar un binario alojado de forma remota.

La razón por la que su desbordamiento de búfer funciona bajo gdb y segfaults es que gdb deshabilita la aleatorización del diseño del espacio de direcciones. Creo que esto se activó de forma predeterminada en la versión 7 de gdb.

Puede verificar esto ejecutando este comando:

show disable-randomization

Y configurarlo con

set disable-randomization on

o

set disable-randomization off

He probado la solución aceptada aquí y no funciona (para mí). Sabía que gdb agregaba variables de entorno y por esa razón la dirección de la pila no coincide, pero incluso eliminando esas variables no puedo trabajar con mi exploit sin gdb (también probé el script publicado en la solución aceptada).

Pero buscando en la web encontré otro script que me funciona: https://github.com/hellman/fixenv/blob/master/r.sh

El uso es básicamente el mismo que el script en la solución aceptada:

  • r.sh gdb ./programa [args] para ejecutar el programa en gdb
  • r.sh ./programa [args] para ejecutar el programa sin gdb

Y este script funciona para mí.

avatar de usuario
jww

Estoy en CentOS 6.4 de 32 bits y estoy tratando de causar un desbordamiento de búfer en un programa… Sin embargo, cuando ejecuto la pila del programa por sí sola, falla la segmentación.

También debe asegurarse de que FORTIFY_SOURCE no afecte sus resultados. La falla de segmentación parece que FORTIFY_SOURCE podría ser el problema porque FORTIFY_SOURCE insertará llamadas a funciones “más seguras” para protegerse contra algunos tipos de desbordamientos de búfer. Si el compilador puede deducir los tamaños del búfer de destino, entonces se verifica el tamaño y se abort() se llama por una violación (es decir, su falla de segmentación).

Para desactivar FORTIFY_SOURCE para la prueba, debe compilar con -U_FORTIFY_SOURCE o -D_FORTIFY_SOURCE=0.

Una de las principales cosas que hace gdb que no sucede fuera de gdb es memoria cero. Lo más probable es que en algún lugar del código no esté inicializando su memoria y esté obteniendo valores basura. Gdb borra automáticamente toda la memoria que asigna ocultando ese tipo de errores.

Por ejemplo: lo siguiente debería funcionar en gdb, pero no fuera de él:

int main(){
    int **temp = (int**)malloc(2*sizeof(int*)); //temp[0] and temp[1] are NULL in gdb, but not outside
    if (temp[0] != NULL){
        *temp[0] = 1; //segfault outside of gdb
    }
    return 0;
}

Intente ejecutar su programa bajo valgrind para ver si puede detectar este problema.

  • El programa vulnerable en realidad lee un archivo en un búfer, por lo que el archivo es la cadena de explotación. Luego llama a una función que hace un strcpy del búfer original en un búfer mucho más pequeño. Entonces nunca inicializa la memoria fuera de esas funciones

    – hombre del tiempo

    21 de julio de 2013 a las 18:36

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad