Lucene search
K

VLC 2.2.8 MP4 Demux Type Conversion Vulnerability

🗓️ 17 Dec 2017 00:00:00Reported by Hans Jerry IllikainenType 
zdt
 zdt
🔗 0day.today👁 70 Views

VLC 2.2.8 MP4 Demux Type Conversion Vulnerability in MP4 demux module allows arbitrary free causing a security risk

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2017-17670
26 May 202605:00
circl
CNVD
VideoLAN VLC media player MP4 demux module denial of service vulnerability
18 Dec 201700:00
cnvd
CVE
CVE-2017-17670
15 Dec 201709:00
cve
Cvelist
CVE-2017-17670
15 Dec 201709:00
cvelist
Debian
[SECURITY] [DSA 4203-1] vlc security update
17 May 201815:24
debian
Debian CVE
CVE-2017-17670
15 Dec 201709:00
debiancve
Tenable Nessus
Debian DSA-4203-1 : vlc - security update
18 May 201800:00
nessus
Tenable Nessus
Linux Distros Unpatched Vulnerability : CVE-2017-17670
25 Aug 202500:00
nessus
Tenable Nessus
VLC < 2.2.9 Type Conversion Vulnerability
27 May 202000:00
nessus
EUVD
EUVD-2017-8827
7 Oct 202500:30
euvd
Rows per page
About
=====

A type conversion vulnerability exist in the MP4 demux module in VLC
<=2.2.8.  This issue has been assigned CVE-2017-17670 and it could be
used to cause an arbitrary free.


Details
=======

MP4 is a container format for video, audio, subtitles and images.  The
various parts of an .mp4 are organized as hierarchical boxes/atoms in
big-endian byte ordering [1].

VLC processes these boxes by using a lookup table:

