Cheating at Online Video Games and What It Can Teach Us About AppSec (Part 3)

Our third and final installment in a series about cheating at video games. If you haven’t already read Part 1 and Part 2, go ahead and do that now. I’ll wait.

RACE CONDITIONS

A classic place for security issues to be introduced is at the stress point between how a system should work on paper and how it has to behave in reality. Games are typically fast paced, requiring low-latency network connections and quick reaction times. However, they also have to deal with the reality of sub-par internet connections, buggy network equipment, and cosmic rays flipping bits en route. By intentionally manipulating network behavior, a player in an online game can gain a big advantage. Let’s take a look at how.

Imagine playing a game of rock, paper, scissors with a friend. An important aspect of the game is that both players have to “throw” at the same time. It remains highly controversial to this day whether one should throw on “rock, paper, scissors, shoot” or “rock, paper, scissors,” and it’s important that the players agree. Whoever throws last gains an advantage since they can see what their opponent has chosen! In the infosec world, we call this a race condition, though it’s a bit unique in infosec because the winner of the race is the slowest player.

A similar arrangement is often present in online video games where gameplay decisions must be made quickly and sent to opposing players. But delaying your own decisions at a crucial moment might just give you extra information needed to defeat your opponent. The canonical example of this is a lag switch — a button (either physical or in software) that deliberately slows or stops your network communication. By hitting the switch at a crucial gameplay moment, the underhanded player can perform some magic. Let’s take a closer look at how this works.

ROLLBACK

Modern online games typically work with a rollback system (or at least the good ones do). The exact details of this system are complicated, but the gist is that what you see on the screen as a player doesn’t necessarily represent a completely accurate view of the game state. Because of network latency, there will be small inconsistencies. The game engine will display its best guess as to where your opponents ought to be, based on their last known position and trajectories. When network conditions improve and packets finally arrive on the other side, the game engine will update the game state to be correct. In practice, this is actually quite seamless and enables lower-latency play than you might think possible due to physics.

So for instance, suppose two players are together in a first-person shooter (FPS) game that looks like this:

 

 

FPS diagram

 

Alice turns a corner and gets a look over at Bob, who is just standing there. Easy prey! Alice takes aim and shoots Bob right in the forehead. But rather than falling down, Bob disappears and teleports right behind Alice with a knife to the back! What happened here? Bob is a filthy cheater, that’s what. But how exactly does this work?

What happened is that as soon as Bob saw Alice, Bob flipped a lag switch. This shut down all of Bob’s network traffic for just a second: long enough for Bob to run up behind Alice and for traffic to resume like normal. During this momentary lapse in network connectivity, what Alice saw was only an illusion. She couldn’t see Bob walking up behind her because no packets were being sent during that time. When the packets finally reached Alice, her game engine updated the game state to be current, which put Bob right behind her.

These kinds of cheats are notoriously difficult to detect or prevent because they occur outside of the gaming system (on the network) and have an air of plausible deniability about them. Legitimate networking errors occur all the time. And sometimes, they will occur to a player’s benefit. So how do we sort out the lucky ones from the cheaters?

RACE CONDITIONS IN APPLICATION SECURITY

The web application world is no stranger to race conditions. For example, a common vulnerability in web systems is a race condition in caching and database infrastructure. Consider for a moment the double-spend problem:

 

Double-spend problem


A user rapidly sends two commands to spend $10 on an online website to purchase two different items. A common problem for web applications is executing the database logic simultaneously, which causes the application to behave in an unexpected way.

 

Double-spend problem app behavior

 

Two threads of execution on different application servers each read the user’s current cash balance of $10. Both threads then calculate that the new balance ought to be $0 after the money is spent, so they update the database and complete the transaction.


Double-spend problem data update

But now the user has spent the same $10 to purchase two items!


Double-spend problem purchase

Forcing synchronization is the most straightforward solution to race conditions used in web applications. Essentially, the system puts a mechanism of mutual exclusion (mutex) around the logic responsible for interacting with a given user’s balance. Thus, one process can’t access a user’s balance until the other process is complete.

Similarly, in our video game example, the issue fundamentally stemmed from one user (deliberately) straying too far from synchronization with other players. This is an identifiable and resolvable condition. For one, the game can refuse to proceed too far out of sync. This can be potentially jarring to players as the entire game sort of freezes for a few brief moments, so it may work better in some games than others. But if the thresholds are set appropriately, it will only be necessary in extreme cases like lag switches.

Additionally, take the long-game approach and look for patterns of repeated behavior. Trying to definitively tell the difference between cheats and luck in any specific instance may not be possible. But if a player has a pattern of lag spikes right before turning corners, then that’s a thing that developers can plan heuristics on.

ENFORCE THE RULES

The rules in any system (game or banking app) need to be enforceable if they’re going to matter. Otherwise, your “rules” quickly devolve into “guidelines” for users:


Rules meme

 

A good example of this is the popular Indian game Kabaddi. If you haven’t had the pleasure of watching a game of competitive Kabaddi, you’re in for a treat:



It’s a bit like competitive tag. One player (the raider) tries to tag members of the opposing team and then get back to the center line without being tackled. Oh, and the raider has to do this all in one breath. But how are you supposed to tell how someone is breathing?! Well, in the official rules, raiders must continually and audibly chant “Kabaddi” over and over to prove that they are exhaling.

Kabaddi has a long history as a children’s game in India dating back to ancient times. It’s the sort of thing that you grow up playing, a bit like playing tag here in the USA. Except that Kabaddi is also a competitive sport watched by hundreds of millions of people. Having to hold your breath is the sort of rule that works well when you’re on the playground: it’s basically a way of having a timer. Otherwise, the raid could go on forever, and having to hold your breath puts an effective cap on the amount of time you can raid. Plus, it’s kind of fun.

But for the pros, there’s a lot of wiggle room in this rule. How are you supposed to tell if someone isn’t taking quick breaths in between words? What if someone is chanting quietly but actually breathing in? The more you think about it, the more it becomes clear that this rule just doesn’t work in a competitive environment with screaming fans in a stadium the same way it does on the playground.

The Pro Kabaddi League (PKL) eventually removed the breathing rule and replaced it with a simple 30-second timer. It’s important for your rules to be enforceable, or else they’re not really rules; they’re more like guidelines. (Raiders do still have to chant “Kabaddi” actually, apparently as an anachronism, but there’s no specific breathing requirement.)

Too often, the video game industry treats cheating as a moral issue, rather than a technical one. There are lots of community-focused efforts to identify cheaters and punish them. But technical anti-cheating mechanisms are never seriously invested in as a result. This is a shame, since security problems are hard but solvable.

On this front, the security team at Riot, (a popular video game developing company) has been doing excellent work both in terms of philosophy and technical progress. They’ve implemented server-side controls to add security features in a way that is rare in the video game industry, such as stopping map hacking in League of Legends and Valorant, and their games are more secure as a result. Although seriously, the spyware approach will never work. Stop trying to make spyware work. Having unwanted proprietary adversarial implants in your kernel is not security; it’s malware.

CONCLUSION

Online video games are as pervasive and complex as anything you’ll see in the web application world, and there are a lot of important security lessons our communities can learn from each other.

In application security, video games are too often overlooked as not being serious business despite the fact that the video game industry far outsizes the movie and TV industries combined. And as you’ve read in this article, video games have many complex and technical security challenges. There’s a lot we can learn from each other as communities to help build safer and fairer systems.