Niveau: Débutant
Cet article est le premier d’une série dédié à l’exploitation de binaire (plus communément nommé pwn).
Vous vous demandez peut-être ce que c’est ? Eh bien c’est l’art d’exploiter des vulnérabilités liées à une mauvaise utilisation d’un langage de bas-niveau comme le C/C++
(note: Parfois on dit que le pwn est toute exploitation d’une faille liée à une mauvaise utilisation d’un langage quelconque comme les injections de code ou autre mais on va rester sur la première définition).
Une des vulnérabilité bien connue de cette dicipline est le buffer overflow.
Aujourd’hui ont va essayer de comprendre les bases de cette vulnérabilité. Et au fil des parties de ce tutoriel, nous allons exécuter nos premiers exploits. C’est parti!
Quelque Bases pour Contrôler EIP
Un peu d’assembleur
Ok, il va falloir voir quelques bases. Quand vous codez un programme en C ou en C++ et que vous le compilez avec gcc en utilisant la commande:
gcc -o programme programme.c
Eh bien savez-vous comment fait gcc pour transformer votre code en C vers du langage machine exécutable par l’ordinateur ?
Cela ce fait en 3 étapes:
d’abord le code en C est transformé en langage assembleur (qui est le langage le plus bas niveau après le binaire), ensuite le code assembleur est traduit en binaire, et enfin l’exécutable est « linké », c’est à dire que les liens sont fais avec les libraires (par exemple si votre code fait un printf il est nécessaire que votre programme sois attaché à la libs.so.6 qui contient la fonction printf).
Très bien maintenant voyons les bases de l’assembleur, langage qui est incontournable dans le domaine de l’exploitation. Vous verrez pourquoi plus tard.
Regardons d’abord à quoi ressemble l’assembleur:
section .text
global _start
_start:
push rdx
mov rdi, 0x4444444444444444 ; v_addr
mov rsi, 0x5555555555555555 ; len
mov rdx, 0x7 ; RWX
mov rax, 10 ; mprotect0x80483dc
syscall
mov rcx, 0x2222222222222222
mov rsi, 0x3333333333333333
mov rdx, 0x6666666666666666 ; random_int
mov rdi, rsi
jmp _loop
_loop:
cmp rcx, 0x0
je _end
lodsb
not al
xor al, dl
stosb
loop _loopon va passer sur
_end:
pop rdx
mov rax, 0x1111111111111111
jmp rax
Il est normal que vous ne compreniez pas grand chose ! C’était juste pour vous montrer à quoi ça ressemble. Donc vous voyez votre code est formé d’instruction comme cmp et call ect .. On va voir les instruction de base:
; Note, en assembleur tout ce qui ai derrière un point virgule est un commentaire
call 0x80483dc; Appelle la fonction à l'addresse 0x80483dc
push 0x0; met la valeur 0x0 sur la stack
pop ebx; met ce qu'il y a en haut de la stack dans ebx
mov eax, 0x1; met 0x1 dans eax
Ça sera tout ! Pas bien compliqué (vous verrez encore beaucoup d’assembleur si vous continuer le pwn ).
Les registres x86 et 64bits
Maintenant c’est quoi eax, ebx ?
Eh bien ce sont ce qu’on nomme des registres, des sortes de blocs ou l’on stocke de petites choses (adresse, nombre, ect …).
Pour un processeur x86 32 bits, vos registres eax, ebx, ecx, edx, ebp, esp, eip et enfin edi ont une taille de 32 bits (soit 4 bytes) .
Il existe d’autres registres qui ne vont pas nous intéresser maintenant.
Dernier petit truc avant de voir à quoi correspondent ces registres: en 64 bits vous aurez les mêmes registres sauf qu’ils feront 64 bits et que à la place du « e » vous aurez « r », (rbx, rip, par exemple).
Ok, passons au choses sérieuses, que contient chacun de ces registres ?
eax -> registre accumulateur (accumulator register). Utilisé pour les opérations arithmétiques et le stockage de la valeur de retour des appels systèmes.
ebx -> registre de base (base register). Utilisé comme pointeur de donnée (située dans DS en mode segmenté).
ecx -> registre compteur (counter register)
edx -> registre de données (data register). Utilisé pour les opérations arithmétiques et les opérations d'entrée/sortie.
ebp -> (Extended Base Pointer) pointeur de base
/!\ important
esp -> Pointe vers le haut de la stack (ou pile), retenez bien !
eip -> Très important, pointe vers la prochaine instruction à executer
Les segments de mémoire
Pour l’instant, étant sur l’exploitation sur des systèmes Linux ont va plutôt s’intéresser au différents segments d’un binaire ELF (ou Executable and Linkable Format) qui est un fichier exécutable sous Linux, on va prendre un petit schéma:

