And again, Diamond Dash
As soon as I read in a recent article about writing a bot for the game Diamond Dash on Google+, which almost reached 2 million points, I immediately combed my hands to write a similar bot that would achieve this goal - and, after several days of experiments, this the result has indeed been achieved .
However, now this was already not enough - using a different approach , at that time my feat was already outstripped and even surpassed (the final result, judging by the article, is approaching 4 millionpoints). Therefore, I decided to take another obvious step - to try to simply replace the request to the server with the result of the game. As you can see from the screenshot, the attempt was more than successful.
The principle of this approach to cheating is simple to disgrace. In games that require a lightning-fast reaction from the player, it is inefficient to check every "move" on the server - the slightest juggling of the Internet and fast players immediately turn into embittered players. And the load on the servers is superfluous - who wants to verify a dozen requests per second from just one player? Therefore, without further ado, the creators of the game transfer the game logic to the client side - and only the calculated number of points is sent to the server. If we send a fake to the server instead of the real result, the next time you start the game, we will be able to admire a picture similar to the one I presented above.
How to protect the server from such fakes? Strictly speaking - no way, this is impossible in this situation in principle. The request informing the server about the result of the game is created on the client - which means that we already have all the rules for its formation. Nevertheless, the hackers can complicate the task in the following ways (and their combinations, of course):
Let's see which of these techniques were used by the developers of the game in question.
We put some web traffic sniffer - for example, Fiddler . It can only intercept HTTP (and even then not always), but here it is enough for us. We launch the sniffer, open the page with the game, and play one game. We return to Fiddler, we look.
Yeah, requests to the toy servers (ddg.wooga.com) are sparse - everything is as expected. You can clearly see the start of the game (request to / game / use_life / - use the heart of life that is spent on each game) and its end ( / game / eor / - end of round), and nothing in between.
There are two requests at the end of the game - one to ddg.wooga.com/game/eor , the other to ddg.t.wooga.com/w/eor . We begin to dissect the first.
Inquiry:
Answer:
Simple and clear JSON, not encrypted in any way. True, timestamp , signature and session are transmitted in the address - therefore, there is some kind of signature. The answer, in fact, is not particularly meaningful - the server, for its part, also spits out signature data.
Well, we’re trying it stupidly: without even starting the game , we’ll send out a completely identical request, replacing only the value of the score field with 99999999. Fortunately, Fiddler has a suitable tool for this - Request Builder.
Oddly enough, in response we get exactly the same 200 OK, except with a different timestamp and signature. We are surprised at the carefree reaction of the server, we’re trying to update the page with the game. Having updated, we are even more surprised: the game believed us, but instead of 99 million it counted 16,777,215. It seems that this is the “ceiling” - in the database it is most likely stored in the form of something like UNSIGNED MEDIUMINT (a three-byte integer), which has exactly this maximum value.
It’s possible to stop at this, but after such sagging in terms of the “security” of the application, one involuntarily asks the question - are there any bigger holes?
As we can see, in the request to the server our user_id is passed - the identifier of our Google+ page. And the signature, apparently, is needed precisely so that the third-party server can understand whether this user_id really belongs to us. Hmm, does he really understand this? Or maybe he is so gullible that he will allow him to “win” even on behalf of someone else?
We climb onto the page of one of our friends, dragging his id from the address, slip everything into the same request (even scoring a timestamp to fix it). Yeah, everything seems to be fine here: 400 Bad Request ... Although no, wait a minute:
Computed ?! In fact, the situation is approximately the following: we are trying to log into someone else's account; without knowing the password, enter whatever; In response, we get not only an error message, but also the correct password. Perfectly.
Obediently copy the signature from the response, substitute it into the request, send it. You probably already guessed that a completely friendly 200 OK comes in response. And the expected result:
(above is my account, below is an “experimental” friend)
The development team of the game Diamond Dash, probably, should be blamed for negligence - it was clearly not worth showing the correct signature in response to the erroneous ... But you can’t be too strict on them. In the end, this is just a casual toy, and you can’t avoid cheating in it, as was already said at the beginning. In fact, the only true way to combat cheating was used in it: the rating table is compiled only from the user's friends. Thus, the results of cheating remain visible only to the friends of the cheaters (however, given the bug with the signature, this is not quite so).
Thank you for your attention - and I hope that my article will first of all be useful not for cheating, but for developing defenses against it :)
However, now this was already not enough - using a different approach , at that time my feat was already outstripped and even surpassed (the final result, judging by the article, is approaching 4 millionpoints). Therefore, I decided to take another obvious step - to try to simply replace the request to the server with the result of the game. As you can see from the screenshot, the attempt was more than successful.
Principle
The principle of this approach to cheating is simple to disgrace. In games that require a lightning-fast reaction from the player, it is inefficient to check every "move" on the server - the slightest juggling of the Internet and fast players immediately turn into embittered players. And the load on the servers is superfluous - who wants to verify a dozen requests per second from just one player? Therefore, without further ado, the creators of the game transfer the game logic to the client side - and only the calculated number of points is sent to the server. If we send a fake to the server instead of the real result, the next time you start the game, we will be able to admire a picture similar to the one I presented above.
How to protect the server from such fakes? Strictly speaking - no way, this is impossible in this situation in principle. The request informing the server about the result of the game is created on the client - which means that we already have all the rules for its formation. Nevertheless, the hackers can complicate the task in the following ways (and their combinations, of course):
- signing the transmitted information with a key wired in the client,
- signing the transmitted information with a key received from the server,
- signing the transmitted information with the current time (transmitted in a separate field),
- encrypting the transmitted information,
- obfuscating the client code to prevent it from knowing the encryption algorithm, the signature algorithm and the value of the flashed key.
Let's see which of these techniques were used by the developers of the game in question.
Operation "interception"
We put some web traffic sniffer - for example, Fiddler . It can only intercept HTTP (and even then not always), but here it is enough for us. We launch the sniffer, open the page with the game, and play one game. We return to Fiddler, we look.
Yeah, requests to the toy servers (ddg.wooga.com) are sparse - everything is as expected. You can clearly see the start of the game (request to / game / use_life / - use the heart of life that is spent on each game) and its end ( / game / eor / - end of round), and nothing in between.
There are two requests at the end of the game - one to ddg.wooga.com/game/eor , the other to ddg.t.wooga.com/w/eor . We begin to dissect the first.
Inquiry:
POST ddg.wooga.com/game/eor/?timestamp=1314395650744&signature=V5rwMEQJS_2diWc...ulj2VBs%3D&session=1100447b5bb0d08c12 HTTP/1.1
Host: ddg.wooga.com
Connection: keep-alive
Content-Length: 99
Origin: 8kubpeu8314p2efdd7ljdo-a-oz-opensocial.googleusercontent.com
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1
content-type: application/json
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3
Cookie: _dd_rails_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIljA4NmUzZDZiNjk5MGYxZDQzNWQ%3D--3e580eae77a1037b347dae6229bb6d
{"user_id":"104465643407894900734","level":21,"sound":1,"score":144768,"xp":130,"gems_removed":348}
Answer:
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 26 Aug 2011 21:54:12 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Vary: Accept-Encoding
Status: 200 OK
Cache-Control: no-cache
X-UA-Compatible: IE=Edge,chrome=1
Set-Cookie: _dd_rails_session=BAh7BkkiD3GOgZFR...wNDUxNTc%3D--b85c8953db82adcb0; path=/; HttpOnly
X-Runtime: 0.009475
Content-Length: 120
{"timestamp":"1314395652","user_id":"104465643407894900734","signature":"PAfgcneDa83-fR5_-CzJWpQ="}
(hereinafter some lines are shortened just to fit without hyphenation)Simple and clear JSON, not encrypted in any way. True, timestamp , signature and session are transmitted in the address - therefore, there is some kind of signature. The answer, in fact, is not particularly meaningful - the server, for its part, also spits out signature data.
Active actions
Well, we’re trying it stupidly: without even starting the game , we’ll send out a completely identical request, replacing only the value of the score field with 99999999. Fortunately, Fiddler has a suitable tool for this - Request Builder.
Oddly enough, in response we get exactly the same 200 OK, except with a different timestamp and signature. We are surprised at the carefree reaction of the server, we’re trying to update the page with the game. Having updated, we are even more surprised: the game believed us, but instead of 99 million it counted 16,777,215. It seems that this is the “ceiling” - in the database it is most likely stored in the form of something like UNSIGNED MEDIUMINT (a three-byte integer), which has exactly this maximum value.
It’s possible to stop at this, but after such sagging in terms of the “security” of the application, one involuntarily asks the question - are there any bigger holes?
Move on
As we can see, in the request to the server our user_id is passed - the identifier of our Google+ page. And the signature, apparently, is needed precisely so that the third-party server can understand whether this user_id really belongs to us. Hmm, does he really understand this? Or maybe he is so gullible that he will allow him to “win” even on behalf of someone else?
We climb onto the page of one of our friends, dragging his id from the address, slip everything into the same request (even scoring a timestamp to fix it). Yeah, everything seems to be fine here: 400 Bad Request ... Although no, wait a minute:
HTTP/1.1 400 Bad Request
Server: nginx
Date: Fri, 26 Aug 2011 22:07:06 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Status: 400 Bad Request
Cache-Control: no-cache
X-UA-Compatible: IE=Edge,chrome=1
Set-Cookie: _dd_rails_session=BAh7BkkiZ...Tk5NmFkOTA%3D--b96793945142dd62b0e5ea9a; path=/; HttpOnly
X-Runtime: 0.002774
Content-Length: 124
Signature mismatch! Got: V5rwMEQJS_2diQ8sdZMXBs= computed: gcLO6NdBJtwBtOwrWIpwL9LliuA=
Computed ?! In fact, the situation is approximately the following: we are trying to log into someone else's account; without knowing the password, enter whatever; In response, we get not only an error message, but also the correct password. Perfectly.
Obediently copy the signature from the response, substitute it into the request, send it. You probably already guessed that a completely friendly 200 OK comes in response. And the expected result:
(above is my account, below is an “experimental” friend)
Conclusion or Why all this is "fake" cheating
The development team of the game Diamond Dash, probably, should be blamed for negligence - it was clearly not worth showing the correct signature in response to the erroneous ... But you can’t be too strict on them. In the end, this is just a casual toy, and you can’t avoid cheating in it, as was already said at the beginning. In fact, the only true way to combat cheating was used in it: the rating table is compiled only from the user's friends. Thus, the results of cheating remain visible only to the friends of the cheaters (however, given the bug with the signature, this is not quite so).
Thank you for your attention - and I hope that my article will first of all be useful not for cheating, but for developing defenses against it :)