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所需要的
按常规操作,用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);
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)
vtrack->cur_chunk = 0;
vtrack->io_cmodel = BC_RGB888;
可以看到,通过上面的一系列分析,并没有发现明显的初始化file->vtracks[track].track->mdia.minf.stbl.stsd.table
的地方,因此当调用quicktime_video_width函数时,直接访问该结构体成员变量,就会造成堆访问的异常
进一步分析quicktime_read_info函数,根据gdb源码调试结果,在quicktime_read_info函数中,执行流程如下:
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);
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);
if(!got_avi)
file->file_type = LQT_FILE_NONE;
quicktime_set_position(file, 0LL);
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
}
}
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
初始化赋值的代码
至此漏洞复现分析完毕,有兴趣复现分析一波的可下载附件