Hein ? Mais c’est quoi .text .rodata etc ??
Eh bien c’est simple ! C’est tout simplement nos segments, voyons ce que contient chacun:
- .data: Segments ou sont stocké les variable globales (on verra plus tard)
- .bss: Contient les variable statique
- .text: Notre code
Ce n’est peut-être pas assez clair, nous allons donc prendre un petit programme pour illustrer cela:
#include <stdio.h>
#include <stdlib.h>
int a;
static int b;
int main(int argc; char **argv) {
int c = 0;
printf("Bonjour ! \n");
}
Eh bien ici nous avons:
- a et b qui sont dans .bss
- c qui est mis sur la stack (on verra plus bas)
- notre programme (c’est a dire le main) qui est dans .text
Petite remarque, les « include » et les « define » font parti de ce que l’on nomme préprocesseur quand notre code est compilé ces parties sont effacées.
Regardons de plus près ce que ça donne. Ça nous permettra aussi au passage de voir comment désassembler un programme:
#define NOMBRE 15
int main() {
int a = NOMBRE;
}
Compilons donc le code:
[email protected]:~/kali$ gcc -o code code.c
[email protected]:~/kali$ file code
code: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=eaac74af1d2565323c1ee8330fff4a208511831f, not stripped
Essayons de décompiler avec objdump qui est un désassembler linéaire
[email protected]:~/kali$ objdump -M intel -d code
code: format de fichier elf64-x86-64
Déassemblage de la section .init :
0000000000400390 <_init>:
400390: 48 83 ec 08 sub rsp,0x8
400394: 48 8b 05 5d 0c 20 00 mov rax,QWORD PTR [rip+0x200c5d] # 600ff8 <_DYNAMIC+0x1d0>
40039b: 48 85 c0 test rax,rax
40039e: 74 05 je 4003a5 <_init+0x15>
4003a0: e8 2b 00 00 00 call 4003d0 <[email protected]+0x10>
4003a5: 48 83 c4 08 add rsp,0x8
4003a9: c3 ret
Déassemblage de la section .plt :
00000000004003b0 <[email protected]>:
4003b0: ff 35 52 0c 20 00 push QWORD PTR [rip+0x200c52] # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
4003b6: ff 25 54 0c 20 00 jmp QWORD PTR [rip+0x200c54] # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
4003bc: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
00000000004003c0 <[email protected]>:
4003c0: ff 25 52 0c 20 00 jmp QWORD PTR [rip+0x200c52] # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
4003c6: 68 00 00 00 00 push 0x0
4003cb: e9 e0 ff ff ff jmp 4003b0 <_init+0x20>
Déassemblage de la section .plt.got :
00000000004003d0 <.plt.got>:
4003d0: ff 25 22 0c 20 00 jmp QWORD PTR [rip+0x200c22] # 600ff8 <_DYNAMIC+0x1d0>
4003d6: 66 90 xchg ax,ax
Déassemblage de la section .text :
00000000004003e0 <_start>:
4003e0: 31 ed xor ebp,ebp
4003e2: 49 89 d1 mov r9,rdx
4003e5: 5e pop rsi
4003e6: 48 89 e2 mov rdx,rsp
4003e9: 48 83 e4 f0 and rsp,0xfffffffffffffff0
4003ed: 50 push rax
4003ee: 54 push rsp
4003ef: 49 c7 c0 60 05 40 00 mov r8,0x400560
4003f6: 48 c7 c1 f0 04 40 00 mov rcx,0x4004f0
4003fd: 48 c7 c7 d6 04 40 00 mov rdi,0x4004d6
400404: e8 b7 ff ff ff call 4003c0 <[email protected]>
400409: f4 hlt
40040a: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
0000000000400410 <deregister_tm_clones>:
400410: b8 37 10 60 00 mov eax,0x601037
400415: 55 push rbp
400416: 48 2d 30 10 60 00 sub rax,0x601030
40041c: 48 83 f8 0e cmp rax,0xe
400420: 48 89 e5 mov rbp,rsp
400423: 76 1b jbe 400440 <deregister_tm_clones+0x30>
400425: b8 00 00 00 00 mov eax,0x0
40042a: 48 85 c0 test rax,rax
40042d: 74 11 je 400440 <deregister_tm_clones+0x30>
40042f: 5d pop rbp
400430: bf 30 10 60 00 mov edi,0x601030
400435: ff e0 jmp rax
400437: 66 0f 1f 84 00 00 00 nop WORD PTR [rax+rax*1+0x0]
40043e: 00 00
400440: 5d pop rbp
400441: c3 ret
400442: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
400446: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
40044d: 00 00 00
0000000000400450 <register_tm_clones>:
400450: be 30 10 60 00 mov esi,0x601030
400455: 55 push rbp
400456: 48 81 ee 30 10 60 00 sub rsi,0x601030
40045d: 48 c1 fe 03 sar rsi,0x3
400461: 48 89 e5 mov rbp,rsp
400464: 48 89 f0 mov rax,rsi
400467: 48 c1 e8 3f shr rax,0x3f
40046b: 48 01 c6 add rsi,rax
40046e: 48 d1 fe sar rsi,1
400471: 74 15 je 400488 <register_tm_clones+0x38>
400473: b8 00 00 00 00 mov eax,0x0
400478: 48 85 c0 test rax,rax
40047b: 74 0b je 400488 <register_tm_clones+0x38>
40047d: 5d pop rbp
40047e: bf 30 10 60 00 mov edi,0x601030
400483: ff e0 jmp rax
400485: 0f 1f 00 nop DWORD PTR [rax]
400488: 5d pop rbp
400489: c3 ret
40048a: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
0000000000400490 <__do_global_dtors_aux>:
400490: 80 3d 99 0b 20 00 00 cmp BYTE PTR [rip+0x200b99],0x0 # 601030 <__TMC_END__>
400497: 75 11 jne 4004aa <__do_global_dtors_aux+0x1a>
400499: 55 push rbp
40049a: 48 89 e5 mov rbp,rsp
40049d: e8 6e ff ff ff call 400410 <deregister_tm_clones>
4004a2: 5d pop rbp
4004a3: c6 05 86 0b 20 00 01 mov BYTE PTR [rip+0x200b86],0x1 # 601030 <__TMC_END__>
4004aa: f3 c3 repz ret
4004ac: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
00000000004004b0 <frame_dummy>:
4004b0: bf 20 0e 60 00 mov edi,0x600e20
4004b5: 48 83 3f 00 cmp QWORD PTR [rdi],0x0
4004b9: 75 05 jne 4004c0 <frame_dummy+0x10>
4004bb: eb 93 jmp 400450 <register_tm_clones>
4004bd: 0f 1f 00 nop DWORD PTR [rax]
4004c0: b8 00 00 00 00 mov eax,0x0
4004c5: 48 85 c0 test rax,rax
4004c8: 74 f1 je 4004bb <frame_dummy+0xb>
4004ca: 55 push rbp
4004cb: 48 89 e5 mov rbp,rsp
4004ce: ff d0 call rax
4004d0: 5d pop rbp
4004d1: e9 7a ff ff ff jmp 400450 <register_tm_clones>
00000000004004d6 <main>:
4004d6: 55 push rbp
4004d7: 48 89 e5 mov rbp,rsp
4004da: c7 45 fc 0f 00 00 00 mov DWORD PTR [rbp-0x4],0xf
4004e1: b8 00 00 00 00 mov eax,0x0
4004e6: 5d pop rbp
4004e7: c3 ret
4004e8: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
4004ef: 00
00000000004004f0 <__libc_csu_init>:
4004f0: 41 57 push r15
4004f2: 41 56 push r14
4004f4: 41 89 ff mov r15d,edi
4004f7: 41 55 push r13
4004f9: 41 54 push r12
4004fb: 4c 8d 25 0e 09 20 00 lea r12,[rip+0x20090e] # 600e10 <__frame_dummy_init_array_entry>
400502: 55 push rbp
400503: 48 8d 2d 0e 09 20 00 lea rbp,[rip+0x20090e] # 600e18 <__init_array_end>
40050a: 53 push rbx
40050b: 49 89 f6 mov r14,rsi
40050e: 49 89 d5 mov r13,rdx
400511: 4c 29 e5 sub rbp,r12
400514: 48 83 ec 08 sub rsp,0x8
400518: 48 c1 fd 03 sar rbp,0x3
40051c: e8 6f fe ff ff call 400390 <_init>
400521: 48 85 ed test rbp,rbp
400524: 74 20 je 400546 <__libc_csu_init+0x56>
400526: 31 db xor ebx,ebx
400528: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
40052f: 00
400530: 4c 89 ea mov rdx,r13
400533: 4c 89 f6 mov rsi,r14
400536: 44 89 ff mov edi,r15d
400539: 41 ff 14 dc call QWORD PTR [r12+rbx*8]
40053d: 48 83 c3 01 add rbx,0x1
400541: 48 39 eb cmp rbx,rbp
400544: 75 ea jne 400530 <__libc_csu_init+0x40>
400546: 48 83 c4 08 add rsp,0x8
40054a: 5b pop rbx
40054b: 5d pop rbp
40054c: 41 5c pop r12
40054e: 41 5d pop r13
400550: 41 5e pop r14
400552: 41 5f pop r15
400554: c3 ret
400555: 90 nop
400556: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
40055d: 00 00 00
0000000000400560 <__libc_csu_fini>:
400560: f3 c3 repz ret
Déassemblage de la section .fini :
0000000000400564 <_fini>:
400564: 48 83 ec 08 sub rsp,0x8
400568: 48 83 c4 08 add rsp,0x8
40056c: c3 ret
[email protected]:~/kali$
Hein ? C’est quoi ça ? Faudrait que je vous en parle mais là c’est encore trop tôt ce qui nous intéresse c’est « main », avant il y’a une technique plus pratique que voici:
[email protected]:~/kali$ gdb code
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from code...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x00000000004004d6 <+0>: push rbp
0x00000000004004d7 <+1>: mov rbp,rsp
0x00000000004004da <+4>: mov DWORD PTR [rbp-0x4],0xf
0x00000000004004e1 <+11>: mov eax,0x0
0x00000000004004e6 <+16>: pop rbp
0x00000000004004e7 <+17>: ret
End of assembler dump.
(gdb)
GDB est l’acronyme de GNU Debugger, un outil très important qu’on va apprendre à utiliser, patience !
Comme vous le voyez dans notre main:
0x00000000004004d6 <+0>: push rbp
0x00000000004004d7 <+1>: mov rbp,rsp
0x00000000004004da <+4>: mov DWORD PTR [rbp-0x4],0xf
0x00000000004004e1 <+11>: mov eax,0x0
0x00000000004004e6 <+16>: pop rbp
0x00000000004004e7 <+17>: ret
Vous rappelez-vous de rbp ? Non? retournez en haut !
Pour les autres, continuons… que fais notre programme ?
- push rbp, met rbp sur la stack
- mov rbp,rsp, met rsp dans rbp
- mov DWORD PTR [rbp-0x4],0xf met 0xf (15 en haxadécimal) dans rbp
- mov eax,0x0 met 0 dans eax
- pop rbp met ce qu’il y a dans le haut de la stack dans rbp
- ret quitte main
Comme vous le voyez on a pas de define (d’ailleurs ont n’a pas de nom de variable non plus) mais finalement on a bien 15 dans rbp !
On va remettre tout ça d’avantage au clair (il est important que vous compreniez bien !), prenons ce petit programme:
#include <stdio.h>
int main(void) {
return 0;
}
Très bien, Compilons cela :
gcc test.c -o test
Et regardons la taille de chaque session via la commande size:
$ size test
text data bss dec hex filename
1073 560 8 1641 669 test
Nous allons changer encore un peu notre code en rajoutant une variable globale !
#include <stdio.h>
int variableglobale;
int main(void) {
return 0;
}
$ size test
text data bss dec hex filename
1073 560 12 1641 669 test
Comme vous le remarquez bss est passé de 8 octets à 12 octets ! Notre variable globale est stockée dans bss !
#include <stdio.h>
int main(void) {
static int variablestatique;
return 0;
}
size test
text data bss dec hex filename
1073 564 8 1641 669 test
Ahah ! Data passe de 560 à 564 notre variable statique est mise dans data
#include <stdio.h>
int global = 1;
int main(void) {
return 0;
}
size test
text data bss dec hex filename
1073 564 8 1641 669 test
Comme vous le remarquez une variable globale si elle est initialisée est mise dans data! Ça ira, j’espère que vous avez maintenant compris !
Comment fonctionne la mémoire ?
Dans cette partie on va pas parler de votre mémoire physique (Disque dur ou SSD) mais plutôt de la mémoire RAM et comment celle-ci est gérée par votre système d’exploitation ?
Nous allons nous attaquer d’abord à la mémoire virtuelle ! Un schéma vaut toujours mieux que de longs discours !

