Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stats vulnerability #28

Open
styla01 opened this issue Mar 16, 2019 · 37 comments
Open

Stats vulnerability #28

styla01 opened this issue Mar 16, 2019 · 37 comments

Comments

@styla01
Copy link

styla01 commented Mar 16, 2019

First, i must say I use same statsdota.cpp like this repo, but I have adapted the ghostone interface to see live events.

I am attacked with a tool who sent fake stats(Kills and Deaths) to the bot.
I made live prints one from game:
Screenshot_2
and after 2 seconds i saw live the ghostone interface:
Screenshot_3
The fake kills/deaths trick the bot, and the atacker can sent 10 fake kills/deaths per second, until the game end all players have scores like K/D: 887/865

@uakfdotb Please help us! Maybe you can make a filter to read/accept action packets only from the bot ip (localhost only), or stats must be read'ed only from replay.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

bump. cen from eurobattle.net can confirm this problem.
if you need to test, we have the hack tool.

@uakfdotb
Copy link
Owner

Fake action packets is fundamental issue with how stats are processed by host bots. Replay parsers would have the same issue.

But this is a bit confusing:

he can sent fake stats to all current running games!

How does the packet sent by the attacker make it to the CStatsDOTA of a different game? It should only be parsed on this line in game.cpp:

if( success && m_Stats && m_Stats->ProcessAction( action ) && m_GameOverTime == 0 )

Only accepting action packets from bot IP wouldn't help because the bot doesn't understand what action packets are at all. Basically the bot is just a router that forwards action packets from one player to all the other players.

Anyway, one solution might be to only process the action packets after the player has KeepAlive packet, which includes a checksum based on the game state. Because if they are sending fake stats then probably their Warcraft III state will not match that of other players (unless they are not just injecting the packets into the TCP connection, but actually sending them through WC3 by modifying WC3 memory). I could provide more pointers on that but the first thing to do is probably to figure out why the attacker can modify stats in other games.

@cen1
Copy link

cen1 commented Mar 20, 2019

The "all current running games" comment is incorrect, you need to join the game to cause this.

My understanding is that replay generated by ghost will contain the same actions and is therefore not good for parsing stats. However, if such replay is opened in W3, the game seems to play fair and stats seem OK also, need to investigate this further.
This means the whole statsdota parser is of no real use other than informative and we would need to parse a replay provided by one of the real clients for 100% foul proof stats.

Packets can be generated out of thin air so to rely on game state is probably not an option.

At the moment I am brainstorming whether a modification in DotA map itself could give some secure solution.

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

Packets can be generated out of thin air so to rely on game state is probably not an option.

Players would need to send legitimate KeepAlive packets in order to avoid desync'ing. It seems to me that it's much harder for the player to compute the checksum in the KeepAlive correctly than merely send spoofed GameAction packets that contain fake stats data. Because that means the player would need their WC3 client to maintain the game state correctly.

(I expect that the player would desync because other players would receive the fake GameAction packets and update their game states accordingly. But the player would not be able to receive their own GameAction packets without modifying WC3 client because WC3 would reject receiving packets that it did not send.)

Edit: (if the player is not able to compute checksum correctly, their checksum would not match that of other players. Certainly if the attacker had two players in the game then they could borrow the checksum from the other player.)

@cen1
Copy link

cen1 commented Mar 20, 2019

I'll produce a wireshark dump to see what kind of checksum is present in the fake packets.

@kirill-782
Copy link
Contributor

It seems I have already discussed this in Skype. But since I now for the PC, then I can answer deployed here.

All statiscs work on the SyncStoredInteger native in Warcraft. The bot sees that some data is synchronized and counts as statistics.

And the main problem is that synchronization does not give clear signs that it was not the one who called it. I can independently generate the necessary SyncStoredInteger and the bot will consider this as an action. There will be no desynchronization.

As a solution - to alter the bot and the map so that all clients of the game sent a notification of the event to the bot, and the bot in turn processed it when it came from everyone, and not from one.

Alternatively, put FakePlayer on the game slot (11 or 12). When the bot receives Sync, it sends the action on behalf of FakePlayer "Sync came from the player ". If the event is correct, the players are silent. If not, send your Sync supposedly wrong event.

