Few vulnerabilities in <= VLC media player 2.0.1 demuxers

After two mails to VLC security team and lack of answer I decided to public this research before any patch. Presented here vulns are not too evil (Local DoS) so making them public will not cause any damage for VLC users.

==[ Details ]==
<= VLC media player 2.0.1 contains vulnerabilities in few Demuxers:

1.	voc.c – DoS via Divison by 0
2.	smf.c – DoS via Infinite loop
3.	au.c  – DoS via Division by 0

1. Details voc.c – DoS via Divison by 0:
First scenario:
ReadBlockHeader function to handle block data type 0x9 contains the following code:

Line 304:
        case 9: /* newer data block with channel number and bits resolution */
            if( i_block_size < 12 )
                goto corrupt;
            i_block_size -= 12;

            if( ( stream_Read( p_demux->s, buf, 8 ) < 8 )
             || ( stream_Read( p_demux->s, NULL, 4 ) < 4 ) )
                goto corrupt;

            new_fmt.audio.i_rate = GetDWLE( buf );
            new_fmt.audio.i_bitspersample = buf[4];
            new_fmt.audio.i_channels = buf[5];

If block header at offset 0x5 will be set to 0 then new_fmt.audio.i_channels = 0, what causes:

Line 360:
  new_fmt.audio.i_bytes_per_frame = new_fmt.audio.i_channels
                * (new_fmt.audio.i_bitspersample / 8);

that new_fmt.audio.i_bytes_per_frame will be set to 0 and after exit from ReadBlockHeader the following code:

Line 428:
    while( ( i_offset >= p_sys->i_block_end )
         && ( p_sys->i_silence_countdown == 0 ) )
        if( ReadBlockHeader( p_demux ) != VLC_SUCCESS )
            return 0;

    if( p_sys->i_silence_countdown == 0 )
    {
        i = ( p_sys->i_block_end - i_offset )
            / p_sys->fmt.audio.i_bytes_per_frame; // <- div by 0

in Demux function leads to division by zero and as an end result VLC crash.

Second scenario:
Because at the beginning in ReadBlockHeader function, structure new_fmt (es_format_t) is initialized by zero:

Line 175:
es_format_Init( &new_fmt, AUDIO_ES, 0 );

therefore if type of first block will be set to different one where “normal” new_fmt structure initialization occurs e.g 0x6 then at the end of
ReadBlockHeader ,

Line 399:
        if( p_sys->p_es == NULL )
        {
            memcpy( &p_sys->fmt, &new_fmt, sizeof( p_sys->fmt ) );

new_fmt structure initialized by 0 will be copied to p_sys->fmt which leads to division by zero after return to Demux function like in above scenario.

2. smf.c – DoS via Infinite loop
In Open function we see the following code:


Line 210:
        for (;;)
        {
            stream_Read (stream, head, 8);
            if (memcmp (head, "MTrk", 4) == 0)
                break;

            msg_Dbg (p_this, "skipping unknown SMF chunk");
            stream_Read (stream, NULL, GetDWBE (head + 4));
        }

it aim is to find „MTrk” ID chunk. But like we can also notice there is lack of checks for stream_Read function indicating that end of stream occurred.
File with malformed or without “MTrk” ID chunk will cause infinite loop and as a result VLC DoS.

3 au.c – DoS via Division by 0

Line 144:    
	/* init fmt */
    es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
    p_sys->fmt.audio.i_rate     = GetDWBE( &hdr[12] );
    p_sys->fmt.audio.i_channels = GetDWBE( &hdr[16] );

setting 0(DWORD) at file offset len(“.snd”)+12 => 16 we set 0 value for i_rate field. Lack of any inspection of this field and its value leads to division by zero at

Line 278:
    p_sys->i_frame_length = (mtime_t)1000000 *
                            (mtime_t)i_samples /
                            (mtime_t)p_sys->fmt.audio.i_rate;

and as an end result to VLC crash.

==[ Proof of Concept ]==

1. voc.c - DoS via Divison by 0:
File sample: http://samples.libav.org/voc/pcm_s16_2/nem.voc
First scenario:
Change offset 0x23 value from 0x02 to 0x0

Second scenario:
Change offset  0x1A value from 0x060C842E to 0x06020000

2. smf.c - DoS via Infinite loop

File sample: http://upload.wikimedia.org/wikipedia/commons/6/61/Drum_sample.mid
Malform “MTrk” chunk ID anyhow e.g “ATrk”.


3. au.c - DoS via Division by 0

File sample: http://samples.libav.org/au/garelka.au
Change offset 0x10  value from 0x00001F40  to 0x00000000
This entry was posted in Bugs, Security and tagged , , , . Bookmark the permalink.

Comments are closed.