#+TITLE: Browser Games Aren't an Easy Target #+DATE: <2020-01-10 Fri 18:39> #+TAGS: writeup programming reverse-engineering video-games game-hacking javascript If you're about my age and had a similarly dull upbringing, you probably also have memories of playing video games behind a teacher's back whenever class involved going to some sort of "computer lab." Flash games were the thing when I was in elementary school, and when I was in middle school, I'd bring Quake with me on a flash drive. By the time I was in high school, I'd realized that these opportunities were better spent getting a head start on homework for other classes, but I did have a few friends who still passed the time playing video games. Rather than Flash games or Quake, though, these were browser games using the new-fangled HTML5 canvas. I'd practically forgotten these games existed until someone from my capture-the-flag team mentioned "krunker.io". [[http://iogames.space/][Apparently]] it's one of the more popular ones. It got me thinking about how I'd go about writing cheats for a game in the browser. Writing cheats for CS:GO was a breeze, so why would this be any harder? I had some time to spare over winter break, so I decided to give it a go and see what kind of damage I could do. * Reconnaissance [[https://mitmproxy.org/][mitmproxy]] was pretty much the only tool I used in this project. The first thing I did was hook my browser up to it and load the game to see what kinds of requests it made.[fn:1] [[./mitmproxy-initial.png]] I've truncated it here because the flows that came afterwards were just assets. Right off the bat, we're learning quite a bit about the game's infrastructure. Namely that it has three parts: 1. 'krunker.io', the URL you type into your browser, which is where the code is. 2. 'assets.krunker.io', for serving up textures and models. 3. 'matchmaker.krunker.io', which appears to be some sort of REST API for finding a game. I'm sure that reversing the Matchmaking API would be fun, but there's more fun to be had in messing with the code. ** Code We can see from the flow that the following libraries are loaded: - 'jquery-3.2.1.min.js' - 'jquery-ui.js' - 'howler.min.js' - 'Tween.min.js' - 'nipplejs.min.js' - 'zip.js' - 'zip-ext.js' We all know what jQuery is. After consulting the all-mighty search engine of the interwebs, I figured out that [[https://howlerjs.com/][howler.js]] is an audio library, that [[https://github.com/tweenjs/tween.js/][tween.js]] is a library for animations, and that [[https://yoannmoi.net/nipplejs/][nippleJS]] is a virtual joystick for mobile devices.[fn:2] I was tripped up by 'zip.js' and 'zip-ext.js' initially, thinking that these are where the code is, but it didn't take long to realize that these constitute the [[https://gildas-lormeau.github.io/zip.js/][zip.js]] library for working with ZIP files. Well, if the game code isn't in any of those files, then it has to be inlined in a = #+END_EXPORT ... Even if your new "Anti Cheat" was this :) #+BEGIN_EXPORT html
#+END_EXPORT ----- I'm inevitably going to get flack for cheating in a video game. Before you write me an email, understand that I really don't care. I have a lot more fun reverse engineering games and writing cheats for them than I do playing them. If it makes you feel any better, the only time these cheats see any use is when I'm demonstrating them. Peace out. [fn:1] I didn't notice the request for '/textures/recticle.png' until I was editing this. Sheesh, that's an unfortunate typo. [fn:2] Given that the author is a self-proclaimed "JavaScript and NodeJS developer", I'm not particularly surprised by the embarrassingly childish name. Go ahead, bud. Put that on your CV. [fn:4] Identifiers like ='VuFlFKJOHFGfinUeccOKbaQQPyhjvfYD'= are pretty common in the code. I suspect these are the high-stakes variables that people like me would be grepping for. # ** Matchmaking # GET https://matchmaker.krunker.io/generate-token # referer/origin: https://krunker.io # > Response with # { # "input": "[TOKEN]" # } # GET https://matchmaker.krunker.io/ping-list?hostname=krunker.io # referer/origin: https://krunker.io # > Response with # { # "[server-name]": "[address]" # } # GET https://matchmaker.krunker.io/seek-game # referer/origin: https://krunker.io # GET PARAMS: hostname=krunker.io, region=[REGION], autoChangeGame=false, validationToken=[TOKEN], dataQuery={"v":"Q43rG"]} # > Response with # { # "changeReason": null, # "clientID": "feb0c9f1-128a-4993-a381-bbf7a56318da", # "gameId": "NY:dvn7x", # "host": "[address]", # "port": "[port]" # } # GET https://matchmaker.krunker.io/game-info?game=[id] # referer/origin: https://krunker.io # > Response with info about the game.