Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-1801C — Analyse statique de rétro-ingénierie des heuristiques d'entrée de mouvement dans le moteur Source 2, identifiant les cas limites structurels dans l'automatisation des entrées et les routines de limitation du taux de saut. | Kitploit
Outils/GitHubGitHub/misterdengi/cve-2026-1801c
Analyse des VulnérabilitésExploitationRétro-ingénierieAnalyse de BinairesArticles et Recherche
GitHubmisterdengi/cve-2026-1801c

CVE-2026-1801C

Analyse statique de rétro-ingénierie des heuristiques d'entrée de mouvement dans le moteur Source 2, identifiant les cas limites structurels dans l'automatisation des entrées et les routines de limitation du taux de saut.

Voir le dépôt
23il y a 1 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-1801C (QUANTUM-SHIFT) / CVE-2026-180A7 (BAL-JUMP) : Analyse statique des heuristiques d'entrée de mouvement dans Source 2 (server.dll)

Résumé

Ce document présente une analyse statique de rétro-ingénierie de deux routines de vérification de mouvement côté client implémentées dans le moteur Counter-Strike 2 (server.dll) : l'évaluateur d'automatisation d'entrée / SOCD (sub_1801C6B30, désigné CVE-2026-1801C / QUANTUM-SHIFT) et le limiteur de débit des requêtes de saut (sub_180A7EDB0, désigné CVE-2026-180A7 / BAL-JUMP). Grâce à l'analyse de désassemblage et à la modélisation mathématique formelle des machines à états sous-jacentes, nous démontrons des cas limites structurels dans les deux heuristiques. Plus précisément, nous documentons comment la quantification temporelle discrète dans sub_1801C6B30 crée une frontière de classification invariante sous des décalages de phase fixes à tick unique, et comment sub_180A7EDB0 repose sur une métrique d'intervalle univariée ($\Delta t$) qui reste invariante sous des déclencheurs à impulsion unique verrouillés en phase.


1. Vérification de l'automatisation d'entrée (sub_1801C6B30)

1.1 Spécification de la routine

  • Binaire cible : server.dll (build commercial Win64)
  • Décalage de symbole : 0x1C6B30
  • Interface : void __fastcall sub_1801C6B30(int *pMovementServices, __int64 pPlayerController, __int64 pUserCmdPB)

1.2 Pipeline d'exécution et représentation d'état

