Hack The Game Writeup – BSides Algiers 2k15

bsides algiers

Une édition très riche en épreuves, des challenges allant du plus facile au plus difficile, préparés par Asma DIB, Sabrina AMROUCHE, Sofiane TALMAT et Hamza TAHMI.

Web, Cryptographie, Reverse Engeneering, Forensic, mixés à quelques challenges réalistes dont le fameux « Hack The Game » resté sans solution à la fin de cette compétition.

Essayons de voir ensemble la solution à ce challenge.

Pour commencer, deux éléments nous ont été fournis : le client d’un jeu en ligne ainsi qu’un fichier pcap contenant les requêtes échangés entre le client de l’administrateur et le serveur de jeu.

le but de ce challenge était de récupérer le mot de passe de l’administrateur, se connecter au serveur et envoyer un packet « FL » qui permettait de récupérer le flag.

Screenshot from 2015-04-21 17:03:37

Screenshot from 2015-04-21 17:05:58

Screenshot from 2015-04-21 17:07:24

En créant un compte « user:user » et en se connectant sur le serveur (plusieurs fois) on arrive à remarquer ceci :

Screenshot from 2015-04-21 17:18:56

Screenshot from 2015-04-21 17:18:20

Screenshot from 2015-04-21 17:19:15

À chaque connexion, une nouvelle chaine est envoyée par le serveur, nous remarquons également que la chaine qui représente le mot de passe crypté est différente à chaque login, nous pouvons donc déduire que la chaine après le « HC » est la clé qui est utilisée par le client afin de crypter le mot de passe avant son envoi au serveur.

Essayons de fouiner dans le code source du client afin de trouver la routine qui permet de crypter le mot de passe :

en utilisant « flare« 

Screenshot from 2015-04-21 18:55:41

après une petite recherche dans le fichier « loader.flr » (ctrl + f : crypt) voici la fonction qui s’occupe du cryptage du mot de passe :

movieClip 20563 __Packages.ank.utils.Crypt {

    #initclip
      if (!ank.utils.Crypt) {
        if (!ank) {
          _global.ank = new Object();
        }
        if (!ank.utils) {
          _global.ank.utils = new Object();
        }
        _global.ank.utils.Crypt = function () {};

        var v1 = _global.ank.utils.Crypt.prototype;
        _global.ank.utils.Crypt.cryptPassword = function (pwd, key) {
          var v4 = '#1';
          var v5 = 0;
          goto 468;
          for (;;) {
            ++v5;
            label 468:
            if (v5 >= pwd.length) break;
            var v6 = pwd.charCodeAt(v5);
            var v7 = key.charCodeAt(v5);
            var v8 = Math.floor(v6 / 16);
            var v9 = v6 % 16;
            v4 += ank.utils.Crypt.HASH[(v8 + v7 % ank.utils.Crypt.HASH.length) % ank.utils.Crypt.HASH.length] + ank.utils.Crypt.HASH[(v9 + v7 % ank.utils.Crypt.HASH.length) % ank.utils.Crypt.HASH.length];
          }
          return v4;
        };

        ASSetPropFlags(v1, null, 1);
        _global.ank.utils.Crypt.HASH = new Array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_');
      }
    #endinitclip
  }

 

un petit script permettant de cracker le mot de passe de l’admin est nécessaire :

<?php
$chars = explode(' ' ,implode(' ',range('a','z')).' '.implode(' ',range('A','Z')).' '.implode(' ',range('0','9')).' - _');
function cryptPassword($pass, $key)
{
	global $chars;

	$l1 = $l2 = $l3 = $l4 = $l5 = 0; 
	$v1 = $v2 = null;
	$l7 = '';
	for ($l1 = 0; $l1 <= strlen($pass) - 1; $l1++)
	{
	    $l2 = ord(substr($pass, $l1, 1));
	    $l3 = ord(substr($key, $l1, 1));
	    $l5 = ($l2/16);
	    $l4 = ($l2 % 16);
	    $v1 = $chars[(($l5+$l3) % (count($chars))) % (count($chars))];
	    $v2 = $chars[(($l4+$l3) % (count($chars))) % (count($chars))];
	    $l7 = $l7.$v1.$v2;
	}
    
    return $l7;
}
$password = "99WTkkusZVZXMJtsnsecmn";
$decrypted = "";
for ($i=2; $i < strlen($password)+2; $i+=2) { 
	foreach ($chars as $char) {
		if (substr($password, 0,$i) == cryptPassword($decrypted.$char,'ymDMlobPGAIg1F1FrJ2pKQicsJVuKSbL'))
		{
			$decrypted .= $char;
			echo $decrypted."\n";
			break;
		}		
	}
}

Mot de passe admin  : « D0fusBA2k14 »

Maintenant il nous reste plus qu’à nous connecter avec les identifiants « admin:D0fusBA2k14 » et envoyer le packet « FL » pour récupérer le flag :

<?php
function cryptPassword($pass, $key)
{
	$chars = explode(' ' ,implode(' ',range('a','z')).' '.implode(' ',range('A','Z')).' '.implode(' ',range('0','9')).' - _');

	$l1 = $l2 = $l3 = $l4 = $l5 = 0; 
	$v1 = $v2 = null;
	$l7 = '#1';
	for ($l1 = 0; $l1 <= strlen($pass) - 1; $l1++)
	{
	    $l2 = ord(substr($pass, $l1, 1));
	    $l3 = ord(substr($key, $l1, 1));
	    $l5 = ($l2/16);
	    $l4 = ($l2 % 16);
	    $v1 = $chars[(($l5+$l3) % (count($chars))) % (count($chars))];
	    $v2 = $chars[(($l4+$l3) % (count($chars))) % (count($chars))];
	    $l7 = $l7.$v1.$v2;
	}
    
    return $l7;
}

$socket = fsockopen("localhost", 443, $errno, $errstr, 3);

if (!$socket) 
	die("Error #($errno) : $errstr");
$key =  fgets($socket, 36);

fwrite($socket, "1.29.1".chr(10).chr(0)."admin".chr(10).cryptPassword("D0fusBA2k14",substr($key,2)).chr(10).chr(0));
fgets($socket, 27);

fwrite($socket, "FL".chr(10).chr(0));
$flag =  fgets($socket, 40);
echo trim($flag);
fclose($socket);

Flag{c4f6ac9a053d8c1fa0e695b102fdadaf}

Rejoindre la conversation

1 commentaire

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.