February 04, 2021     3min read

Creating a FiveM Anti-Cheat

Introduction

Hi there.

As most of you will know, there is a large amount of hackers/cheaters in the FiveM community. They usually use a combination of a “Lua executor” and a “Lua menu”. Other forms of cheats involve Cheat Engine or bypassing the disabled Scripthook feature.

The most used cheat in Lua menus is abusing vulnerable and exploitable events to give one more money, handcuff everyone, ban players, and so on.

I would like to give you all a list of known vulnerable/exploitable events that are being actively abused by cheaters. This to encourage anyone having these events in their resources to fix them. Those not running an ESX/vRP server can also take advantage of this list by simply listening to the events and straight out banning anyone using them.

See How hackers can exploit your servers and what to do about it for an overview of how such an exploit may work.

IF YOU FIX ANY OF THESE VULNERABLE EVENTS OR KNOW A GOOD COUNTER, TELL THE RESOURCE CREATOR AND/OR CREATE A PULL REQUEST ON THEIR REPOSITORY

(I personally do not use any of these events so I simply listen for and ban - See examples below)


Blocking Server-Side Events

  • For a full list of Server-Side Events that Hackers/Modders tend to exploit Click Here

Example of Blocking Server-Side Events

Make sure the List of events found above is Included with this example.

for i, eventName in ipairs(ForbiddenEvents) do
  RegisterNetEvent(eventName)
  AddEventHandler(
    eventName,
    function()
      local _source = source
      local name = GetPlayerName(_source)

      local steam = ""
      local license = ""
      local discord = ""
      local xbl = ""
      local live = ""
      local fivem = ""

      for k, v in pairs(GetPlayerIdentifiers(_source)) do
        if string.sub(v, 1, string.len("steam:")) == "steam:" then
          steam = v
        elseif string.sub(v, 1, string.len("license:")) == "license:" then
          license = v
        elseif string.sub(v, 1, string.len("xbl:")) == "xbl:" then
          xbl = v
        elseif string.sub(v, 1, string.len("discord:")) == "discord:" then
          discord = v
        elseif string.sub(v, 1, string.len("live:")) == "live:" then
          live = v
        elseif string.sub(v, 1, string.len("fivem:")) == "fivem:" then
          fivem = v
        end
      end

      BanPlayer(license, steam, xbl, live, discord, fivem, 9000, "Event Hacker", true, _source) -- replace with own ban logic
    end
  )
end

Blocking Client-Side Events

This is a full list of Client-Side Events that Hackers/Modders tend to exploit.

-- Client side events that are abused with TriggerEvent
local ForbiddenClientEvents = {
  "ambulancier:selfRespawn",
  "bank:transfer",
  "esx_ambulancejob:revive",
  "esx-qalle-jail:openJailMenu",
  "esx_jailer:wysylandoo",
  "esx_policejob:getarrested",
  "esx_society:openBossMenu",
  "esx:spawnVehicle",
  "esx_status:set",
  "HCheat:TempDisableDetection",
  "UnJP"
}

Example of Blocking Client-Side Events

local AlreadyTriggered = false

for i, eventName in ipairs(ForbiddenClientEvents) do
    AddEventHandler(
        eventName,
        function()
            if AlreadyTriggered == true then
                CancelEvent()
                return
            end
            TriggerServerEvent("ggac:banMe", 9000, "Cheating", nil, true) -- replace with your own event to ban
            AlreadyTriggered = true
        end
    )
end

Bonus

If you don’t run esx it’s often even easier to catch cheaters as most cheat menus try to check if you use esx by using the “famous” esx:getSharedObject event.

AddEventHandler(
    "esx:getSharedObject",
    function(cb)
        if AlreadyTriggered == true then
            CancelEvent()
            cb(nil)
            return
        end
        TriggerServerEvent("ggac:banMe", 9000, "Cheating", nil, true)
        AlreadyTriggered = true
        cb(nil)
    end
)