Aujourd'hui on s'attaque au challenge "collision" de pwnable.kr.
Etape 1: Récupérer le code source et le comprendre
#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
// Creation d'un fonction de hachage
unsigned long check_password(const char* p){
int* ip = (int*)p; // Declare un tableau de
// pointeur de type entier sur la string
// Chaque pointeur contient 4 octet de la string
// Il y a 5 morceaux car
// 5 morceaux de 4 octets = 20 octets ou 20 caractères
int i;
int res=0;
// Parcour la string
for(i=0; i<5; i++){
// Pour chaque octet la valeur de celui ci est ajouté à l'entier "res"
res += ip[i];
}
return res;
}
int main(int argc, char* argv[]){
if(argc<2){
printf("usage : %s [passcode]\n", argv[0]);
return 0;
}
if(strlen(argv[1]) != 20){
printf("passcode length should be 20 bytes\n");
return 0;
}
if(hashcode == check_password( argv[1] )){
system("/bin/cat flag");
return 0;
}
else
printf("wrong passcode.\n");
return 0;
}
Au cas où vous seriez confus, ce qui se passe, c'est que le programme prend le code d'accès donné qui fait 20 octets de long et le divise en 5 morceaux (chaque morceau fait 4 octets) puis il additionne la valeur décimale des 5 morceaux et renvoie cette valeur.
Etape 2: Exploitation
On peut se dire que la solution est simple il suffit de diviser le hashcode par 5 et de le passer en argument au programme. Le seul hic c'est que le hashcode en décimal vaut 568134124
, qui n'est pas divisible par 5 (car il ne finit ni pas zéro ni par 5).
La solution consiste à passer en argument quelque chose comme ça
568134124 = 142033530 * 4 + 4
568134124 = 568134120 + 4
NB: On peut tout fait passer 5 valeurs différentes les unes des autres mais j'essaye de rester simple dans mon explication.
C'est à dire 4 octets contenant la valeur 142033530
et un octet contenant la valeur 4
. De cette façon on obtient bien 5 octets qui une fois additionner vaudront 568134124
.
Sauf que ça ne peut pas marcher. Pourquoi ? Parce que la dernière valeur va être encodé comme suit: 0x4
soit une fois convertit en little endian : \x04\x00\x00\x00
Ce qui en soit ne pose pas de problème au programme mais par contre le shell ne nous laissera pas faire.

Il faut donc revoir notre stratégie, il faut faire en sorte que les valeurs ajoutés ne contiennent pas de null byte.
Il y a une multitude de chose qui peuvent valoir le hashcode (c'est d'ailleurs grâce à ça qu'on peut faire une hash collision)
Par exemple:
568134124 = 113626824 * 4 + 113626828
Ce qui une fois convertit en hexa donne
from pwn import *
print(p32(113626824) * 4 + p32(113626828))
\xc8\xce\xc5\x06\xc8\xce\xc5\x06\xc8\xce\xc5\x06\xc8\xce\xc5\x06\xcc\xce\xc5\x06
Comme on le voit, plus de null bytes !
Testons ça !

Et bingo !
Il ne reste plus qu'a reproduire ça sur le serveur de pwnable.kr !
Bonus:
On peut automatiser cette exploitation via un script python et la librairie pwntools
#!/usr/bin/python
from pwn import *
from pprint import pprint
shell = ssh('col' ,'pwnable.kr' ,password='guest', port=2222)
payload = p32(113626824)*4 + p32(113626828)
process = shell.process(executable='./col', argv=['col',payload])
log.success(process.recv())

Social et Media
Comme toujours je suis disponible sur Twitter et cie, si vous avez des questions, des remarques, des suggestions etc. N’hésitez pas !
Twitter: @GhostAgs
Discord: hackraw