Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-1801C — Análisis estático de ingeniería inversa de las heurísticas de entrada de movimiento en el motor Source 2, identificando casos límite estructurales en la automatización de entradas y las rutinas de limitación de velocidad de salto. | Kitploit
Herramientas/GitHubGitHub/misterdengi/cve-2026-1801c
Análisis de VulnerabilidadesExplotaciónIngeniería InversaAnálisis de BinariosPapers e Investigación
GitHubmisterdengi/cve-2026-1801c

CVE-2026-1801C

Análisis estático de ingeniería inversa de las heurísticas de entrada de movimiento en el motor Source 2, identificando casos límite estructurales en la automatización de entradas y las rutinas de limitación de velocidad de salto.

Ver Repositorio
2hace 5h 47mAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2026-1801C (QUANTUM-SHIFT) / CVE-2026-180A7 (BAL-JUMP): Análisis Estático de Heurísticas de Entrada de Movimiento en Source 2 (server.dll)

Resumen

Este documento presenta un análisis estático de ingeniería inversa de dos rutinas de verificación de movimiento del lado del cliente implementadas en el motor de Counter-Strike 2 (server.dll): el evaluador de automatización de entrada / SOCD (sub_1801C6B30, designado CVE-2026-1801C / QUANTUM-SHIFT) y el limitador de tasa de solicitudes de salto (sub_180A7EDB0, designado CVE-2026-180A7 / BAL-JUMP). Mediante análisis de desensamblado y modelado matemático formal de las máquinas de estado subyacentes, demostramos casos límite estructurales en ambas heurísticas. Específicamente, documentamos cómo la cuantización temporal discreta en sub_1801C6B30 crea un límite de clasificación invariante bajo desplazamientos de fase fijos de un solo tick, y cómo depende de una métrica de intervalo univariante ($\Delta t$) que permanece invariante bajo disparadores de impulso único bloqueados por fase.

sub_180A7EDB0

1. Verificación de Automatización de Entrada (sub_1801C6B30)

1.1 Especificación de la Rutina

  • Binario Objetivo: server.dll (Compilación Minorista Win64)
  • Desplazamiento de Símbolo: 0x1C6B30
  • Interfaz: void __fastcall sub_1801C6B30(int *pMovementServices, __int64 pPlayerController, __int64 pUserCmdPB)

1.2 Pipeline de Ejecución y Representación de Estado

La rutina evalúa eventos de transición de botones de movimiento (+moveleft / +moveright) enviados a través de payloads de cliente CBaseUserCmdPB. La ejecución sigue un pipeline condicional:

  1. Filtrado de Velocidad: La magnitud escalar al cuadrado de la velocidad 2D del pawn del jugador debe superar un umbral estático: $$|v_{xy}|^2 > (0.52 \cdot 260.0)^2 = 18279.04 \text{ unit}^2/\text{s}^2$$
  2. Cuantización Temporal: Los deltas de fase de transición ($\Delta t_{\text{trans}}$) se cuantizan a unidades discretas 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. Clasificación Simbólica: El valor entero $k \in [0, 15]$ se asigna a un código de evento discreto $c \in {1, 2, 3}$: $$c = \begin{cases} 1 & \text{si } k = 0 \text{ (Transición ideal de 0 ticks)} \ 2 & \text{si } k \ge 1 \text{ y el estado es Solapamiento} \ 3 & \text{si } k \ge 1 \text{ y el estado es Sub-solapamiento} \end{cases}$$
  4. Almacenamiento en Buffer Circular: El código de clasificación $c$ se almacena en un array de historial circular de capacidad $N$ (sv_auto_cstrafe_attempt_window, por defecto 100).

1.3 Lógica Descompilada (sub_1801C6B30)

root@kitploit:~
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]);
    
    // Filtrado: Umbral mínimo de velocidad
    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;

    // Asignación de Símbolo
    char symbolCode;
    if (roundedTicks == 0)
        symbolCode = 1; // Éxito / 0 ticks perfecto
    else
        symbolCode = bIsOverlap ? 2 : 3; // Solapamiento o Sub-solapamiento

    // Obtener punteros de configuración ConVar
    unsigned int windowCap = *GetConVarUInt(&unk_181DDBD30, &qword_181DDBD38);
    if (windowCap - 1 > 999)
        return;

    sub_1801ECEA0(pMovementServices, windowCap);

    // Añadir símbolo al buffer circular
    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;
        }
    }

    // Actualizar histogramas de frecuencia de ticks discretos
    if (bIsOverlap)
        pMovementServices[roundedTicks + 7]++;
    else
        pMovementServices[roundedTicks + 23]++;

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

    // Evaluar métricas de secuencia de ventana deslizante
    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++;
            }
        }

        // Actualización de ventana deslizante
        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); // Por defecto 20.0%
            float upperPct = *GetConVarFloat(&unk_181DDBD60, &qword_181DDBD68); // Por defecto 5.0%
            
            dynamicLimit = (lowerPct - upperPct) * successRatio + upperPct;
        }
    }

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

    // Condición de Violación: El límite dinámico supera la proporción de solapamiento observada
    if (dynamicLimit > observedOverlapPct)
    {
        sub_1801ECEA0(pMovementServices, 0); // Vaciar estado del buffer
        
        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);

            int slotIdx = -1;
            sub_181265470(pPlayerController, &slotIdx);
            
            // Código de Desconexión 162: NETWORK_DISCONNECT_KICKED_INPUTAUTOMATION
            pfnKickClient(pEngine, (unsigned int)(slotIdx - 1), 0, 162);
        }
    }
}

