CVE-2017-9128复现与分析
2020-04-21 10:25:22 Author: xz.aliyun.com(查看原文) 阅读量:248 收藏

cve信息

The quicktime_video_width function in lqt_quicktime.c in libquicktime 1.2.4 allows remote attackers to cause a denial of service (heap-based buffer over-read and application crash) via a crafted mp4 file.

通过攻击者精心构造的一个mp4文件,能够使得libquicktime 1.2.4在调用

quicktime_video_width函数时造成堆空间越界读的操作,最后会导致程序crash,可引发拒绝服务

exp-db上是这么写的

the quicktime_video_width function in lqt_quicktime.c in libquicktime 1.2.4 can cause a denial of service(heap-buffer-overflow and application crash) via a crafted mp4 file.


./lqtplay libquicktime_1.2.4_quicktime_video_width_heap-buffer-overflow.mp4


=================================================================
==10979==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000009d00 at pc 0x7f36a1017a37 bp 0x7ffe65a90010 sp 0x7ffe65a90008
READ of size 4 at 0x602000009d00 thread T0
   #0 0x7f36a1017a36 in quicktime_video_width /home/a/Downloads/libquicktime-1.2.4/src/lqt_quicktime.c:998
   #1 0x7f36a1017a36 in quicktime_init_maps /home/a/Downloads/libquicktime-1.2.4/src/lqt_quicktime.c:1633
   #2 0x7f36a101af13 in quicktime_read_info /home/a/Downloads/libquicktime-1.2.4/src/lqt_quicktime.c:1891
   #3 0x7f36a10204a8 in do_open /home/a/Downloads/libquicktime-1.2.4/src/lqt_quicktime.c:2026
   #4 0x7f36a0ff15da in quicktime_open /home/a/Downloads/libquicktime-1.2.4/src/lqt_quicktime.c:2075
   #5 0x47fad2 in qt_init /home/a/Downloads/libquicktime-1.2.4/utils/lqtplay.c:987
   #6 0x47fad2 in main /home/a/Downloads/libquicktime-1.2.4/utils/lqtplay.c:1852
   #7 0x7f369e8d7ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
   #8 0x47f3dc in _start (/home/a/Downloads/libquicktime-1.2.4/utils/.libs/lqtplay+0x47f3dc)


0x602000009d00 is located 4 bytes to the right of 12-byte region [0x602000009cf0,0x602000009cfc)
allocated by thread T0 here:
   #0 0x4692f9 in malloc (/home/a/Downloads/libquicktime-1.2.4/utils/.libs/lqtplay+0x4692f9)
   #1 0x7f36a12543ba in quicktime_read_dref_table /home/a/Downloads/libquicktime-1.2.4/src/dref.c:66


SUMMARY: AddressSanitizer: heap-buffer-overflow /home/a/Downloads/libquicktime-1.2.4/src/lqt_quicktime.c:998 quicktime_video_width
Shadow bytes around the buggy address:
 0x0c047fff9350: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
 0x0c047fff9360: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
 0x0c047fff9370: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fd
 0x0c047fff9380: fa fa fd fd fa fa fd fa fa fa fd fa fa fa fd fa
 0x0c047fff9390: fa fa fd fa fa fa fd fa fa fa 01 fa fa fa 00 04
=>0x0c047fff93a0:[fa]fa 00 04 fa fa 00 fa fa fa 00 fa fa fa 00 00
 0x0c047fff93b0: fa fa 00 00 fa fa 00 00 fa fa 00 fa fa fa 00 00
 0x0c047fff93c0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 fa
 0x0c047fff93d0: fa fa 00 00 fa fa 00 fa fa fa fd fd fa fa fd fd
 0x0c047fff93e0: fa fa fd fd fa fa 00 04 fa fa 00 00 fa fa fd fa
 0x0c047fff93f0: fa fa 00 fa fa fa 00 00 fa fa 00 00 fa fa 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
 Addressable:           00
 Partially addressable: 01 02 03 04 05 06 07 
 Heap left redzone:     fa
 Heap right redzone:    fb
 Freed heap region:     fd
 Stack left redzone:    f1
 Stack mid redzone:     f2
 Stack right redzone:   f3
 Stack partial redzone: f4
 Stack after return:    f5
 Stack use after scope: f8
 Global redzone:        f9
 Global init order:     f6
 Poisoned by user:      f7
 ASan internal:         fe
==10979==ABORTING


POC:
libquicktime_1.2.4_quicktime_video_width_heap-buffer-overflow.mp4
CVE:
CVE-2017-9128
---------------------
qflb.wu () dbappsecurity com cn

Proofs of Concept:
https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/42148.zip

从上面的信息错误是由ASAN报错指出的,估计是用fuzz结合ASAN跑出来的漏洞

poc可从上面的链接中下载,其中包含了很多mp4文件,只有libquicktime_1.2.4_quicktime_video_width_heap-buffer-overflow.mp4

是我们本次验证cve所需要的

libquicktime-1.2.4下载链接

按常规操作,用configure来产生Makefile,然后再用make,make install

但是在我的Ubuntu1604下编译安装出来的没有lqtplay,这是因为没有安装相应的libc库,具体解决办法是找到 libquicktime-1.2.4\utils目录下的qltplay.c文件,根据里面include的头文件去安装libc库

这里可以使用apt-file来查找到这些库所在的包

sudo apt-get install apt-file
sudo apt-file update
apt-file search xx/XXXX.h

gdb lqtplay

r libquicktime_1.2.4_quicktime_video_width_heap-buffer-overflow.mp4

产生报错

给quicktime_video_width下断点,再次运行