Un processus qui tourne sur une machine nécessite de la mémoire, et dans un ordinateur, la quantité de mémoire est limitée. Il faut donc que les processus aillent chercher de la mémoire disponible pour pouvoir travailler.
Mais maintenant plusieurs processus s’exécutent en même temps. Que se passerait-il si deux processus voulaient accéder, à la même zone mémoire ? Et si jamais un processus écrivait dans une zone mémoire, puis qu’un autre processus écrase cette même zone mémoire avec ses propres données, alors le premier processus pensera retrouver ses données, mais il trouvera en fait les données du deuxième processus. Cela pose un très très gros problème ! !
C’est là qu’intervient une fonctionnalité majeure de votre système d’exploitation qui va résoudre le problème en allouant à chaque processus une plage de mémoire virtuelle (de 4Go sur les système 32 bits et de 8Go sur les systèmes 64 bits) chaque processus pourra utiliser les adresses mémoires dont il a besoin sans se soucier des autres processus, le noyau du système d’exploitation se débrouillera pour faire le lien entre la mémoire virtuelle et la mémoire réelle !
La Stack et la Heap
Nous allons maintenant passer à quelque chose de très important ! C’est quoi la stack et la heap (pile et tas):
La heap (ou tas pour les français) est manipulable par le programmeur. C’est la partie de la mémoire dans laquelle sont écrites les zones mémoires allouées dynamiquement (malloc() ou calloc()). Cette zone mémoire n’a pas de taille fixe. Elle augmente et diminue en fonction de ce qu’on lui demande, on peut réserver ou supprimer des blocs via des algorithmes d’allocation ou de libération pour une utilisation future. Plus la taille du tas augmente, plus les adresses mémoires augmentent, et s’approchent des adresses mémoires de la pile. La taille des variables dans le tas n’est pas limitée (sauf limite physique de la mémoire), contrairement à la pile.
Les variables stockées dans le tas sont accessibles partout dans le programme avec des pointeurs (vous avez sûrement vu ça quand vous avez appris le C) .
La stack (Pile en français) possède également une taille variable, mais plus sa taille augmente, plus les adresses mémoires diminuent, en s’approchant du haut du tas. En gros la stack grandi vers le bas. C’est ici qu’on retrouve les variables locales des fonctions . La stack frame d’une fonction est une zone mémoire, dans la pile, dans laquelle toutes les informations, nécessaires à l’appel de cette fonction, sont stockées. S’y trouvent également les variables locales de la fonction. Retenez cela très important.
Approfondir un peu la notion de Stack
Cela sera très important pour la suite !
Commençons par LIFO.
Hein ? Quoi LIFO
Rien de bien compliqué et on l’a déjas un peu vu , LIFO signifie Last In, First Out . C’est à dire que le dernier truc mis sur la stack est le premier qu’on va sortir on la vu notamment à travers pop et push
On fait un pop rax; rax est sur la stack
On fait un push rbp; on a rax dans rbp (rax est retiré de la stack)
En fait non, c’est pas totalement ça, rax reste à la même adresse sauf que maintenant rsp (qui est le stack pointer pointant vers le haut de la stack) pointe maintenant vers une adresse en plus bas.
Maintenant parlons de stack frame c’est simple et on doit juste savoir que c’est ce qui permet de passer le contexte d’exécution lorsqu’on appelle une fonction, en 32 bits tout les arguments d’une fonction sont passé par la stack
Dernier petit points vous vous rappelez les adresses de la stack diminuent ? On va expliquer ça un peu