1.4 Modelo Matemático y Análisis de Clasificación

Sea $\mathbf{S} = {s_1, s_2, \dots, s_N}$ la secuencia de símbolos de eventos en el buffer de historial de tamaño $N$. El parámetro $S_{\text{max}}$ denota el número máximo de símbolos de código $1$ ($s_i = 1$) dentro de cualquier sub-secuencia contigua de longitud $L$:

$$S_{\text{max}} = \max_{0 \le j \le N - L} \sum_{i=j}^{j+L-1} \mathbb{I}(s_i = 1)$$

La función de umbral adaptativo $T(S_{\text{max}})$ está condicionada a $S_{\text{max}} \ge S_{\text{thresh}}$:

$$T(S_{\text{max}}) = \begin{cases} \theta_{\text{upper}} + (\theta_{\text{lower}} - \theta_{\text{upper}}) \cdot \frac{S_{\text{max}} - S_{\text{thresh}}}{L - S_{\text{thresh}}} & \text{si } S_{\text{max}} \ge S_{\text{thresh}} \ 0 & \text{si } S_{\text{max}} < S_{\text{thresh}} \end{cases}$$

Donde los valores de configuración por defecto se definen como:

  • $L = 15$ (sv_auto_cstrafe_sequence_length)
  • $S_{\text{thresh}} = 10$ (sv_auto_cstrafe_success_threshold)
  • $\theta_{\text{lower}} = 20.0$ (sv_auto_cstrafe_lower_overlap_pct_threshold)
  • $\theta_{\text{upper}} = 5.0$ (sv_auto_cstrafe_upper_overlap_pct_threshold)

Se declara una violación si y solo si $T(S_{\text{max}}) > P_{\text{overlap}}$, donde $P_{\text{overlap}}$ es la proporción muestral de eventos de código $2$:

$$P_{\text{overlap}} = \frac{100}{N} \sum_{i=1}^{N} \mathbb{I}(s_i = 2)$$

Invariante Estructural

Para cualquier flujo de entrada donde el desplazamiento de fase $\Delta t_{\text{trans}}$ esté restringido de modo que $k = \text{round}(\Delta t_{\text{trans}} / \tau_{\text{tick}}) \ge 1$:

  1. $s_i \in {2, 3}$ para todo $i$, lo que produce $\mathbb{I}(s_i = 1) = 0$.
  2. En consecuencia, $S_{\text{max}} = 0$.
  3. Dado que $0 < S_{\text{thresh}}$, $T(S_{\text{max}}) = 0$ se cumple de manera idéntica.
  4. La desigualdad $0 > P_{\text{overlap}}$ se evalúa como falsa para todo $P_{\text{overlap}}$ no negativo. La ruta de evaluación que termina en pfnKickClient permanece sin ejecutarse.

2. Limitación de Tasa de Salto (sub_180A7EDB0)

2.1 Especificación de la Rutina

  • Binario Objetivo: server.dll (Compilación Minorista Win64)
  • Desplazamiento de Símbolo: 0x1A7EDB0
  • Interfaz: void* __fastcall sub_180A7EDB0(__int64 pMovementServices, __int64 pMoveData)

2.2 Lógica Descompilada (sub_180A7EDB0)