int quicktime_video_width(quicktime_t *file, int track)
  {
  if((track < 0) || (track >= file->total_vtracks))
    return 0;
  return file->vtracks[track].track->mdia.minf.stbl.stsd.table->width;

  }

一步步si

可以看到最后一步取出数据时用了[rax+0x30],而此时rax为0x627bd0,来康康对应的chunk信息

可以看到这个堆块大小只有0x20,而取数据时却用了0x30的偏移导致越界读取

这可能是因为在这个过程中:

file->vtracks[track].track->mdia.minf.stbl.stsd.table->width;

有某些结构体是没有初始化的,具体原因,下面来一步步分析

分析一波函数回溯

return file->vtracks[track].track->mdia.minf.stbl.stsd.table->width;中的各种数据结构类型:

quicktime_s 结构体指针file

quicktime_video_map_t 结构体数组vtracks

quicktime_trak_t 结构体指针track

quicktime_mdia_t 结构体mdia

quicktime_minf_t 结构体minf

quicktime_stbl_t 结构体stbl

quicktime_stsd_t 结构体stsd

quicktime_stsd_table_t 结构体指针table

int 整型width

从qt_init函数开始记录各种结构的的初始情况:

  • qt_init(stdout,argv[1]);

  • quicktime_open(argv[1],1,0);

  • do_open(argv[1],1,0, LQT_FILE_QT_OLD, NULL, NULL);

    • quicktime_t *new_file;

    • new_file = calloc(1, sizeof(*new_file))

      new_file->log_callback = log_cb;

      new_file->log_data = log_data;

    • quicktime_init(new_file);

      1. file->max_riff_size = 0x40000000;
    • new_file->wr = wr;

      new_file->rd = rd;
      new_file->mdat.atom.start = 0;
    • quicktime_file_open(new_file, filename, 1, 0);

    • quicktime_read_info(new_file)

      • file->file_position = 0;
      • quicktime_init_maps(file);
        • file->vtracks[i].track = file->moov.trak[track];
        • quicktime_init_video_map(&file->vtracks[i], file->wr, (lqt_codec_info_t*)0);
          • vtrack->current_position = 0;
            vtrack->cur_chunk = 0;
            vtrack->io_cmodel = BC_RGB888;
          • quicktime_init_vcodec(vtrack, 1, 0);
            • char *compressor = vtrack->track->mdia.minf.stbl.stsd.table[0].format;
        • lqt_get_default_rowspan(file->vtracks[i].stream_cmodel, quicktime_video_width(file, i), &file->vtracks[i].stream_row_span, &file->vtracks[i].stream_row_span_uv);

可以看到,通过上面的一系列分析,并没有发现明显的初始化file->vtracks[track].track->mdia.minf.stbl.stsd.table的地方,因此当调用quicktime_video_width函数时,直接访问该结构体成员变量,就会造成堆访问的异常

进一步分析quicktime_read_info函数,根据gdb源码调试结果,在quicktime_read_info函数中,执行流程如下:

  1. int result = 0, got_header = 0;
    int64_t start_position = quicktime_position(file);
    quicktime_atom_t leaf_atom;
    uint8_t avi_avi[4];
    int got_avi = 0;

    quicktime_set_position(file, 0LL);

  2. do
    {
    file->file_type = LQT_FILE_AVI;
    result = quicktime_atom_read_header(file, &leaf_atom);
    if(!result && quicktime_atom_is(&leaf_atom, "RIFF"))
    {
    .........
    }
    else
    {
    result = 0;////////////1
    break;
    }
    }while(1);

  3. if(!got_avi)
    file->file_type = LQT_FILE_NONE;
    quicktime_set_position(file, 0LL);

  4. if(file->file_type == LQT_FILE_AVI)
    {

    ​ ..........

    ​ }

    else if(!(file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML)))

    {

    ​ do
    ​ {

    ​ .....

    ​ result = quicktime_atom_read_header(file, &leaf_atom);

    ​ .....

    ​ 该do-while循环执行三次,分别处理ftype、 mdat、movv box

    ​ }

    }

  5. if(got_header)
    {
    quicktime_init_maps(file);
    }

可以看到,在这个流程中,不存在初始化赋值file->vtracks[track].track->mdia.minf.stbl.stsd.table的地方

对于这部分赋值的代码在这里

if(!got_avi) 
    file->file_type = LQT_FILE_NONE;
  quicktime_set_position(file, 0LL);

  /* McRoweSoft AVI section */
  if(file->file_type == LQT_FILE_AVI)
    {
    /* Import first RIFF */
    do
      {
      result = quicktime_atom_read_header(file, &leaf_atom);
      if(!result)
        {
        if(quicktime_atom_is(&leaf_atom, "RIFF"))
          {
          quicktime_read_riff(file, &leaf_atom);
          /* Return success */
          got_header = 1;
          }
        }
      }while(!result &&
             !got_header &&
             quicktime_position(file) < file->total_length);

    /* Construct indexes. */
    if(quicktime_import_avi(file))
      return 1;
    }

使用010editor打开poc.mp4文件,可以看到ftype、 mdat、movv格式的box

由于在mp4文件中没有检测到AVI的格式类型的box,因此got_avi=0,于是导致了file->file_type = LQT_FILE_NONE,因此导致无法进入if语句if(file->file_type == LQT_FILE_AVI),最终导致无法执行quicktime_import_avi(file),该函数中包含了对file->vtracks[track].track->mdia.minf.stbl.stsd.table初始化赋值的代码

至此漏洞复现分析完毕,有兴趣复现分析一波的可下载附件


文章来源: http://xz.aliyun.com/t/7585
如有侵权请联系:admin#unsafe.sh