Catégorie Web
Difficulté Medium
Auteur Eteck#3426

Introduction

A pro player challenge you to a new game. He spent a huge amount of time on it, and did an extremely good score.

Your goal is to beat him by any way

Code source

On tombe sur un jeu navigateur, qui ressemble à un space shooter classique. Il est aussi possible de voir le classement, et le score que nous devons battre

Hello Friend

En regardant le code source, on peut trouver du code javascript :

<script defer="defer" src="/js/runtime.f2fd320ff236045767b9.bundle.js"></script>
<script defer="defer" src="/js/main.0acc8a51228c77e4a908.bundle.js"></script>

Fonctionnement

J’ai fais quelques parties sur le jeu pour comprendre le fonctionnement de l’application. Si on intercepte les requètes avec BURP, on peut remarquer que lorsque notre partie est finie, l’utilisateur envoie une requète POST sur l’endpoint /score avec l’objet suivant :

{
	"score":"4",
	"pseudo":"Francis",
	"signature":1094553691
}

Le serveur nous répond :

{
	"msg":"Score added to the leaderboard",
	"pseudo":"Francis",
	"score":"4"
}

J’essaye donc de renvoyer un requète avec un faux score supérieur à 1337420, le serveur me répond autre chose :

{
	"msg":"Invalid signature"
}

La signature est donc calculé en fonction du score, je vais donc regarder le code source pour voir comment la signature est calculée.

Exploitation

Avant de faciliter la lecture du code, je vais déminifié le code javascript avec la console de firefox :

Hello Friend

Le fichier main.0acc8a51228c77e4a908.bundle.js contient du code à propos de cette signature :

(_0x3f296b = {
	'score': _0x5a84cd[_0x534bdd(3049)](),
  'pseudo': this[_0x534bdd(2984)]
}) ['signature'] = _0x3f306f(_0x5a84cd),

La signature est donc calculé dans la fonction _0x3f306f avec le paramètre _0x5a84cd, qui doit être le score. En cherchant dans le fichier le nom de la fonction, on trouve son contenu :

_0x3f306f = function (_0x359a29) {
	var _0x29faf7 = _0x534bdd,_0x54a291,
  _0x3a1e82 = String(_0x359a29) + _0x29faf7(2675),
  _0x8a3192 = 0;
  if (0 === _0x3a1e82['length']) return _0x8a3192;
  for (_0x54a291 = 0; _0x54a291 < _0x3a1e82[_0x29faf7(288)]; _0x54a291++) _0x8a3192 = (_0x8a3192 << 5) - _0x8a3192 + _0x3a1e82[_0x29faf7(132)](_0x54a291),
	_0x8a3192 |= 0;
	return _0x8a3192;
}

La signature est contenue dans la variable _0x8a3192 qui est renvoyé à la fin de la fonction. Maintenant que j’ai identifié les éléments, je vais pouvoir exploiter cela.

Comme le javascript tourne sur le navigateur de l’utilisateur, il m’est possible d’importer la partie front sur ma machine, sur une serveur web et celui-ci pourra communiquer avec le back si les arrangement sont bien fait.

J’ai utilisé apache pour faire tourner le front :

kali@pc$ cd /var/www/html
kali@pc$ wget http://13.37.17.31:54232/
kali@pc$ sudo service apache2 start

En allant sur mon adresse locale, les fichier s’importent petit à petit. J’ai du renommer le dossier Spaceshooter_filchiers en Spaceshooter_files pour que le front puisse trouver les différentes images.

Pour la dernière étape, il est important de modifier le fichier main.0acc8a51228c77e4a908.bundle.js. Cela va permettre d’interagir avec le back de l’instance, et pas le notre puisque nous n’en avons pas :

  • "/scores" deviendra "http://13.37.17.31:52360/scores"
  • "/assets/shaders" deviendra "http://13.37.17.31:52360/assets/shaders/"

Même si le jeu n’a pas toutes les shaders ou autre ressources, il reste jouable sans erreur majeure.

Nous pouvons maintenant modifier le javascript pour obtenir une signature, je vais changer quelques lignes du fichier main.0acc8a51228c77e4a908.bundle.js. Au lieu de calculer la signature de mon score, je vais demander le calcul d’une signature pour une score de 2000000 :

['signature'] = _0x3f306f(2000000)

Nous ne voyons pas la valeur de la signature avant notre requête, je vais donc ajouter une ligne à la fonction de calcul de signature pour l’afficher de la console du navigateur :

_0x3f306f = function (_0x359a29) {
	...
	console.log(_0x8a3192);
	return _0x8a3192;
}

A la fin d’une partie, lorsque la signature sera calculé, elle sera ensuite affichée :

Hello Friend

On a une signature de -1803026343 pour un score de 2 millions de points.

Flag

Je vais rejouer la requête d’envoi de score avec Burp, en modifiant le corps de la requête avec mon faux score et ma signature :

{
	"score":"2000000",
	"pseudo":"Francis",
	"signature":-1803026343
}

Bingo ! Le serveur nous répond bien avec le flag 🙂

Hello Friend