tiré de Hackndo, blog de pixis.
Vous voyez la pile en haut ? imaginons que la première adresse de la stack après le mapping du noyau est 0xfffbbbbb par exemple et bien on va dire que c’est la plus basse (pourtant elle est plutôt vers le haut en fait !). En effet la stack grandie en se rapprochant de plus en plus de 0x00000000, c’est a dire l’adresse la plus basse
L’Overflow enfin !
Enfin, nous arrivons à la partie de l’exploitation ! Prenons un programme pour l’exemple !
#include <stdio.h>
int main() {
char buffer[100];
int a;
scanf("%s", buffer);
}
Le code à l’air totalement normal, vous avez sûrement du utiliser la fonction « scanf « dans votre apprentissage du langage C. Mais et si on regarde à quoi ressemble la stack dans cet exemple ?? Eh bien suivez moi bien c’est très important !
[ buffer (100) ][int a][saved ebp][saved eip]
Vous vous demandez peut être c’est quoi saved ebp et saved eip ? Bon en fait on s’en fou un peu de saved ebp ce qui nous intéresse c’est saved eip, vous vous rappelez ce que contient eip ? Oui c’est ça ! L’adresse de la prochaine instruction a exécuter 🙂 Et si on changeait cette adresse on pourrait exécuter n’importe quoi !
Mais comment changer cette valeur ? Et bien c’est très simple ! Vous voyez scanf ne vérifie pas le nombre de caractères qu’elle reçois ! Prenons un autre programme :
#include <stdio.h>
int fonctionadmin() {
printf("Vous avez réussi à sauter sur la fonction administrateur ! \n");
}
int vuln() {
char buffer[10];
scanf("%s", buffer);
}
int main() {
vuln()
}
Dans ce cas nous avons la stack qui correspond plus ou moins à ça:

