This page is at least 15 years old !
Alteration de reqûetes cryptées avec flash
Ou comment en faire beaucoup trop pour fausser les scores sur
les jeux.
Dans les sites de jeux en flash (que je ne fréquente
plus depuis au moins 2002), la transmission des scores depuis les applications
flash se font souvent en clair, par simple GET ou POST. Dans les sites payants, avec des concours pour gagner
des lots, ou sur les jeux produits par des studios assez gros, les scores
sont parfois cryptés pour décourager cette attaque simple. |
Je prendrais exemple ici sur le jeu "Paf le Chien"
d'Adictiz, trouvable sur Facebook, et sur lequel plusieurs de mes connaissances
s'étaient acharnées pour dépasser le kilomètre. Visiblement, les données ne sont pas transmises
en clair. L'en-tête n'indique rien de spécial, mais le jeu
de caractères utilisés pour coder l'information montre que
le tout est en Base64. Le décodage Base64 vers Hexa ne donne rien de concluant.
On aurait donc à faire a du cryptage, qui serait pris en charge
directement par l'application flash. |
![]() |
La liste des scripts dévoile une fonction interessante:
HttpCrypt, qui n'aurait pas pu être mieux nommée. Quand le jeu démarre (dans Stratosphere.as), la fonction HttpCrypt est appellée, où on voit que le jeu a absolument besoin de g.php pour transmettre ses données: this.oHC = new HttpCrypt(this.sitePath + "g.php"); En éxaminant rapidement la suite du script, on reconnaît la fonction appellée une fois le lancer terminé: private function finDuJeu() A la fin de cette fonction, on trouve: if (this.distance > 10)
{ La distance n'est transmise que si elle excède
10m. Elle est arrondie (distance est en virgule flottante dans tous les
scripts du jeu). |
La fonction SetVar se trouve dans HttpCrypt.as et assemble simplement les deux arguments qu'on lui passe. public function SetVar(param1:String,
param2:String) : void { outData sera donc sous la forme "score:xxx;user:yyy;" juste avant que Send() soit apellé dans finDuJeu(). Facebook fournit une variable fb_sig_user, qui est un
identifiant numérique pour chaque utilisateur. Ici j'utiliserais
un identifiant quelconque, appartenant peut être déjà
à quelqu'un. La fonction Send() dans HttpCrypt.as appèle encrypt() avec outData comme argument. private function encrypt(param1:String)
: String { On voit ici aussi clairement les étapes pour coder
les données du POST. D'abord outData est converti en un tableau
d'octets, la fonction de crypto est initialisée par l'appel de
prepare(), et la valeur est retournée codée en Base64. |
La fonction prepare() indique tout aussi clairement la méthode de cryptage, sa clé et son mode: private function prepare() :
ICipher { C'est là où on peut découvrir toute la grandeur de l'imagination des dévelopeurs, avec notament la clé de cryptage, ici secretKey (véridique, quoique pas si étonnant).
Leur chaîne outData est alors cryptée avec
Blowfish en mode ECB, avec la clé "merdemerde".
A partir de là, on a toutes les informations necéssaires
pour fausser les données du POST. |
L'identifiant Facebook est trouvable dans à peu
près toutes leurs requêtes de pages, surtout quand on commente
quelque chose. C'est un nombre entre 6 et 9 chiffres. La petite difficulté est de pouvoir utiliser Blowfish
avec le bon mode et avec les données qu'on veut. function bfcrypt($donnees,
$cle) { function str2hex($string)
{ |
(A partir d'ici, les données ont été modifiées pour ne pas qu'on retrouve mon identifiant, alors c'est normal si les données ne sont pas bonnes, l'important c'est que ça puisse être compris). Pour vérifier que la méthode est bonne,
on peut essayer de retomber sur la valeur de outData à partir des
données du POST. Par exemple, avec une distance de 62m, le jeu
a envoyé: Il suffit alors d'utiliser le script PHP pour créer les données que l'on veut envoyer à la place du vrai score: echo str2hex(bfcrypt("score:4597;user:1139855929;", "merdemerde")); Donnera une suite d'octets qu'il faudra passer en Base64
par le biais d'un convertisseur en ligne (ce qui peut aussi être
fait via PHP), qu'il faudra ajuster pour éviter les caractères
spéciaux. D103Gh3O9Pj6qxOA89x9PfhSatbwvx2xX5r3nXqbjvU%3D Malheureusement, je ne peut pas montrer le résultat final car le jeu transmet ces données seulement vers adictiz.com, et pas vers Facebook. Facebook prend le score en clair, mais avec un checksum, dont on ne peut pas connaître l'algorithme de calcul... Ca ne devrait par contre pas rater pour d'autres sites. Bon kikoololisme. |