La routine évalue les événements de transition des boutons de mouvement (+moveleft / +moveright) soumis via les charges utiles client CBaseUserCmdPB. L'exécution suit un pipeline conditionnel :

  1. Filtrage par vélocité : La magnitude scalaire au carré de la vélocité 2D du pion du joueur doit dépasser un seuil statique : $$|v_{xy}|^2 > (0.52 \cdot 260.0)^2 = 18279.04 \text{ unité}^2/\text{s}^2$$
  2. Quantification temporelle : Les deltas de phase de transition ($\Delta t_{\text{trans}}$) sont quantifiés en unités discrètes de ticks de frame : $$k = \text{round}\left( \frac{\Delta t_{\text{trans}}}{\tau_{\text{tick}}} \right), \quad \tau_{\text{tick}} \approx 15.625\text{ ms}$$
  3. Classification symbolique : La valeur entière $k \in [0, 15]$ correspond à un code d'événement discret $c \in {1, 2, 3}$ : $$c = \begin{cases} 1 & \text{si } k = 0 \text{ (transition idéale à 0 tick)} \ 2 & \text{si } k \ge 1 \text{ et l'état est Chevauchement} \ 3 & \text{si } k \ge 1 \text{ et l'état est Sous-chevauchement} \end{cases}$$
  4. Stockage en tampon circulaire : Le code de classification $c$ est stocké dans un tableau d'historique circulaire de capacité $N$ (sv_auto_cstrafe_attempt_window, valeur par défaut 100).

1.3 Logique décompilée (sub_1801C6B30)

void __fastcall sub_1801C6B30(int *pMovementServices, __int64 pPlayerController, __int64 pUserCmdPB)
{
    if (!pPlayerController || (*(_BYTE *)(pUserCmdPB + 16) & 1) == 0)
        return;

    __int64 pPawn = sub_180B137A0(pPlayerController);
    if (!pPawn || !(*(unsigned __int8 (__fastcall **)(__int64))(*(_QWORD *)pPawn + 3216i64))(pPawn))
        return;

    float *pVel = (float *)sub_1803CBD90(pPawn, &szVelocityBuf);
    float vSq = (pVel[0] * pVel[0]) + (pVel[1] * pVel[1]) + (pVel[2] * pVel[2]);
    
    // Filtrage : Seuil de vélocité minimale
    if (vSq <= 18279.04f)
        return;

    int rawTicks = *(_DWORD *)(pUserCmdPB + 24);
    bool bIsOverlap = (rawTicks >= 0);
    int absTicks = bIsOverlap ? rawTicks : ~rawTicks;

    double curTime = sub_1801F46D0(off_181C9F350);
    if (curTime * 1e-9 * (double)absTicks >= 15.5)
        return;

    int roundedTicks = (int)V_roundd();
    if ((unsigned int)roundedTicks > 15)
        return;

    // Attribution de symbole
    char symbolCode;
    if (roundedTicks == 0)
        symbolCode = 1; // Succès / 0-tick parfait
    else
        symbolCode = bIsOverlap ? 2 : 3; // Chevauchement ou Sous-chevauchement

    // Récupération des pointeurs de configuration ConVar
    unsigned int windowCap = *GetConVarUInt(&unk_181DDBD30, &qword_181DDBD38);
    if (windowCap - 1 > 999)
        return;

    sub_1801ECEA0(pMovementServices, windowCap);

    // Ajout du symbole au tampon circulaire
    int bufCap = pMovementServices[0];
    if (bufCap > 0)
    {
        int writeIdx = pMovementServices[6];
        if (writeIdx >= 0 && writeIdx < bufCap)
        {
            *(_BYTE *)(writeIdx + *((_QWORD *)pMovementServices + 1)) = symbolCode;
            if (++pMovementServices[6] == bufCap)
                pMovementServices[6] = 0;
        }
    }

    // Mise à jour des histogrammes de fréquence de ticks discrets
    if (bIsOverlap)
        pMovementServices[roundedTicks + 7]++;
    else
        pMovementServices[roundedTicks + 23]++;

    int seqLen = *GetConVarInt(&unk_181DDBD40, &qword_181DDBD48);
    if ((unsigned int)(seqLen - 1) > 999)
        return;

    // Évaluation des métriques de séquence en fenêtre glissante
    int totalValid = 0;
    int totalOverlaps = 0;
    int curSequenceSuccesses = 0;
    int maxSequenceSuccesses = 0;

    for (int i = 0; i < (int)windowCap; ++i)
    {
        if (i < bufCap)
        {
            int readIdx = i + pMovementServices[6] - bufCap;
            if (i + pMovementServices[6] < bufCap)
                readIdx = i + pMovementServices[6];

            char sym = *(_BYTE *)(readIdx + *((_QWORD *)pMovementServices + 1));
            if (sym != 0)
            {
                totalValid++;
                if (sym == 2) totalOverlaps++;
                else if (sym == 1) curSequenceSuccesses++;
            }
        }

        // Mise à jour de la fenêtre glissante
        if (i >= seqLen && (i - seqLen) >= 0)
        {
            if ((i - seqLen) < bufCap)
            {
                int popIdx = i + pMovementServices[6] - seqLen - bufCap;
                if (i + pMovementServices[6] - seqLen < bufCap)
                    popIdx = i + pMovementServices[6] - seqLen;

                if (*(_BYTE *)(popIdx + *((_QWORD *)pMovementServices + 1)) == 1)
                    curSequenceSuccesses--;
            }
        }

        if (maxSequenceSuccesses < curSequenceSuccesses)
            maxSequenceSuccesses = curSequenceSuccesses;
    }

    int minAttempts = *GetConVarInt(&unk_181DDBD20, &qword_181DDBD28);
    float dynamicLimit = 0.0f;

    if (totalValid >= minAttempts)
    {
        int minSuccessThreshold = *GetConVarInt(&unk_181DDBD50, &qword_181DDBD58);
        if (maxSequenceSuccesses >= minSuccessThreshold)
        {
            float successRatio = 0.0f;
            if (seqLen > minSuccessThreshold)
            {
                successRatio = (float)(maxSequenceSuccesses - minSuccessThreshold) / 
                               (float)(seqLen - minSuccessThreshold);
            }

            float lowerPct = *GetConVarFloat(&unk_181DDBD70, &qword_181DDBD78); // Défaut 20.0%
            float upperPct = *GetConVarFloat(&unk_181DDBD60, &qword_181DDBD68); // Défaut 5.0%
            
            dynamicLimit = (lowerPct - upperPct) * successRatio + upperPct;
        }
    }

    float observedOverlapPct = ((float)totalOverlaps / (float)totalValid) * 100.0f;

    // Condition de violation : La limite dynamique dépasse le ratio de chevauchement observé
    if (dynamicLimit > observedOverlapPct)
    {
        sub_1801ECEA0(pMovementServices, 0); // Vidage de l'état du tampon
        
        bool bEnableKick = *GetConVarByte(&unk_181DDBD90, &qword_181DDBD98);
        if (bEnableKick)
        {
            __int64 pEngine = qword_182012050;
            void (__fastcall *pfnKickClient)(__int64, unsigned int, _QWORD, __int64) = 
                *(void (__fastcall **)(__int64, unsigned int, _QWORD, __int64))(*(_QWORD *)pEngine + 768i64);
Télécharger l’outil