Open styla01 opened 5 years ago
bump. cen from eurobattle.net can confirm this problem. if you need to test, we have the hack tool.
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.
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.
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.)
I'll produce a wireshark dump to see what kind of checksum is present in the fake packets.
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
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.
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.
@kirill-782 focus on the bot side, in the maps side i spoke with 'gods' map creators and you can do nothing!
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.
I made a lot of edits so here's summary of my thoughts:
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.
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.
@styla01 well if you want an even more temporary solution, just kick the player if they send 6+ kills within, say, ten seconds.
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.
we cant, players are suicides See my videos and prints
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.
can u add a commit? please i bet, lot of ppl will enjoy
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.
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.
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.
i made the changes only in map side. I will upload the map script without any changes.(only blue sent packets)
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!
is done, all players save the stats. I need your discord to sent to you
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.
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)
So the only problem is you need the corresponding changes on the bot side to make this block the attacker, right?
Since the stats come in async I guess the voting is to be done at the very end by comparing each player report?
@uakfdotb yes here is the file https://files.fm/u/nzzbxsn2 and the comment inside //now save with all slots
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.
map, https://files.fm/u/nnv5s665 and is compatible only 1.26
@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?
@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.
@uakfdotb, Blizzard bans CD keys?
@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
I got started here but I wasn't able to test it (it does compile though).
https://github.com/uakfdotb/ghostpp/commit/7fe28c2370ce9d65076179966ece0c1e620214ce
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++.
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.
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
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: and after 2 seconds i saw live the ghostone interface: 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.