[PSA] Exploit for servers linked with MySQL

The issue:
On practically any server that uses a mysql database to link two or more servers you can use -multirun to log into both servers and manipulate things by overwriting your data with a second instance of Garry’s Mod.
There is no convar I or anyone I’ve asked knows of that can disallow people to use multirun on your servers.
There is no easy way to fix this that doesn’t require most mysql based addons to be heavily modified or recoded.

**Examples:
**1. Join two linked DarkRP servers, drop all your money on server A, drop $1 on server B, reconnect to server A, pickup your dropped money and you have now duped your wallet. See here.
2. Join two linked servers with pointshop, spend all your points on both servers effectively doubling your points. Even though it is done what most would call the proper way it is still vulnerable.

KingofBeast and I made a quick addon that will kick multirun accounts (Hopefully Rubat or Willox will add a convar/hook in the future so hacky fixes like this aren’t needed):
tmysql3(lol): https://github.com/SuperiorServers/NoMultirun/tree/tmysql3
tmysql4: https://github.com/SuperiorServers/NoMultirun

If/when they do, I really hope it’s enabled by default.

:snip:

Haha, clever!

Surely your script will break if the server crashes?

I suppose if for some reason checkactive ran before setactive completed it’d be possible but very unlikely, fixed it anyway.

Lmfao

Very helpful, thanks.

This kind of exploit has been around for ages, used to see people do similar stuff back in 2010. If you never accounted for instances like this at any point in the design of your gamemode and you intended to run multiple servers linked to any sort of database then you really messed up. I can only imagine the terrible “global ban” code other people make if this comes to a surprise to most people. Duplication exploits are pretty much the worst of the worst and should always be kept in mind.

I assume you’d know your code will fail up terribly if you shut down a server and your players attempt to join your other servers, or in the case that it crashes or if you restart the map?

You really should be dropping these players LONG before they get to initialspawn as spamming some binds while joining before you get kicked off a timer really isn’t difficult.

Apparently Zarp already fixed this problem, if you try to do it with them they fail your steam auth.

Yeah, they give a fake Steam auth message in CheckPassword and do all of the verification work there. It’s actually way too early of a window in-case their other server shuts down or crashes – PlayerAuth is the earliest safe time.

Same thing with Supiorer Servers.

Unfortunately just about nothing accounts for this functionality in Garry’s Mod, not even the most popular addons and gamemodes.

It’s [del]not[/del] wasn’t intended to kick you from the server you’re joining but rather the server you were last on so in the case of a crash it’d just ignore it.

Totally valid point, I didn’t think of that. Fixed it.

  • Preventing this would require the servers linked to the same database to communicate with one another about which players are in which server.
  • A hack solution could be to check whether data isn’t being changed behind a server’s back, e.g. when updating the player’s money, check whether the previous value in the database is the same as the player’s money before the update.
  • Properly solving this would require the servers to communicate changes to the database, to have everything run in sync.

All three solutions have serious downsides. All of them are based around the specific existence of multirun and require increasingly much effort to implement. Never mind the serious downsides of the three individual solutions:

  • Disallowing players to join two servers seems unnecessary, since the only reason for disallowing it is the server’s inability to properly deal with it.
  • The hack solution is a bitch to implement because of race conditions (e.g. two updates shortly after each other from the same server)
  • MySQL is ill equipped to send push messages about updates.

This problem is non-trivial, and the solutions have terrible downsides. This is not a case of having really messed up, it’s a tradeoff. Not solving it if you don’t know about multirun is a perfectly valid tradeoff.

A sockets based system would be trivial and solve the problem without any downsides.

Player joins server - server queries other servers to check if they have the same player on there - take appropriate action.

What in the world is “trivial” to you? If something is “trivial” you should be able to solve it with the standard library, and even then, preferably easily.

The issue primarily affects those using a multiserver platform, typically via SQL (or noSQL if that takes your fancy) meaning you’re already outside of the standard realm of the gmod library. This means you’re most likely going to be having to fix the issue without use of the standard library and thankfully there is a list of socket libraries you can use.

(oh and GLsock was succeeded on that list by GLSock2)

why not just use a socket module so the 2 servers can talk directly to each other about which players are online
granted that’s a bit of a pain in the ass in itself since it requires manually setting up connections between all of your servers but if you got as far as making multi SQL linked servers you should be able to figure it out

There’s nothing difficult about having “multi SQL linked servers”, you just tell everyone to connect to the same database.

On the other hand, having connections between servers is a little more difficult.
If you have multiple servers, in different locations, the correct way is to communicate over the internet.
If you have multiple servers all on the same intranet, you use different addresses, but it’s the same.
If your gmod servers are all on one physical server, the “correct” way is with (os dependent) pipes or shared memory. You could set it up like the above, but then you need to figure out ports for everything.

Also, how should I keep track of players? Should I have every server send a request to every other server to see if the player is there? Should I have a master “who is online” list on one server, and everyone queries that?

Another solution for this problem is to use a php script to fire rcon commands to notify your other server(s) when a player is authed. Then you can use the game.KickID function to insure the steamid is not connected to any of your other servers at the same time. This solution has been working for us for a while now.

Also thank you for taking the time to make this thread. Hopefully now that this has been publicly released, one of the devs will actauly implement a proper fix. Despite the fact RB was notified about this months ago.