vlc-2.2.8/modules/demux/mp4/libmp4.c
,----
| 3297 static const struct
| 3298 {
| 3299     uint32_t i_type;
| 3300     int  (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
| 3301     void (*MP4_FreeBox_function )( MP4_Box_t *p_box );
| 3302     uint32_t i_parent; /* set parent to restrict, duplicating if needed; 0 for any */
| 3303 } MP4_Box_Function [] =
| 3304 {
| 3305     /* Containers */
| 3306     { ATOM_moov,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, 0 },
| 3307     { ATOM_trak,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_moov },
| ....
| 3565     /* Last entry */
| 3566     { 0,              MP4_ReadBox_default,      NULL, 0 }
| 3567 };
`----

vlc-2.2.8/modules/demux/mp4/libmp4.c
,----
| 3574 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
| 3575 {
| 3576     MP4_Box_t *p_box = calloc( 1, sizeof( MP4_Box_t ) ); /* Needed to ensure simple on error handler */
| 3577     unsigned int i_index;
| ....
| 3582     if( !MP4_ReadBoxCommon( p_stream, p_box ) )
| 3583     {
| ....
| 3587     }
| ....
| 3605     /* Now search function to call */
| 3606     for( i_index = 0; ; i_index++ )
| 3607     {
| ....
| 3613         if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
| 3614             ( MP4_Box_Function[i_index].i_type == 0 ) )
| 3615         {
| 3616             break;
| 3617         }
| 3618     }
| 3619
| 3620     if( !(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ) )
| 3621     {
| 3622         MP4_BoxFree( p_stream, p_box );
| 3623         return NULL;
| 3624     }
| 3625
| 3626     return p_box;
| 3627 }
`----


MP4_ReadBox() allocates a MP4_Box_t structure and invokes
MP4_ReadBoxCommon() to read the properties common to all mp4 boxes;
`i_size' and `i_type' (and optionally an extended size).  Afterwards,
MP4_Box_Function is used to dispatch further parsing to a suitable
function based on its `i_type'.

When VLC is done with the boxes, they are freed with MP4_BoxFree():

vlc-2.2.8/modules/demux/mp4/libmp4.c
,----
| 3633 void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
| 3634 {
| 3635     unsigned int i_index;
| ....
| 3650     /* Now search function to call */
| 3651     if( p_box->data.p_payload )
| 3652     {
| 3653         for( i_index = 0; ; i_index++ )
| 3654         {
| ....
| 3660             if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
| 3661                 ( MP4_Box_Function[i_index].i_type == 0 ) )
| 3662             {
| 3663                 break;
| 3664             }
| 3665         }
| 3666         if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
| 3667         {
| ....
| 3677         }
| 3678         else
| 3679         {
| 3680             MP4_Box_Function[i_index].MP4_FreeBox_function( p_box );
| 3681         }
| ....
| 3685 }
`----

Again, `i_type' is used to find a suitable free-function.

The reason this may be problematic is that `i_type' could be changed
when VLC handles `sinf' and `frma' boxes in TrackCreateES() -- meaning
that a box may be read as one type, and freed as another.

`sinf' is the "Protection Scheme Information Box" and it's used for
protected/encrypted media.  `frma' is the "Original Format Box" and it's
used to declare the format of the unprotected media.

If a sinf/frma is found underneath a sample box, the `i_type' of that
sample is replaced with the original format declared in the `frma':

vlc-2.2.8/modules/demux/mp4/mp4.c
,----
| 2180 static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
| 2181                           unsigned int i_chunk, es_out_id_t **pp_es )
| 2182 {
| ....
| 2208     p_sample = MP4_BoxGet(  p_track->p_stsd, "[%d]",
| 2209                             i_sample_description_index - 1 );
| ....
| 2219     p_track->p_sample = p_sample;
| 2220
| 2221     if( ( p_frma = MP4_BoxGet( p_track->p_sample, "sinf/frma" ) ) && p_frma->data.p_frma )
| 2222     {
| 2223         msg_Warn( p_demux, "Original Format Box: %4.4s", (char *)&p_frma->data.p_frma->i_type );
| 2224
| 2225         p_sample->i_type = p_frma->data.p_frma->i_type;
| 2226     }
| ....
`----

No sanity check is done to make sure that the MP4_FreeBox_function
associated with the new `i_type' is compatible with the old
MP4_ReadBox_function.


Example
=======

One way to abuse the type change is to have a `soun' changed to a
`vide'.  This results in a 72-byte allocation (x86-64) for the
`p_sample_soun' member of the p_box->data union when the box is read:

vlc-2.2.8/modules/demux/mp4/libmp4.c
,----
| 1614 static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
| 1615 {
| 1616     p_box->i_handler = ATOM_soun;
| 1617     MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
| ....
`----

vlc-2.2.8/modules/demux/mp4/libmp4.h
,----
| 1351 #define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \
| ....
| 1369     if( !( p_box->data.p_payload = calloc( 1, sizeof( MP4_Box_data_TYPE_t ) ) ) ) \
| 1370     { \
| ....
| 1373     }
`----

where `p_box' is MP4_Box_t:

vlc-2.2.8/modules/demux/mp4/libmp4.h
,----
| 1284 typedef struct MP4_Box_s
| 1285 {
| ....
| 1296     MP4_Box_data_t   data;   /* union of pointers on extended data depending
| 1297                                 on i_type (or i_usertype) */
| ....
| 1306 } MP4_Box_t;
`----

and MP4_Box_data_t:

vlc-2.2.8/modules/demux/mp4/libmp4.h
,----
| 1200 typedef union MP4_Box_data_s
| 1201 {
| ....
| 1220     MP4_Box_data_sample_vide_t *p_sample_vide;
| 1221     MP4_Box_data_sample_soun_t *p_sample_soun;
| ....
| 1278     void                *p_payload; /* for unknow type */
| 1279 } MP4_Box_data_t;
`----

,----
| (gdb) p sizeof(MP4_Box_data_sample_soun_t)
| $1 = 72
`----

After the box has had its type changed to `vide' and it's later freed,
the `p_sample_vide' member of the p_box->data union is used:

vlc-2.2.8/modules/demux/mp4/libmp4.c
,----
| 1861 void MP4_FreeBox_sample_vide( MP4_Box_t *p_box )
| 1862 {
| 1863     FREENULL( p_box->data.p_sample_vide->p_qt_image_description );
| 1864 }
`----

,----
| (gdb) p sizeof(MP4_Box_data_sample_vide_t)
| $2 = 96
| (gdb)
`----

vlc-2.2.8/modules/demux/mp4/libmp4.h
,----
| 529 typedef struct MP4_Box_data_sample_vide_s
| 530 {
| ...
| 557     uint8_t *p_qt_image_description;
| 558
| 559 } MP4_Box_data_sample_vide_t;
`----

`p_sample_vide' is 24 bytes larger than `p_sample_soun', and
`p_qt_image_description' is at the end of the vide struct; i.e. the
pointer to be free()d is read out-of-bounds from potentially
user-controlled memory.

`mkmp4.py' at [2]

,----
| $ uname -imrs
| FreeBSD 11.1-RELEASE-p4 amd64 GENERIC
| $ ./mkmp4.py file.mp4
| $ vlc --version
| VLC media player 2.2.8 Weatherwax (revision 2.2.7-14-g3cc1d8cba9)
| $ gdb -q --args vlc file.mp4
| (gdb) set breakpoint pending on
| (gdb) b libmp4.c:1618
| No source file named libmp4.c.
| Breakpoint 1 (libmp4.c:1618) pending.
| (gdb) b libmp4.c:1863
| No source file named libmp4.c.
| Breakpoint 2 (libmp4.c:1863) pending.
| (gdb) r
| [...]
| Breakpoint 3, MP4_ReadBox_sample_soun (p_stream=0x802ab2710, p_box=0x802a85000) at demux/mp4/libmp4.c:1618
| 1618        p_box->data.p_sample_soun->p_qt_description = NULL;
| (gdb) p p_box->data.p_sample_soun
| $1 = (MP4_Box_data_sample_soun_t *) 0x802a79810
| (gdb) c
| Continuing.
|
| Breakpoint 4, MP4_FreeBox_sample_vide (p_box=0x802a85000) at demux/mp4/libmp4.c:1863
| 1863        FREENULL( p_box->data.p_sample_vide->p_qt_image_description );
| (gdb) p p_box->data.p_sample_vide
| $2 = (MP4_Box_data_sample_vide_t *) 0x802a79810
| (gdb) p p_box->data.p_sample_vide->p_qt_image_description
| $3 = (uint8_t *) 0x1122334455667788 <Error reading address 0x1122334455667788: Bad address>
| (gdb) b free
| Breakpoint 5 at 0x8019d3ce4
| (gdb) c
| Continuing.
|
| Breakpoint 5, 0x00000008019d3ce4 in free () from /lib/libc.so.7
| (gdb) p/x $rdi
| $4 = 0x1122334455667788
| (gdb) c
| Continuing.
|
| Program received signal SIGBUS, Bus error.
| 0x00000008019d36f3 in realloc () from /lib/libc.so.7
| (gdb) x/i $rip
| 0x8019d36f3 <realloc+3939>:     mov    rbx,QWORD PTR [rax+rcx*8+0x68]
| (gdb) i r
| rax            0x1122334455600000       1234605616436084736
| rbx            0x1122334455667788       1234605616436508552
| rcx            0x5a     90
| [...]
| (gdb) bt 4
| #0  0x00000008019d36f3 in realloc () from /lib/libc.so.7
| #1  0x00000008019d3d51 in free () from /lib/libc.so.7
| #2  0x0000000806d7fafd in MP4_FreeBox_sample_vide (p_box=0x802a85000) at demux/mp4/libmp4.c:1863
| #3  0x0000000806d7fcfd in MP4_BoxFree (s=0x802ab2710, p_box=0x802a85000) at demux/mp4/libmp4.c:3680
`----


Solution
========

This issue does not affect the HEAD of the VLC master branch.



Footnotes
_________

[1] [http://xhelmboyx.tripod.com/formats/mp4-layout.txt]

[2] [https://gist.github.com/dyntopia/194d912287656f66dd502158b0cd2e68]


-- 
hji

#  0day.today [2018-04-08]  #

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

17 Dec 2017 00:00Current
8.8High risk
Vulners AI Score8.8
EPSS0.01254
70