Capítulo 4: Patch Diffing
El "Patch Diffing" es el proceso de comparar dos versiones de un programa, una con un parche de seguridad y otra sin él, para identificar la vulnerabilidad que el parche corrige. Es una técnica crucial para los investigadores de seguridad que quieren entender cómo funciona una vulnerabilidad y cómo explotarla.
4.1. 3.1 Fundamentos de Patch Diffing
El Proceso:
- Obtener los Binarios: Se necesitan las dos versiones del binario: la vulnerable y la parcheada.
- Diferenciar los Binarios: Se utiliza una herramienta de "diffing" binario (como
bindiff,Ghidra, oIDA Pro) para comparar los dos archivos. - Analizar las Diferencias: El investigador analiza las funciones que han cambiado para identificar la vulnerabilidad.
- Desarrollar un PoC: Una vez que se entiende la vulnerabilidad, se puede desarrollar una prueba de concepto (PoC) para demostrarla.
4.2. 3.2 Extracción de Parches de Windows
En Windows, los parches de seguridad se distribuyen como archivos MSU. Estos archivos se pueden extraer para obtener los binarios actualizados.
Script de Extracción PowerShell (Extract-Patch.ps1):
Un script de PowerShell puede automatizar el proceso de descarga y extracción de parches de Windows Update.
4.3. 3.3 Herramientas de Diffing Binario
- Ghidra y Ghidriff: Ghidra es un framework de ingeniería inversa de software de la NSA. Ghidriff es una extensión de Ghidra que facilita el "diffing" de binarios.
- BinDiff: Una popular herramienta de "diffing" para IDA Pro.
- Version Tracking de Ghidra: Ghidra también tiene una función de "version tracking" incorporada que se puede utilizar para comparar binarios.
4.4. 3.4 Caso de Estudio: CVE-2022-34718 (EvilESP)
Este caso de estudio muestra cómo se utilizó el "patch diffing" para analizar una vulnerabilidad en el protocolo ESP de Windows. El análisis reveló un error en el manejo de paquetes ESP fragmentados que podía llevar a la ejecución remota de código.
Información del CVE:
| Atributo | Valor |
|---|---|
| CVE | CVE-2022-34718 |
| Nombre | "EvilESP" |
| Componente | tcpip.sys (Windows TCP/IP Driver) |
| Tipo | Remote Code Execution (RCE) |
| CVSS | 9.8 (Crítico) |
| Vector | Red, sin autenticación (con IPsec habilitado) |
| Versiones | Windows Server 2012-2022, Windows 10/11 |
| Parche | Septiembre 2022 (KB5017308, KB5017305) |
Prerrequisitos para Explotación:
| Prerrequisito | Descripción |
|---|---|
| IPv6 habilitado | Default en Windows |
| IPsec habilitado y SA establecida | |
| Atacante conoce SPI + clave HMAC | De la víctima |
| Atacante puede enviar paquetes IPv6 | A la víctima |
4.4.1. Adquisición de Binarios para EvilESP
# Crear directorio de trabajo
mkdir C:\EvilESP-Analysis
cd C:\EvilESP-Analysis
# Obtener tcpip.sys vulnerable (pre-Septiembre 2022)
# WinbIndex: https://winbindex.m417z.com/ → tcpip.sys → KB5016616
# Obtener tcpip.sys parcheado (Septiembre 2022+)
# WinbIndex → KB5017308 (Server 2022) o KB5017305 (Win 10/11)
# Descargar símbolos
$symchk = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe"
& $symchk tcpip_vulnerable.sys /s "SRV*.\Symbols*https://msdl.microsoft.com/download/symbols"
4.4.2. Ejecutar Diff y Análisis
ghidriff tcpip_vulnerable.sys tcpip_patched.sys \
--symbols-path .\Symbols \
--max-section-funcs 5000 \
--output tcpip_diff
# Esperado: Solo 2 funciones cambiadas
# - IppReceiveEsp
# - Ipv6pReassembleDatagram
4.4.3. Análisis de Código Vulnerable vs Parcheado
Función 1: IppReceiveEsp
Código Vulnerable:
void IppReceiveEsp(longlong param_1) {
iVar3 = IppReceiveEspNbl(...);
// BUG: Solo verifica 0 (éxito) o 0x105 (pendiente)
if ((iVar3 == 0) || (iVar3 == 0x105)) {
*(undefined4 *)((longlong)param_1 + 0x2c) = 0x3b;
return;
}
}
Código Parcheado:
void IppReceiveEsp(longlong param_1) {
iVar3 = IppReceiveEspNbl(...);
// FIX 1: Verificación de rango completa
if ((iVar3 != 0) && (1 < (uint)(iVar3 - 0x2b))) {
// FIX 2: Descartar paquetes inválidos
if ((iVar3 != 0x105) && (puVar3 != NULL)) {
IppDiscardReceivedPackets(
(longlong)puVar3, 6, param_1, 0, 0, 0, 0xe0004148);
return;
}
}
}
Función 2: Ipv6pReassembleDatagram
Código Vulnerable:
void Ipv6pReassembleDatagram(...) {
uVar11 = *(int *)(param_2 + 0x8c) + (uint)*(ushort *)(param_2 + 0x88);
// BUG 1: Sin verificación de overflow de 16 bits
// BUG 2: Sin validación de nextheader_offset
if (uVar1 < uVar13) {
memcpy(puVar5 + 5, *(void **)(param_2 + 0x80),
(ulonglong)*(ushort *)(param_2 + 0x88));
}
}
Código Parcheado:
void Ipv6pReassembleDatagram(...) {
uVar11 = *(int *)(param_2 + 0x8c) + (uint)*(ushort *)(param_2 + 0x88);
// FIX 1: Verificar overflow de 16 bits
if (uVar14 < 0x10001) {
// FIX 2: Validar nextheader_offset
if (*(ushort *)(param_2 + 0xbc) <= uVar13) {
// FIX 3: Verificar tamaño final
if (uVar14 + 0x28 < *(uint *)(lVar4 + 0x18)) {
// Registrar fallo
}
}
}
}
4.4.4. Flujo de Ataque
- Atacante crea paquetes IPv6 maliciosos con header ESP y fragmentos que causan overflow
- Paquete 1: Fragment con offset=0, M=1
- Paquete 2: Fragment con offset=24, M=0 (dispara reensamblaje)
- IppReceiveEsp() no valida correctamente el código de resultado
- Ipv6pReassembleDatagram() no verifica overflow ni nextheader_offset
- memcpy OOB → corrupción de memoria → RCE o BSOD
4.4.5. Estructura de Paquetes ESP
ESP Header (RFC 4303): - SPI (4 bytes) - Sequence Number (4 bytes) - Payload Data (variable) - Padding + Pad Length + Next Header
IPv6 Fragment Header: - Next Header (1 byte) - Fragment Offset (13 bits) + Flags - Identification (4 bytes)
4.4.6. Primitiva de Explotación
| Aspecto | Detalles |
|---|---|
| Tipo | Out-of-bounds write |
| Tamaño | Variable |
| Control de Offset | Via nextheader_offset |
| Trigger | Remoto, requiere IPsec SA |
| Prerrequisito | IPv6 enabled, IPsec corriendo |
4.4.7. Resumen del Parche
| Función | Vulnerabilidad | Fix |
|---|---|---|
| IppReceiveEsp | Validación faltante | Verificación de rango |
| IppReceiveEsp | Error continuo | IppDiscardReceivedPackets |
| Ipv6pReassembleDatagram | Integer overflow | Check: uVar14 < 0x10001 |
| Ipv6pReassembleDatagram | OOB offset | Check: offset <= buffer |
4.4.8. Lecciones
- Binary diffing es efectivo: 10,000+ funciones → solo 2 cambiaron
- Conocimiento de protocolos es esencial
- Bugs simples tienen alto impacto (CVSS 9.8)
- Vulnerabilidades multi-función son comunes
- Prerrequisitos limitan el riesgo real
- Parches revelan las condiciones de trigger
4.5. 3.5 Pipeline de Automatización de Patch Diffing
¿Por Qué Automatizar?
- Microsoft libera parches mensualmente (Patch Tuesday - 2do martes de cada mes)
- Analizar cada actualización manualmente consume mucho tiempo
- Detección temprana de vulnerabilidades provee ventaja competitiva
- La automatización permite monitoreo continuo
Etapas del Pipeline:
- MONITOREAR: MSRC API, Patch Tuesday
- DESCARGAR: WinbIndex, Update Catalog
- EXTRAER: Expand MSU, Extract CAB
- SÍMBOLOS: symchk.exe, Symbol Server
- DIFF: Ghidriff, BinDiff
- REPORTE: HTML/PDF, JSON para CI
- ALERTA: Email, Ticket, Slack/Teams
Script de Automatización Python para Ghidriff
#!/usr/bin/env python3
import subprocess
import json
import os
from pathlib import Path
from datetime import datetime
class PatchDiffer:
# ... (implementación del script)
4.6. 3.6 Patch Diffing en Linux Kernel
3.6.1. Diferencias con Windows
| Aspecto | Windows | Linux |
|---|---|---|
| Código Fuente | Cerrado (solo binarios) | Abierto (git.kernel.org) |
| Formato Binario | PE/COFF | ELF |
| Símbolos Debug | PDB via Symbol Server | DWARF en paquetes -dbgsym |
| Distribución | Windows Update | apt/yum + distro-specific |
| Modificaciones Vendor | Ninguna | Backports, parches custom |
3.6.2. Flujo de Trabajo para Linux
- Identificar Versiones de Kernel
- Descargar Imágenes de Kernel y Símbolos
- Extraer vmlinux
- Identificar Módulos Cambiados
- Diff con Ghidriff
3.6.3. Diff a Nivel de Código Fuente
# Clonar fuente del kernel
git clone --branch v6.8 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
# Buscar commits de CVE
git log --all --grep="CVE" --oneline | head -20
# Ver diff de commit específico
git show f342de4e2f33e0e39165d8639387aa6c19dff660
... (El resto del capítulo seguiría la misma estructura)
3.6.4. Ejemplo: CVE-2024-1086 (nf_tables UAF)
| Atributo | Valor |
|---|---|
| CVE | CVE-2024-1086 |
| Componente | nf_tables (subsistema Netfilter) |
| Tipo | Use-After-Free → LPE |
| CVSS | 7.8 (Alto) |
| Afecta | Linux 3.15 - 6.8 |
| Exploit Público | Sí (~99% success rate) |
Análisis del Bug: - Validación basada en máscara permitía valores como NF_DROP | extra_bits - & NF_VERDICT_MASK dejaba pasar verdicts "decorados" - Type confusion → UAF → LPE - Fix: Cambiar de validación por máscara a coincidencia exacta
3.6.5. Recursos para Linux Kernel
| Recurso | URL | Utilidad |
|---|---|---|
| syzbot | syzkaller.appspot.com | Reproducers, bisección automática |
| Ubuntu Security Notices | ubuntu.com/security/notices | Advisories de distro |
| kernel.org | git.kernel.org | Código fuente oficial |
4.7. Caso de Estudio: 7-Zip Path Traversal
4.7.1. Información del Caso
| Atributo | Valor |
|---|---|
| Software | 7-Zip File Archiver |
| Versiones Afectadas | 24.09 y anteriores |
| Tipo | Path Traversal via Symlink (CWE-22) |
| Impacto | Arbitrary File Write → RCE potencial |
| CVSS | 7.8 (Alto) |
4.7.2. Análisis del Parche
Archivo: CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
Cambio 1: IsSafePath con Parámetro WSL
// ANTES: bool IsSafePath(const UString &path)
// DESPUÉS: static bool IsSafePath(const UString &path, bool isWSL)
Cambio 2: Detección WSL-Aware
// ANTES: IsAbsolute = NName::IsAbsolutePath(path);
// DESPUÉS: IsAbsolute = isWSL ? IS_PATH_SEPAR(path[0]) : NName::IsAbsolutePath(path);
4.7.3. Escenario de Ataque
- Crear archivo con symlink WSL:
link -> /mnt/c/Users/Public/Desktop - 7-Zip 24.09: IsSafePath() sin isWSL=true → clasifica como "relativo"
- Symlink creado fuera del directorio de extracción
- → Arbitrary File Write → RCE via DLL hijacking
4.7.4. Checklist de Validación de Paths
Buscar: IsSafePath, ValidatePath, IsAbsolute, IsRelative, symlinks
Verificar: - ¿Detección cross-plataforma correcta? - ¿Symlinks WSL/Linux con semántica adecuada? - ¿Normalización antes de validación?
4.8. Conclusiones del Capítulo 4
-
El parche es frecuentemente la única fuente de verdad cuando los detalles del CVE son limitados.
-
Las herramientas automatizan pero no reemplazan el análisis humano - Ghidriff encuentra funciones cambiadas, tú entiendes por qué.
-
Los símbolos son multiplicadores de fuerza - Con PDBs ves
IppValidatePacketLength; sin ellos, vessub_1400A2F40. -
Patrones de corrección revelan clases de vulnerabilidad:
- Bounds checks → overflow/OOB
- Inicialización → memoria no inicializada
- Locks → race condition
-
Validación de input → input validation flaw
-
El patch diffing encuentra variantes - Al analizar un fix, frecuentemente se descubren bugs similares en código cercano.
-
El análisis cross-plataforma requiere conocimiento de ambas semánticas - Como se vio en 7-Zip.
-
La automatización transforma el análisis de reactivo a proactivo.
Preguntas de Discusión:
-
CVE-2022-34718 requiere IPsec SA pero recibió CVSS 9.8. ¿Cómo deberían los prerrequisitos afectar el rating?
-
El bug de EvilESP abarcó dos funciones. ¿Cómo podrían detectar vulnerabilidades cross-función?
-
La fragmentación IPv6 es fuente recurrente. ¿Qué hace que sea propensa a errores?
-
El fix de 7-Zip añadió múltiples cambios. ¿Cómo determinas cuál corrige la vulnerabilidad core?