web-dev-qa-db-fra.com

Le débordement de tampon fonctionne dans gdb mais pas sans lui

Je suis sur CentOS 6.4 32 bits et j'essaye de provoquer un débordement de tampon dans un programme. Au sein de GDB, cela fonctionne. 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 <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#

Cependant, lorsque j'exécute la pile de programmes seule, les erreurs de segmentation se produisent. Pourquoi est-ce possible?

38
thaweatherman

Le développement des exploits peut entraîner de sérieux maux de tête si vous ne tenez pas suffisamment compte des facteurs qui introduisent non-déterminisme dans le processus de débogage. En particulier, les adresses de pile dans le débogueur peuvent ne pas correspondre aux adresses pendant l'exécution normale. Cet artefact se produit car le chargeur du système d'exploitation place à la fois les variables d'environnement et les arguments du programme avant le début de la pile:

Process layout

Étant donné que votre programme vulnérable ne prend aucun argument, les variables d'environnement sont probablement le coupable. Jument sûr qu'ils sont les mêmes dans les deux invocations, dans le Shell et dans le débogueur. À cette fin, vous pouvez encapsuler 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 renvoyer une liste vide. À ce stade, vous pouvez démarrer le processus de débogage pour trouver l'adresse de pile absolue vers laquelle vous envisagez d'accéder (par exemple, 0xbffffa8b), et codez-le en dur dans votre exploit.

Un autre détail subtil mais important: il y a une différence entre appeler ./stack et /path/to/stack: puisque argv[0] contient le programme exactement comme vous l'avez appelé, vous devez garantir des chaînes d'invocation égales. Voilà pourquoi j'ai utilisé /path/to/stack dans les exemples ci-dessus et pas seulement ./stack et gdb stack.

Lorsque vous apprenez à exploiter avec des vulnérabilités de sécurité de la mémoire, je recommande d'utiliser le programme wrapper ci-dessous, qui fait le gros du travail et assure des décalages de pile é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
94
mavam

L'adresse du pointeur de cadre de pile lors de l'exécution du code dans gdb est différente de son exécution normale. Vous pouvez donc corrompre l'adresse de retour en mode gdb, mais elle peut ne pas fonctionner correctement en mode normal. La raison principale en est que les variables d'environnement diffèrent entre les deux situations.

Comme il ne s'agit que d'une démo, vous pouvez modifier le code victime et imprimer l'adresse du tampon. Changez ensuite votre adresse de retour en offset + adresse de tampon.

En réalité, cependant, vous devez deviner l'adresse de retour ajouter traîneau NOP avant votre code malveillant. Et vous pouvez deviner plusieurs fois pour obtenir une adresse correcte, car votre supposition peut être incorrecte.

J'espère que cela peut vous aider.

7
York

Voici une manière simple d'exécuter votre programme avec des piles identiques dans le terminal et dans gdb:

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

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 changer cela.

Exécutez ensuite votre programme comme ceci (terminal et gdb respectivement):

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, assurez-vous de unsetLINES et COLUMNS.

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

Ces deux exécutions vous donneront des pointeurs identiques vers le haut de la pile, donc pas besoin de manigances de script à distance si vous essayez d'exploiter un binaire hébergé à distance.

5
Aralox

La raison pour laquelle votre débordement de tampon fonctionne sous gdb et segfaults sinon, c'est que gdb désactive la randomisation de la disposition de l'espace d'adressage. Je crois que cela a été activé par défaut dans gdb version 7.

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

show disable-randomization

Et le régler avec

set disable-randomization on

ou

set disable-randomization off
5
LogicG8

J'ai essayé la solution acceptée ici et ça ne marche pas (pour moi). Je savais que gdb a ajouté des variables d'environnement et pour cette raison, l'adresse de la pile ne correspond pas, mais même en supprimant ces variables, je ne peux pas travailler 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 essentiellement 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.

2
RdlP

Je suis sur CentOS 6.4 32 bits et j'essaye de provoquer un débordement de tampon dans un programme ... Cependant, lorsque j'exécute la pile de programmes seule, cela provoque des erreurs.

Vous devez également vous assurer que FORTIFY_SOURCE n'affecte pas vos résultats. La faute de segment sonne comme FORTIFY_SOURCE pourrait être le problème car FORTIFY_SOURCE insérera des appels de fonction "plus sûrs" pour se prémunir contre certains types de débordements de tampon. Si le compilateur peut déduire des tailles de tampon de destination, alors la taille est vérifiée et abort() est appelée en cas de violation (c'est-à-dire votre faute de segmentation).

Pour désactiver FORTIFY_SOURCE pour les tests, vous devez compiler avec -U_FORTIFY_SOURCE ou -D_FORTIFY_SOURCE=0.

1
jww

L'une des principales choses que gdb fait qui ne se produit pas en dehors de gdb est la mémoire nulle. Plus que probablement quelque part dans le code, vous n'initialisez pas votre mémoire et il obtient des valeurs de déchets. Gdb efface automatiquement toute la mémoire que vous allouez en masquant ces types d'erreurs.

Par exemple: ce qui suit devrait 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.

0
chacham15