Game Development Community

Cheating/Exploiting serverCmd Functions in Multiplayer TGE Games

by BrokeAss Games · in Torque Game Engine · 06/30/2005 (7:18 am) · 7 replies

I'm trying to protect my multi-player game from cheating/exploiting.
There are a few issues I'm concerned about before releasing a demo.
After using TGE for awhile and reading the forums I understand that a client can send any serverCmd function to the server at any time, using a custom .cs file loaded on the client, accessing the console, or using a third party program to create/inject the packet.
The Teams Implementation mod by Xavier "ExoDuS" Amado here is the example I'll use.
This is a wonderful piece of code that I use for factions in my game and I do not think it was intended to be used in this manner at all.
When the mod is used as intended by the author, what I'm going to describe is not an exploit or a cheat, it is the intended nature of the mod.
I am currently working on a hybrid mmo rpg/fps game and I am using the teams as armies that a player/npc can join.
Using the RPGDialog mod and some basic NPCs I have the joining/leaving of the team/army as a dialog response.
However, a client could send something like joinTeam(1); at any tme and change armies at will.
Removing the console from the client, deleting .cs files, using an encrypted file system or .zip archive would prevent most of the problems, but custom binds, third party programs injecting packets or accessing memory can still send the commands to the server.
So it seems that great care must be taken when writing ANY serverCmd function when writing a game of this style, where cheating can be a serious issue.
I'm interested in ways of writing serverCmd routines that make server side checks before executing the real meat of the code.
Besides %client.player.yourcheckhere what other things would be good to check?
What fixes can be made to the existing mods on this site to secure them for multi-player games?

Example:
function serverCmdJoinTeam(%client, %teamid)
{
   if(%client.player.somecheck) //<- Player Check Goes Here
      %client.joinTeam(%teamid);
}
Please help.

Ari Rule

#1
06/30/2005 (7:42 am)
The solution is really to only accept data from the client that you're expecting to receive. For example if you want to only allow the player to change teams via a dialog that is shown at certain times, then make the server tell the client to show the dialog.

Then store server side the fact that you have requested the player select a team via the dialog. When you receive info back from the client saying they've selected a team (either from the dialog, via hacked scripts or any other way) you then check whether the server has asked the client to select a team. If it hasn't, then ignore the change team request.

There are probably a number of alternative schemes, however they'll pretty much all require that the server be in charge or all validation. Trust nothing from the client :)
#2
06/30/2005 (7:59 am)
For commands that don't need to be excecuted immediately you could do something similar to the model below:

1. Client sends serverCmdJoinTeam()
a. Client listens for a verification packet
b. Client runs the information from the packet against something like the players ID, generating a new value.
c. Client returns a value to the server.

2. Server recieves serverCmdJoinTeam() from client
a. Server sends verification packet to client
b. Server listens for response packet
c. Server checks the returned value
d. If value is correct, execute serverCmdJoinTeam()
e. If value is incorrect or server doesn't recieve a response, we know it was faked.

The server recieves the command, and says whoa, wait a second, I need to see some ID. What is the secret handshake?
The server sends a value, "4A05" (or whatever) to the client.

The client runs 4A05 through a predetermined algorithm that the server is running the value through as well. So the server knows what value it should be expecting back.

The client sends back the info and if all is well, the command is proccessed.

The verification packet could contain information on Which of several algorithms to use say the A in our value is for our first algorithm. If it recieved 4B05 it would use the second of our algorithms (obviously we wouldn't make it this simple).

This wouldn't be a good check for commands like shooting, or real time actions. But bank transfers, switching teams, using items or resources would be ok.

This isn't a complex model, but it would protect your game from packet injecting or custom binds.
#3
06/30/2005 (8:03 am)
Don't just accept the data that the client sends.. veryify it before (perhaps in the serverCmd itself) and then pass it along to a seperate function.

It's so general to your game though, so I cannot give you any good examples.
For the JoinTeam thing, you would check if the player is already on a team and if he's allowed to switch.. if he is, switch him over.. if he's not allowed to do it, just ignore it.

If he's not meant to be using the dialog or the command at all, perhaps logging it to a file on the server or disconnecting the player would make them not do it again.
#4
06/30/2005 (8:45 am)
Stefan has the easiest solution.

I have the server generate a hash value PER COMMAND that is passed to the client when certain interactions are required from the player. If the player doesn't respond in the serverCmd with the correct hash value, the command is ignored completely. It's similar to Unsung's solution, except that you can pass the hash value back and forth in the serverCmds themsevles without the extra network traffic. Just add an extra %hash field in your Cmds and you should be good to go.
#5
06/30/2005 (10:28 am)
Any time the client can say "its okay", you're going to get falsification.

Final authority must rest at the server. All the hashing in the world won't matter if the cracker can call your hash function too.

I recommend some kind of per-client permissions testing, as Gary suggested. The server could store a bit array for each client, long enough to have a bit for each possible command from that client. As things happen, you can flip those permission bits on and off as appropriate.

1) User asks for team dialog (through a server command)
2) Server decides if this is permissible and responds accordingly, also setting the "joinTeam okay" bit to true for this client.
3a) User picks a team, server permits it AND CLEARS THE BIT.
3b) User cancels dialog, SERVER CLEARS THE BIT.

I think a nefarious client might still be able to "intercept" the dialog so it wouldn't have to be displayed, but the server still has final say over whether or not a given client can have that bit set.

The concern then becomes what happens when a user asks for the team dialog, and doesn't respond to it at that time. If the bit is left true indefinitely, a sneaky bastard could choose some inopportune moment to switch teams. Even if they can only do it once, they're still doing something they shouldn't be able to.


There's a few ways around that:
1) When a given permission bit is set, schedule a "clear" action for some point in the future.

2) Wipe bits when a client switchs between states [logged in but not in game, spawned, dead, etc].

3) Use a timestamp rather than a bit for each command. You set the timestamp to some non-zero value and that command is available until that time. This method is similar to the first one, but doesn't require any scheduling overhead on the part of the server. On the down side, when ever that command is executed, you now have to check the current time. Knowing which one is more efficeint may require some profiling (though it could be obvious, I haven't looked at this portion of torque's script(yet)).
#6
08/10/2005 (2:17 am)
Does the network code handle packet loss for all this? Or do you need to handle that explicitly? (Recall that this is all going over UDP, which doesn't guarantee delivery.)
#7
08/10/2005 (2:33 am)
Commands to server/client are guaranteed.

Torque implements several reliable transports over UDP.