Zusammenfassung
Der Handler für msgNetGameEventV2 im FXServer verarbeitet eine vom Client gelieferte
Liste von Ziel-Spielern. Jeder dieser Werte wird vor jeder Validierung als Index in
ein thread_local-Bitset benutzt, das nur für die maximale Spielerzahl dimensioniert
ist. Da der Client beliebige 16-Bit-Werte senden darf, entsteht ein Out-of-Bounds-Lese-
und -Schreibzugriff mit einem vom Angreifer wählbaren Offset im Thread-Local-Storage des
Game-State-Sync-Threads.
Jeder verbundene Client kann das jederzeit auslösen — es handelt sich um Speicher korruption, nicht um einen reinen DoS.
Ursache
Der Verarbeitungs-Loop testet und setzt Bits an der vom Client gelieferten Position, bevor der Spielerindex überhaupt geprüft wird:
thread_local eastl::bitset<roundToType<size_t>(MAX_CLIENTS)> processed;
processed.reset();
for (const uint16_t player : targetPlayersSpan)
{
if (processed.test(player)) // client-kontrolliert, KEIN Bounds-Check → OOB-Read
{
continue;
}
processed.set(player); // OOB-Write
auto targetClient = clientRegistry->GetClientByNetID(player); // erste Prüfung — zu spät
}
Das Bitset ist nur für die maximale Spielerzahl dimensioniert (wenige hundert Byte). Ein
Zugriff mit einem Wert nahe dem 16-Bit-Maximum landet mehrere Kilobyte hinter dem Objekt.
eastl::bitset::test/set prüft die Position im Release-Build nicht — der Bereichs-Check
ist dort nur ein Debug-Assert. Zusätzlich fehlt dem V2-Handler als einzigem in seiner
Nachbarschaft ein Rate-Limiter.
Auswirkung
- DoS: zuverlässiger Absturz des Sync-Threads bzw. des Prozesses, sobald der Schreib zugriff eine ungemappte Seite oder eine kritische Struktur trifft.
- Speicherkorruption: der Schreibzugriff landet im angrenzenden Thread-Local-Bereich, in dem weitere Objekte anderer Serverkomponenten liegen. Stille Korruption von Server-State ist denkbar; die konkrete Auswirkung hängt vom Heap-Layout des Builds ab.
Behebung
Eine Bereichsprüfung vor dem Bitset-Zugriff genügt:
for (const uint16_t player : targetPlayersSpan)
{
if (player >= MAX_CLIENTS) // fehlte
{
continue;
}
if (processed.test(player)) { /* ... */ }
}
Zusätzlich empfohlen: einen Rate-Limiter analog zu den Nachbar-Handlern ergänzen.