Si lors du scanf on donnait une valeur trop grande par exemple plusieurs « A » la stack ressemblera à cela:

Crédit: Ces deux schémas sont tiré de Hackndo, blog de pixis
Conclusion
Et voila EIP à été overflow ! A correspond à 0x41 en ASCII, EIP va donc sauter sur 0x41414141 qui n’est sûrement pas une valeur valide, le programme va donc nous retourner un segmentation fault ! Mais si on changeait les A par une adresse valide on pourrait sauter n’importe ou et notamment sur la fonction fonctionadmin()
C’est donc fini pour le coté théorique, on verra la pratique dans la deuxième partie. On se retrouve donc au prochain article!
À bientôt!
10 thoughts on “Overflow ? Comment ça marche ?”
Oui en fait j’ai éssayé ceci :
python -c « print ‘A’*24+’@_fonctionadmin' » , malheuresement ça m’affiche une erreur de segmentation , …
au fait , j’ai bien debuger le code , esp diminue de 64 bits suivant votre shema
Je ne suis pas un grand spécialiste de ce genre de détails mais :
Tu dis que la pile grandit vers le bas. Que le tas grandit vers le bas.
Mais en réalité est ce que ce ne serait pas plutôt :
Le tas grandit vers le bas, la pile grandit vers le haut ? (Je suppose que c’est cela qui va permettre un écrasement de données et générer nos vuln enfin je suppose hein)
Merci pour cet océan de connaissance partagé avec nous 😀 J’apprends plein de choses.
Quelques coquilles orthographiques, mais je ne ferais l’affront à personne de te corriger en public, si tu veux, MP moi – Sinon pas grave – cela me va tout aussi bien.
Petit détail qui semble important : La Stack et la Heap
Tu as un smiley dans ton paragraphe où tu dis que « Stack » = « Tas », je découvre mais d’après ce que j’ai compris le stack serait plutôt la pile, cela pourrait foutre le bordel dans la tête des gens 😉
Merci encore X_X Je me suis gavé avec ton tuto 🙂
Merci Dnl5. Bien vu, Stack = Pile et Heap = Tas!
L’article avait grand besoin de relecture..
Tu vois je te l’avais dis que ça serait plus rapide de le poster ici 😉
Bonjour, comment faites-vous pour afficher le stack ?
> Pour un processeur 32 bits vos registres eax, ebx, ecx, edx, ebp, esp, eip et enfin edi ont une taille de 8 bits sois un byte (ou octet).
C’est pas 32 bits (soit 4 bytes) plutôt ? 🙂
C’est bien ça c’est maintenant corrigé. Merci FlOZz.
« Pour un processeur 32 bits vos registres eax, ebx, ecx, edx, ebp, esp, eip et enfin edi ont une taille de 8 bits sois un byte (ou octet). Il existe d’autres registres qui ne vont pas nous intéresser maintenant. Dernier petit truc avant de voir à quoi corresponde ces registre: en 64 bits vous aurez les même registre sauf qu’ils feront 16 bits et que à la place due vous aurez r, (rbx, rip, par exemple). »
Il faudrait corriger ces erreurs qui rendent les explications difficiles à comprendre pour les non-connaisseurs. Les registres x86 32 bits font… 32 bits et non pas 8. Et dans l’architecture 64 bits ils font… 64 bits et non pas 16. Certes, EAX contient aussi AX (16 bits), AL et AH (8 bits), mais c’est un registre 32 bits. D’ailleurs il n’est pas très cohérent d’écrire `mov rax, 0x1111111111111111` avant d’expliquer que RAX est un registre 16 bits.
Merci Renaud d’être passé. Voyons si l’explication est plus claire maintenant. Est-ce que c’est validé?