root@kitploit:~
void *__fastcall sub_180A7EDB0(__int64 pMovementServices, __int64 pMoveData)
{
    __int64 pPawn = *(_QWORD *)(pMovementServices + 8);
    sub_180C28550(pPawn, 2i64);
    
    if (!*(_QWORD *)(pPawn + 56))
        nullsub_908(pPawn);

    // Evaluación de colisión de casco y contacto con el suelo
    (*(void (__fastcall **)(_QWORD))(**(_QWORD **)(pPawn + 56) + 1624i64))(*(_QWORD *)(pPawn + 56));
    sub_1803CBD30(*(_QWORD *)(pPawn + 56));
    sub_1803CD4C0(*(_QWORD *)(pPawn + 56), v14);

    if (dword_181FDB358)
        --dword_181FDB358;

    // Comprobar bit IN_JUMP (0x2) en la máscara de botones de comando
    if ((*(_BYTE *)(pPawn + 88) & 2) != 0 || sub_180C28550(pPawn, 2i64))
    {
        _BYTE *pPenaltyActive = (_BYTE *)(pMovementServices + 16);
        if (*pPenaltyActive)
        {
            float curTime = *((float *)off_181C9F350 + 12);
            float lastJumpTime = *(float *)(pMovementServices + 20);
            float penaltyInterval = sub_18029CE70(&unk_181FDB4D8, 0xFFFFFFFFi64); // sv_jump_spam_penalty_time

            // Evaluación de intervalo: curTime > lastJumpTime + penaltyInterval
            if (curTime > (penaltyInterval + lastJumpTime))
            {
                if (*pPenaltyActive)
                {
                    sub_180A99DE0(pMovementServices + 16, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
                    *pPenaltyActive = 0; // Limpiar estado de penalización
                }

                // Aplicar impulso de salto
                sub_180A7F550(pMovementServices, pMoveData);

                if (!*pPenaltyActive)
                {
                    sub_180A99DE0(pPenaltyActive, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
                    *pPenaltyActive = 1; // Activar estado de penalización
                }

                if (sub_180C28550(*(_QWORD *)(pMovementServices + 8), 2i64))
                {
                    // Almacenar marca de tiempo de salto: lastJumpTime = curTime - frameTime
                    *(float *)(pMovementServices + 20) = *((float *)off_181C9F350 + 12) - 
                                                         *((float *)off_181C9F350 + 13);
                }
                return pMovementServices;
            }
        }

        bool bDebugSpam = *GetConVarByte(&unk_181FDB640, &qword_181FDB648);
        if (!bDebugSpam)
        {
            // Aplicar impulso de salto cuando la depuración de penalización está deshabilitada
            sub_180A7F550(pMovementServices, pMoveData);
            if (!*pPenaltyActive)
            {
                sub_180A99DE0(pPenaltyActive, 0xFFFFFFFFi64, 0xFFFFFFFFi64);
                *pPenaltyActive = 1;
            }
            *(float *)(pMovementServices + 20) = *((float *)off_181C9F350 + 12) - 
                                                 *((float *)off_181C9F350 + 13);
        }
    }
    return pMovementServices;
}

2.3 Modelo de Temporización y Evaluación de Intervalo

Sea $t_n$ la marca de tiempo de ejecución de la $n$-ésima solicitud de salto, y $\tau_{\text{penalty}}$ el valor de sv_jump_spam_penalty_time (típicamente $1$ tick, o $\approx 15.625\text{ ms}$). La transición de estado para el indicador de penalización $P \in {0, 1}$ y la activación de impulso $I \in {0, 1}$ se define por:

$$I_n = \begin{cases} 1 & \text{si } P_{n-1} = 0 \text{ o } t_n - t_{n-1} > \tau_{\text{penalty}} \ 0 & \text{si } P_{n-1} = 1 \text{ y } t_n - t_{n-1} \le \tau_{\text{penalty}} \end{cases}$$

Análisis de Entradas de Alta Frecuencia vs. Bloqueadas por Estado de Suelo

  1. Flujos de Entrada de Alta Frecuencia: Los flujos de entrada discretos generados en frames consecutivos producen intervalos $t_n - t_{n-1} \approx \tau_{\text{tick}} \le \tau_{\text{penalty}}$. Bajo esta condición, $I_n = 0$, suprimiendo la generación de impulso vertical.
  2. Bloqueo de Fase por Estado de Suelo: Si un comando de salto se emite exclusivamente al transicionar al estado FL_ONGROUND ($P_{\text{ground}} = 1$), la duración entre solicitudes corresponde a la duración del vuelo balístico $T_{\text{flight}}$:

$$t_n - t_{n-1} = T_{\text{flight}} \ge \frac{2 \cdot v_z}{g} \approx 300\text{--}500\text{ ms}$$

Debido a que $T_{\text{flight}} \gg \tau_{\text{penalty}}$, el predicado $t_n - t_{n-1} > \tau_{\text{penalty}}$ se cumple incondicionalmente para todo $n$, impidiendo la activación de la ruta de supresión.


3. Resumen de Remediación Estructural

ComponenteSímbolo ObjetivoPrimitiva ActualDebilidad AnalíticaRemediación Propuesta
Automatización de Entradasub_1801C6B30Clasificación binaria ($k=0$ vs $k \ge 1$) + umbralizaciónDesplazamiento de fase fijo ($k=1$) produce $S_{\text{max}} = 0$ de manera idénticaEvaluar la varianza muestral $\sigma^2(\Delta t)$ en todos los $k$; marcar distribuciones de baja varianza independientemente del índice de bin
Limitación de Tasa de Saltosub_180A7EDB0Comparación escalar de delta temporal ($t_n - t_{n-1} > \tau$)Invariante bajo retrasos de fase en el aire ($T_{\text{flight}} \gg \tau$)Evaluar la continuidad del vector de velocidad y la duración del contacto con el suelo ($\Delta t_{\text{contact}}$)
Descargar herramienta