ponchio / untrunc

Restore a damaged (truncated) mp4, m4v, mov, 3gp video. Provided you have a similar not broken video.
GNU General Public License v2.0
1.63k stars 229 forks source link

null pointer reference in libav #131

Open jinyu00 opened 6 years ago

jinyu00 commented 6 years ago

When open a crafted mp4 file, The program could be Segmentation fault

lsl@yhk-RH2485-V2:~/workplace/untrunc-master$ ./untrunc ~/pocs/untrunc_null_ptr_ref_poc 
Reading: /home/lsl/pocs/untrunc_null_ptr_ref_poc
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x2ebf1c0] Could not find codec parameters (Audio: [0][0][0][0] / 0x0000
      0 channels, 127 kb/s)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/lsl/pocs/untrunc_null_ptr_ref_poc':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2mp41
    encoder         : Lavf56.40.101
  Duration: 00:00:00.04, start: 0.000000, bitrate: 257 kb/s
    Stream #0:0(und): Audio: [0][0][0][0] / 0x0000
      0 channels, 127 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
Segmentation fault

Now let see in gdb


[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x1 
RCX: 0x1562940 --> 0x1561be8 --> 0x0 
RDX: 0x7ffff6f5c770 --> 0x1560e00 --> 0x0 
RSI: 0xffffffff 
RDI: 0x7fffffffde7f --> 0x7fffffffdff000 
RBP: 0x7fffffffdec0 --> 0x7fffffffdff0 --> 0x7fffffffe0e0 --> 0x7fffffffe180 --> 0x7fffffffe250 --> 0x0 
RSP: 0x7fffffffde50 --> 0x1565a00 --> 0xa4aa90 --> 0x44b1ba (<_ZN4AtomD2Ev>:    push   rbp)
RIP: 0x443a0a (<_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+126>:   mov    rax,QWORD PTR [rax])
R8 : 0x0 
R9 : 0x1560e10 --> 0x1562940 --> 0x1561be8 --> 0x0 
R10: 0x2 
R11: 0x7ffff6d24150 --> 0xfffda660fffda38f 
R12: 0x0 
R13: 0x0 
R14: 0x1 
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x4439fe <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+114>:  mov    rdi,rax
   0x443a01 <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+117>:  call   0x404500 <_ZNSaIcED1Ev@plt>
   0x443a06 <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+122>:  mov    rax,QWORD PTR [rbp-0x28]
=> 0x443a0a <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+126>:  mov    rax,QWORD PTR [rax]
   0x443a0d <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+129>:  add    rax,0x28
   0x443a11 <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+133>:  mov    rax,QWORD PTR [rax]
   0x443a14 <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+136>:  mov    rdx,QWORD PTR [rbp-0x28]
   0x443a18 <_ZN5Codec5parseEP4AtomRSt6vectorIiSaIiEES1_+140>:  mov    esi,0x4
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffde50 --> 0x1565a00 --> 0xa4aa90 --> 0x44b1ba (<_ZN4AtomD2Ev>:   push   rbp)
0008| 0x7fffffffde58 --> 0x7fffffffe088 --> 0x1564110 --> 0x19f0000002c 
0016| 0x7fffffffde60 --> 0x1565b50 --> 0xa4aa90 --> 0x44b1ba (<_ZN4AtomD2Ev>:   push   rbp)
0024| 0x7fffffffde68 --> 0x7fffffffe050 --> 0x7ffff7792878 --> 0x0 
0032| 0x7fffffffde70 --> 0x7fffffffdea0 --> 0x0 
0040| 0x7fffffffde78 --> 0x1 
0048| 0x7fffffffde80 --> 0x7fffffffdff0 --> 0x7fffffffe0e0 --> 0x7fffffffe180 --> 0x7fffffffe250 --> 0x0 
0056| 0x7fffffffde88 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000443a0a in Codec::parse(Atom*, std::vector<int, std::allocator<int> >&, Atom*) ()
gdb-peda$ bt
#0  0x0000000000443a0a in Codec::parse(Atom*, std::vector<int, std::allocator<int> >&, Atom*) ()
#1  0x0000000000445565 in Track::parse(Atom*, Atom*) ()
#2  0x000000000045227e in Mp4::parseTracks() ()
#3  0x0000000000450a10 in Mp4::open(std::string) ()
#4  0x0000000000443512 in main ()
#5  0x00007ffff6bbbf45 in __libc_start_main (main=0x4432d3 <main>, argc=0x2, argv=0x7fffffffe338, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe328) at libc-start.c:287
#6  0x0000000000442400 in _start ()
gdb-peda$ 

Crash at 0x443a0a, the asm code are as below

mov    rax,QWORD PTR [rax]

and rax=0 , so null pointer reference

The vulnerability is in track.cpp


void Codec::parse(Atom *trak, vector<int> &offsets, Atom *mdat) {
    Atom *stsd = trak->atomByName("stsd");
    int entries = stsd->readInt(4);  // crash at there
    if(entries != 1)
        throw string("Multiplexed stream! Not supported");
    ..........................
    ..........................
    ..........................
}

From the debug session , I find that the following line tigger the vulnerability

int entries = stsd->readInt(4);  // crash at there

stsd obj is a null pointer , let's see in trak->atomByName

Atom *Atom::atomByName(std::string name) {
    for(unsigned int i = 0; i < children.size(); i++) {
        if(children[i]->name == name)
            return children[i];
        Atom *a = children[i]->atomByName(name);
        if(a) return a;
    }
    return NULL;
}

The function could return NULL, but Codec::parse don't consider it.

To fix it , may be only need to check the Atom::atomByName 's return value

The poc file

https://gitee.com/hac425/fuzz_data/blob/master/untrunc_null_ptr_ref_poc
Hacklin commented 6 years ago

There are several Maintenance: Pull Requests that address issues like this. Let me know, if you have bugs like this null-pointer dereference with these Maintenance: patches.

Alternatively, you could use @anthwlock Untrunc repository.