2

If I wanted to make a bot that plays/issues automatic actions/moves in a online browser game, whose communication is realized over HTTP1/1 and WebSocket (https and wws respectively), all TLS encrypted, what approach would you take?

Additionally the following constraints need to be considered:

  • The bot should work while the player is actually playing. That means: Without any real action by a human, the bot won't do anything at all. But every action taken by the player should be modified on the fly by the bot, which calculates a better move/action and updates the packets accordingly (On which layer [TCP, HTTP, WebSocket this happens becomes important on the bottom approaches). Hence the size of the TCP packets won't change, but the checksum (and other fields that depend on the payload) may so.
  • The source of the bot calulated actions is a local process. This means we need to obtain the data from a local process and can't integrate it into the browser process space (for example). We can interact with the local process in any possible way, such as IPC, sockets (client-server-architecture). But for the sake of simplicity I won't inject the process into the broser process space, since it seems hard and I don't know how to do it.

I have compiled the following list of procedures that differentiate in the layer or abstraction in where they alter the flow of communication of the game:

  1. A high level approach would be to inject custom javascript into the DOM of a running browser session. This piece of javascript then connects to a local server (e.g. to a simple server listening on localhost:8888) that responses with a bot calculated move when requesting with the current game action history.

    • Advantages: Comparably easy implementation (javascript is easy to code in). Works for all platforms and all browsers, because javascript is universally runnable.
    • Drawbacks: Maybe we can't build a connection to localhost due to the same-origin policy (Can we?) This would render this approach impossible, since we absolutely need a way to communicate with the local program.
  2. Another high level technique would be to write a custom browser extension that intercepts the browser game traffic and injects bot calculated traffic.

    • Advantages: We don't need to hassle with SSL/TLS decryption because our application is executed in the browser process. Furthermore it must be somehow possible to communicate with a local process that supplies the extension with bot knowledge.
    • Disadvantages: Platform and browser dependent code. When going down that road, I would need to write platform independent C code for chromium and firefox (Because I consider these two browsers to be most used). Additionally, it's questionable if we can speek to different processes, because of the browser sandboxes. What do you think?
  3. Low level network stack interception technique: I could sniff on the interface where the TCP packets of the communication sessions are exchanged with a appropriate API like scapy or libpcap (When writing C directly). Because the communication is encrypted with SSL/TLS needs to be a reliable way to decrpyt the TCP packets. This is not a trivial task, since different browsers use differnt ciphers/HMACS to encrypt the traffic. This issue is alleviated by the fact that some browsers can be started with a option (environment variable SSLKEYLOGFILE) to dump the current key secrets of a SSL/TLS session relevant mdn link for SSLKEYLOGFILE to a file which my bot could use to decrypt the traffic. Once decrypted, I will modify the HTTP POST PAYLOAD (json data) and replace the action I made, with the bot calculated move/action. Then I need to encrypt the packet again with the appropriate cipher. But this implies several issues as for example:

    • How can my sniffer/bot know which cipher was used? He only knows the current keys for the session, but not the ciphers. In the worst case, we need to also sniff the SSL/TLS handshake and connection start. This again is a very tedious process since the many quirks and combinatinos of a TLS session beginning.
    • Padding shouldn't be a bigger issue because the moves in the packet are just replaced and no additional data is injected or deleted. So the TCP packets should stay the same. We only need to recalculate the checksums.
  4. Another really really low level approach: Hooking! This might be the hardest approach in the investigation and research phase (It's not a easy task to find the correct hooking points in the HUGE chromium or firefox code base, but it looks like the NSS library is a good starting point), but also the most elegant way, because we don't need to hassle with SSL/TLS quirks and can work with plaintext HTTP packets, when we find a good hook point. This approach, although very elegant and straightforward comes with huge drawbacks:

    • Hooking is very platform depended. On linux we could hook with kernel modules or the LD_PRELOAD trick. On Windows we'd need other hooking techniques like IAT hooking, using the microsoft hooking library or something else. Additionally, we need to know the target architecutre (Different between x86 and amd64). But from what I know now, this approch seems to be the best compared to the others, because we can work in the target process space (The browser userland process space itself) and we do not reassemble/decrypt packets ourselves (like in the previous technique). Form grabbers are a related technique used by blackhats for their trojans.
  5. The traditional way: Reimplement the high level browser game protocol. This is not very elegant because our goal is to just modify packets. But when following this approach, we'd need to rebuilt the whole game logic (or at least many parts). This'd look something like the following:

    import requests

    login = requests.post('https://browsergame.com', {'login': user, 'password': pass}) if login.read().success(): requeset = request.get('https://browsergame.com/action.php?gamelogic=blabla') # Do implement game logic

So what do you think? I'm heavily inclined to the hooking approach, just because it is so elegant and involves sexy low level stuff...

2 Answers 2

1

For the low-level stack interception:

  • You cannot know what cryptographic algorithms are in force for a given connection if you did not see the handshake. However, connections are not kept open for long; a typical Web server will drop a connection after 15 seconds of inactivity. Browsers transparently reconnect when needed. Also, a given client (the Web browser) and a given server will normally always negotiate the same cipher suite, so all you have to do is to open an extra connection from the browser to the server to see what these two negotiate.

  • The "checksums" are not as easily modified, even if the keys are known. Crucially, the "checksum" (technical term is MAC) is computed over the concatenation of the record sequence number and the record contents. So you must know whether the record you are currently trying to alter is number 18 or 723 or 47634 in the connection. This is easy if you saw the whole connection (beginning with the handshake); if you did not then this may be resynchronized by brute-forcing the sequence number, but that may prove uncomfortable.

  • You also have to take care of CBC-based cipher suites. When using SSL-3.0 or TLS-1.0, and the symmetric encryption uses a block cipher in CBC mode, then the last block of a record is used as IV for the next; if you alter the record, you will imply a modification of that last block, so you must not forget to fix the start of the next record. This, again, is doable, but you have to think about it.

An easier method is a Man-in-the-Middle attack. Configure your Web browser with an additional root CA that you control. Configure also the browser to use for all connections a proxy server that you control. When a SSL connection is performed, intercept it and impersonate the server with a fake certificate, issued by your additional root CA; the client will accept it. Simultaneously, connect to the server as if you were the client, with a SSL of your own. Forward data in both directions, altering it in transit as you see fit.

This MitM setup has some advantages:

  • Applicable to any unmodified Web browser (except configuration of a root CA); no dependency on the browser model or version, OS, or system architecture.
  • It can even work from the outside, in case the target browser runs in, say, an iPad, or some other platform for which it would be difficult to do hooking or local low-level traffic interception.
  • At the MitM level, you get the cleartext streams in both directions, so there is no constraint on size. You can alter request sizes; you can drop, duplicate or reorder requests; you are free.
  • Software to do that is already available.

Personally I would do that; or hooking, depending on "the fun factor".

3
  • Thanks for the elaborate answer. MitM seems looks like it's the best solution, for some reason I didn't realize that I am able to control the connections in both directions. Can I create this root certificate on my own? Jan 16, 2014 at 11:38
  • Yes, creating your own root certificate is easy; OpenSSL can do that.
    – Tom Leek
    Jan 16, 2014 at 12:35
  • Nice, then it's basically the same thing that I did on my server. I was confused for a second because of the word root and associated it with the certificates only a CA can issue... Jan 16, 2014 at 20:40
1

If you can get sufficient logic with Javascript, you can use GreaseMonkey. Otherwise maybe some scripts for Selenium could do the job too.

In last resort, use a local proxy implementing TLS and modify your request on the fly.

Hooking the browser really seems to be overkill for a web-browser game.

2
  • I second the recommendation for GreaseMonkey. I used to write GreaseMonkey scripts to automate zynga games. Easy to do and lots of examples out on the 'net
    – Chad
    Jan 15, 2014 at 16:41
  • But isn't Greasemonkey restricted to firefox browsers? But I guess Tampermonkey is the chrome equivalent and because it's all javascript it's runs on both browsers, right? Jan 16, 2014 at 11:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .