How to create a Remote Execution
Arma 3 Remote Execution is considered one of the few peaks of script-based cheating. For server owners, cheaters with remote executions can be a real pain. It is important that every script developer understand how remote executions are created so they can avoid allowing these vulnerabilities to exist in the first place. Just as a heads up, this post will assume you have a pretty decent understanding of scripting in the multiplayer context.
When I talk about Remote Execution, I am referring to the process of executing arbitrary SQF on a remote machine. Ideally, we want to execute this arbitrary code on the server, as we’ll have more power over the state of the server from there, however, Remote Execution can also take place on a client to client basis, which also has it’s own merits. Many of the most insidious scripted cheats have only been possible because of a remote execution vulnerability on the server. An example I would like to point out is the Kill All script. Yes, there are many ways to do it, but by far the most effective is to execute the following code on every client: player setDamage 1;.
Remote Execution opens up loads of possibilities to scripted cheats. Many objects on the server cannot be easily manipulated due to locality. Certain script commands require arguments that must be local or have effects that only take place on the local machine. For an example of a local argument script, look at setVelocity. For an example of a local effect script, look at setFace. There is another state that some script commands require, the Server Execution property. These commands will only function if executed on the server. So in order to make use of some of this functionality, either by changing other player’s velocity, their faces, or even making them invisible, we’ll need to remote execute some code on either the server or their machine.
First, I want to walk you through some basic examples of remote execution. Most of you will be familiar with these functions, so if you skip through this part, that’s fine.
Here, we use the remoteExec functionality to execute a hint on all clients. One thing I would like to point out is the usage of BIS_fnc_execVM. Often this script command is allowed through Battleye filters and can be used in combination with the fn_call script to execute a payload.
Here, createUnit is used with its alternate syntax. The alternative syntax has an init field, which executes on every machine. This is often filtered pretty heavily, but some of the time you can sneak around Battleye filters with just this command and a smart init field. Note that the init field is a string, so you’ll need to format your payload into a string as well.
Here, addMPEventHandler is used with the MPKilled event. By creating an agent, attaching this event, and killing the agent, the payload is executed on every machine. Very often this style of execution is filtered, so it’s not common to see anymore, but it is important to know it exists.
Many SQF functions have the capability to execute code on remote machines. Sometimes you have to get crafty in order to trigger execution, but never rule out a possible approach, even addPublicVariableEventHandler could be exploited to execute your payload!