In this case, to hack the statistics you need to have several slots in the game for the hacker, which may not always be possible.

@cen1
Copy link

cen1 commented Mar 20, 2019

RECEIVED W3GS_OUTGOING_ACTION
{ f7 26 b0 0 7 23 49 8d 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 31 0 1 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 32 0 2 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 33 0 3 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 34 0 4 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 35 0 5 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 37 0 7 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 38 0 8 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 39 0 9 0 0 0 }
CRC
{ 7 23 49 8d }
Action
{ 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 31 0 1 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 32 0 2 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 33 0 3 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 34 0 4 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 35 0 5 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 37 0 7 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 38 0 8 0 0 0 6b 64 72 2e 78 0 44 61 74 61 0 48 65 72 6f 39 0 9 0 0 0 }

Locally calculated CRC (matches):
{ 7 23 49 8d }

If packet is generated outside the engine and distributed to clients I see no desync issues since clients probably just discard it.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

@kirill-782 focus on the bot side, in the maps side i spoke with 'gods' map creators and you can do nothing!

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

Interesting, I remember trying this before, I guess I had a bug (maybe the issue I ran into was WC3 crashing after receiving an action packet that it didn't send, but simply not forwarding that packet to WC3 gets around it).

If the map can be edited then kirill your solutions seem quite good, especially the first one (more straightforward to implement).

If the map can't be edited, do y'all think that the impact could be minimized by shuffling the players prior to game start, and only accepting the packets from blue player? I ran parser on some GHost++ replays and it seems like DotA always sends the synchronization through blue player, at least for the keys sent at end of game. (Based on W3MMD which probably takes same approach I think it's the first slot or something right? so if player leaves I imagine it'd transfer to teal.)

(If this works, you could just shuffle within the teams, and then also flip a coin to decide who is sentinel/scourge, then at least people can still play together and attacker with one player in the game has 1/10 chance of getting blue.)

(BTW I don't understand why the attacker needs to slowly send these packets to increment the kills one at a time, because there seems to be a set of keys "1"/"2"/etc sent at end of game which directly set the number of kills.)

Edit: oh, I think W3MMD already implements a "NUM_SENDERS_SAFE" approach where multiple players send the stats data? So it's like kirill's approach but it just does 3 random players I think. But I guess DotA always picks first slot, with no redundancy.

Edit2: very cool, from https://www.ghostpp.com/forum/index.php?topic=8.0 it looks like W3MMD defaults to 2 players but when it detects players are tampering with the messages, it increases it to 3. I don't think the host bot currently does anything special though.

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

I made a lot of edits so here's summary of my thoughts:

  • I believe DotA always sends the packets through the lowest slot. If that's the case, shuffling within teams prior to the game start would reduce the attacker's chance of being able to tamper with the stats to 1/10. Maybe reasonable limits (max 30 K/D per game) could further reduce the gain that attackers get from participating in this behavior.
  • Strilanc's W3MMD library seems to already implement a means to have multiple players vote on the stats, similar to kirill's suggestions. Initially, 2 players send the stats, but if tampering is detected, it is incremented to 3 players. (https://www.ghostpp.com/forum/index.php?topic=8.0). For W3MMD maps (i.e. everything but DotA), you could modify the host bot to take these multiple votes into account.

@cen1
Copy link

cen1 commented Mar 20, 2019

Shuffling is an interesting idea but it's mostly a band aid. We usually balance in lobby per player stats and allow slot locking so at best that would be ~1/5 chance. Still, as last resort it's better than no solution.

If map could be updated it would have to send from all players, anything less and you compromise on a team of hackers locking slots or voting over fair players.

I forwarded the info to d1stats for input.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

here are a live with the tool: https://gaming.youtube.com/watch?v=LNmDjlGkSV4&feature=share
pings are increased!

and here are stats with a hacked game: http://prntscr.com/n0mthx players suicides http://prntscr.com/n0mu7l

@cen1 Before starting this topic i spoke with d1, they said cant help.

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

@styla01 well if you want an even more temporary solution, just kick the player if they send 6+ kills within, say, ten seconds.

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

W3MMD has this comment:

/// - Calling RaiseGuard will increase the number of senders for each message from 1 to 3. This increases
/// security but uses more network bandwidth. It is done automatically if tampering is detected.

I guess the bandwidth issue isn't relevant anymore so all 10 players would make a lot of sense.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

we cant, players are suicides
See my videos and prints

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

we cant, players are suicides

The host bot knows who sent the action packet corresponding to each "suicide" event though. Just whichever player it got the action packet from.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

can u add a commit? please
i bet, lot of ppl will enjoy

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

Nah it is temporary fix anyway, just if you want it fixed in next few days it may be the simplest way; but you'd need to implement it yourself. The shuffling is slightly longer term, but still just means attacker won't be able to do it every game.

If you are okay with modifying DotA map (only need to edit war3map.j) then you could actually implement the fix proposed by kirill and cen without assistance from the map creators. If you post link to DotA map you're using I could take a stab at it using umpqx.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

Ofcourse I am ok to modify map script, Maybe @cen1 and @kirill-782 can implement the fix but I'm afraid will took too long. Kicking the flooder was a very good temp solution.

Edit. Saving stats by map with all slots instead of the blue only wont change anything, already tried.

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

Why wouldn't it change anything? You're saying you modified the map to run SyncStoredInteger from every player instead of just first slot player, and you updated the host bot to do something like majority voting, but one attacker can still mess up the stats? It seems like it should work to me so I don't understand exactly.

If you post a link to the DotA map that you're using I can try to edit it to run SyncStoredInteger from every player, assuming you haven't already implemented that solution. If you updated the map already, but not the host bot fix, I could look at implementing majority voting if that'd be useful, but that part seems quite straightforward.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

i made the changes only in map side.
I will upload the map script without any changes.(only blue sent packets)

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

That's pretty cool! In that case can you post the modified map where all players send packets? Then I (or someone else) may have some time to update the host bot to do majority voting, and check if it is all working. To me the map editing is harder than the majority voting!

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

is done, all players save the stats. I need your discord to sent to you

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

Can you upload map somewhere and post link here so anyone can download?

That way if someone else gets to it first they can go ahead and implement a solution.

Anyway anyone can download the map by joining your game! So would be good to have the link here.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

I will upload.
As I said , allready tested, here is a pic http://prntscr.com/n0nk98 A player kill a tower and is send 8 times (8 players)

@uakfdotb
Copy link
Owner

So the only problem is you need the corresponding changes on the bot side to make this block the attacker, right?

@cen1
Copy link

cen1 commented Mar 20, 2019

Since the stats come in async I guess the voting is to be done at the very end by comparing each player report?

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

@uakfdotb yes
here is the file https://files.fm/u/nzzbxsn2 and the comment inside //now save with all slots

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 20, 2019

Very cool! Can you upload the w3x though? That way on bot side can just stick the map in and don't need to create new w3x.

@cen1 I haven't thought about it much but that may be the simplest. Or could wait until (# players)/2+1 come in.

@styla01
Copy link
Author

styla01 commented Mar 20, 2019

map, https://files.fm/u/nnv5s665 and is compatible only 1.26

@kirill-782
Copy link
Contributor

@uakfdotb,
Once the conversation has already started here, and you do not answer me in Discord, then I will ask here: what is there to broadcast the game on the LAN to 1.30.4 warcraft?

@uakfdotb
Copy link
Owner

@kirill-782 I have no idea, I haven't upgraded 1.30.4, because Battle.net banned my personal CD keys. I think it'd be difficult with the new LAN system.

@kirill-782
Copy link
Contributor

@uakfdotb, Blizzard bans CD keys?

@kirill-782
Copy link
Contributor

@uakfdotb

0000   0a 17 4c 6f 63 61 6c 20 47 61 6d 65 20 28 6b 69  ..Local Game (ki
0010   72 69 6c 6c 5f 37 38 32 29 10 01 1a 17 0a 0b 67  rill_782)......g
0020   61 6d 65 5f 73 65 63 72 65 74 12 08 31 31 38 33  ame_secret..1183
0030   30 31 38 32 1a 0a 0a 05 5f 74 79 70 65 12 01 31  0182...._type..1
0040   1a 0d 0a 08 5f 73 75 62 74 79 70 65 12 01 30 1a  ...._subtype..0.
0050   0c 0a 07 67 61 6d 65 5f 69 64 12 01 31 1a 20 0a  ...game_id..1. .
0060   05 5f 6e 61 6d 65 12 17 4c 6f 63 61 6c 20 47 61  ._name..Local Ga
0070   6d 65 20 28 6b 69 72 69 6c 6c 5f 37 38 32 29 1a  me (kirill_782).
0080   10 0a 0b 70 6c 61 79 65 72 73 5f 6d 61 78 12 01  ...players_max..
0090   34 1a 0b 0a 06 5f 66 6c 61 67 73 12 01 30 1a 10  4...._flags..0..
00a0   0a 0b 70 6c 61 79 65 72 73 5f 6e 75 6d 12 01 31  ..players_num..1
00b0   1a 1e 0a 10 67 61 6d 65 5f 63 72 65 61 74 65 5f  ....game_create_
00c0   74 69 6d 65 12 0a 31 35 35 32 35 36 39 31 30 39  time..1552569109
00d0   1a c2 01 0a 09 67 61 6d 65 5f 64 61 74 61 12 b4  .....game_data..
00e0   01 41 51 41 41 41 41 45 44 53 51 63 42 41 57 73  .AQAAAAEDSQcBAWs
00f0   42 6d 57 73 42 34 78 4e 6a 7a 30 33 62 59 58 46  BmWsB4xNjz03bYXF
0100   7a 4c 30 56 76 64 31 6c 76 62 57 39 68 5a 53 39  zL0Vvd1lvbW9hZS9
0110   4e 48 32 56 6e 61 57 39 76 49 56 56 35 52 53 46  NH2VnaW9vIVV5RSF
0120   4e 5a 57 64 68 49 5a 4e 50 57 79 45 7a 4c 7a 4e  NZWdhIZNPWyEzLzN
0130   6a 7a 53 39 33 4d 33 6b 42 61 32 6c 6c 63 32 6c  jzS93M3kBa2llc2l
0140   74 62 56 38 33 4f 59 45 7a 41 51 47 33 33 61 32  tbV83OYEzAQG33a2
0150   78 64 66 58 6e 63 78 76 6c 4d 32 2f 33 31 54 48  xdfXncxvlM2/31TH
0160   4e 61 65 66 6c 73 77 63 78 6d 77 41 47 41 41 41  NaeflswcxmwAGAAA
0170   41 54 47 39 6a 59 57 77 67 52 32 46 74 5a 53 41  ATG9jYWwgR2FtZSA
0180   6f 61 32 6c 79 61 57 78 73 58 7a 63 34 4d 69 6b  oa2lyaWxsXzc4Mik
0190   41 41 43 45 55                                   AACEU

To disassemble this package. And so it’s not hard to deal with MDNS

@uakfdotb
Copy link
Owner

uakfdotb commented Mar 21, 2019

I got started here but I wasn't able to test it (it does compile though).

7fe28c2

As you can see it is a very small change, I don't have time to set up WC3 and all but hopefully it is enough to point you in the right direction to complete the implementation.

Of course there may be additional changes needed in your replay parser but that is separate from GHost++.

@styla01
Copy link
Author

styla01 commented Mar 21, 2019

i made a test with the patch, but bot crash when tryed to save dota stats.

I have also noticed a huge lag from the hack tool, we need a way to detect and kick the hack tool user.

@cen1
Copy link

cen1 commented Apr 29, 2019

I have a working patch, lightly tested but it should be a great start for anyone who wants to integrate it into upstream. Unfortunately our code base has diverged too much and I can't make a clean pull request. I most probably won't have the time to rebase this against this repo so anyone is welcome to take this work and integrate it.
D1stats dota a6 is required for this to work. It is not backward compatible with other maps altho it would be possible to detect if only player 0 sent the events and fallback to allow a single source.

https://gist.github.com/cen1/6dda290d3f397a15701553705beb8aea
https://gist.github.com/cen1/1a70688155573e1485615966a62a4e67
https://gist.github.com/cen1/c25b5b843dee2cc7798c5b34db579929

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants