Le dépassement de mémoire tampon fonctionne dans gdb mais pas sans elle

Je suis sur CentOS 6.4 32 bits et j’essaie de provoquer un débordement de tampon dans un programme. Cela fonctionne dans GDB. Voici la sortie:

[root@localhost 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  This is free software: you are free to change and redissortingbute 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: ... 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# 

Cependant, lorsque j’exécute la stack de programmes seule, elle segmente les erreurs. Pourquoi cela pourrait-il être?

Le développement d’exploitation peut entraîner de graves maux de tête si vous ne prenez pas correctement en compte les facteurs qui introduisent le non-déterminisme dans le processus de débogage. En particulier, les adresses de stack dans le débogueur peuvent ne pas correspondre aux adresses lors de l’exécution normale. Cet artefact se produit parce que le chargeur du système d’exploitation place les variables d’environnement et les arguments de programme avant le début de la stack:

Mise en page de processus

Puisque votre programme vulnérable ne prend aucun argument, les variables d’environnement sont probablement le coupable. Je suis sûr qu’ils sont les mêmes dans les deux invocations, dans le shell et dans le débogueur. À cette fin, vous pouvez envelopper votre invocation dans env :

 env - /path/to/stack 

Et avec le débogueur:

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

Dans l’exemple ci-dessus, il existe deux variables d’environnement définies par gdb, que vous pouvez désactiver davantage:

 unset env LINES unset env COLUMNS 

Maintenant, show env devrait retourner une liste vide. À ce stade, vous pouvez démarrer le processus de débogage pour rechercher l’adresse de stack absolue à laquelle vous souhaitez 0xbffffa8b (par exemple, 0xbffffa8b ) et la coder en dur dans votre exploit.

Un autre détail subtil mais important: il existe une différence entre appeler ./stack et /path/to/stack : puisque argv[0] contient le programme exactement comme vous l’avez appelé, vous devez vous assurer que les chaînes d’appel sont égales. C’est pourquoi j’ai utilisé /path/to/stack dans les exemples ci-dessus et pas seulement ./stack et gdb stack .

Lorsque vous apprenez à exploiter des vulnérabilités de sécurité de la mémoire, je vous recommande d’utiliser le programme d’emballage ci-dessous, qui permet de supporter les charges lourdes et d’assurer des décalages de stack égaux:

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

Voici le script:

 #!/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 "$@" else exec env - $env TERM=screen PWD=$PWD gdb --args $prog "$@" fi else exec env - $env TERM=screen PWD=$PWD $prog "$@" fi 

L’adresse du pointeur de cadre de stack lors de l’exécution du code dans gdb est différente de son exécution normale. Donc, vous pouvez corrompre l’adresse de retour directement en mode gdb, mais cela peut ne pas être le cas lorsqu’il est exécuté en mode normal. La raison principale en est que les variables d’environnement diffèrent d’une situation à l’autre.

Comme il ne s’agit que d’une démonstration, vous pouvez modifier le code de la victime et imprimer l’adresse du tampon. Puis changez votre adresse de retour en offset + adresse du tampon.

En réalité, vous devez toutefois deviner l’adresse de retour et append NOP sled avant votre code malveillant. Et vous pouvez deviner plusieurs fois pour obtenir une adresse correcte, car votre estimation peut être incorrecte.

J’espère que cela peut vous aider.

Si votre dépassement de mémoire tampon fonctionne sous gdb et segfaults, c’est que gdb désactive la randomisation de la disposition des espaces d’adresses. Je crois que cela a été activé par défaut dans la version 7 de gdb.

Vous pouvez vérifier cela en exécutant cette commande:

 show disable-randomization 

Et le mettre avec

 set disable-randomization on 

ou

 set disable-randomization off 

Voici un moyen simple d’exécuter votre programme avec des stacks identiques dans le terminal et dans gdb :

Tout d’abord, assurez-vous que votre programme est compilé sans protection de stack,

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

et et ASLR est désactivé:

echo 0 > /proc/sys/kernel/randomize_va_space

REMARQUE: la valeur par défaut sur ma machine était 2, notez la vôtre avant de la modifier.

Puis lancez votre programme comme suit (respectivement terminal et gdb):

 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 

Dans gdb , veillez à unset LINES et les COLUMNS .

Remarque: j’ai obtenu ces variables d’environnement en jouant avec un programme de test .

Ces deux exécutions vous donneront des pointeurs identiques vers le haut de la stack. Vous n’avez donc pas besoin de scripts de script distants si vous essayez d’exploiter un binary hébergé à distance.

J’ai essayé la solution acceptée ici et cela ne fonctionne pas (pour moi). Je savais que gdb ajoutait des variables d’environnement et pour cette raison, l’adresse de la stack ne correspondait pas, mais même en supprimant ces variables, je ne peux pas exploiter mon exploit sans gdb (j’ai également essayé le script publié dans la solution acceptée).

Mais en cherchant sur le Web, j’ai trouvé un autre script qui fonctionne pour moi: https://github.com/hellman/fixenv/blob/master/r.sh

L’utilisation est fondamentalement la même que celle du script dans la solution acceptée:

  • r.sh gdb ./program [args] pour exécuter le programme dans gdb
  • r.sh ./program [args] pour exécuter le programme sans gdb

Et ce script fonctionne pour moi.

Une des principales choses que gdb ne fait pas en dehors de gdb est la mémoire zéro. Plus que probablement, quelque part dans le code, vous n’initialisez pas votre mémoire et vous obtenez des valeurs parasites. Gdb efface automatiquement toute la mémoire que vous allouez en masquant ces types d’erreur.

Par exemple, les éléments suivants devraient fonctionner dans gdb, mais pas en dehors:

 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; } 

Essayez d’exécuter votre programme sous valgrind pour voir s’il peut détecter ce problème.

Je suis sur CentOS 6.4 32 bits et j’essaie de provoquer un débordement de mémoire tampon dans un programme … Cependant, lorsque je lance la stack de programmes seule, elle commet des erreurs.

Vous devez également vous assurer que FORTIFY_SOURCE n’affecte pas vos résultats. Le problème seg qui ressemble à FORTIFY_SOURCE pourrait être en cause, car FORTIFY_SOURCE insérera des appels de fonction “plus sûrs” pour se protéger contre certains types de dépassement de mémoire tampon. Si le compilateur peut déduire les tailles de mémoire tampon de destination, la taille est vérifiée et abort() est appelé en cas de violation (c’est-à-dire votre erreur de segmentation).

Pour désactiver FORTIFY_SOURCE à des fins de test, vous devez comstackr avec -U_FORTIFY_SOURCE ou -D_FORTIFY_SOURCE=0 .