这个同样是一周前clone的最新库fuzz结果
问题出现在svread.c中的parseSVG执行strncpy复制前长度判断不严。
crash结果
首先来看一下批处理crash发现的gdb结果
Program received signal SIGSEGV, Segmentation fault.
0x0000000000496010 in parseSVG (h=0x998c5a43686190bf) at ../../../../../source/svread/svread.c:864
864 while (!(h->flags & SEEN_END)) {
#0 0x0000000000496010 in parseSVG (h=0x998c5a43686190bf) at ../../../../../source/svread/svread.c:864
#1 0x0d895f8642801ab0 in ?? ()
#2 0x330ad0e8e8e8e8a7 in ?? ()
#3 0x000000000a24ddef in ?? ()
#4 0x0000000000581468 in ?? ()
#5 0x0000000000000008 in ?? ()
#6 0x000000000a20e078 in ?? ()
#7 0x0000000000000000 in ?? ()
Dump of assembler code from 0x496010 to 0x496020:
=> 0x0000000000496010 <parseSVG+432>: mov 0xcd28(%rax),%ecx
0x0000000000496016 <parseSVG+438>: and $0x1,%ecx
0x0000000000496019 <parseSVG+441>: mov %ecx,%esi
0x000000000049601b <parseSVG+443>: mov %ecx,-0x148(%rbp)
End of assembler dump.
rax 0x998c5a43686190bf -7382426443606552385
rbx 0x0 0
rcx 0xffffffdd 4294967261
rdx 0x0 0
rsi 0x0 0
rdi 0x0 0
rbp 0x7fffffffdca0 0x7fffffffdca0
rsp 0x7fffffffda30 0x7fffffffda30
r8 0x0 0
r9 0xfffffffffffffff 1152921504606846975
r10 0x0 0
r11 0x7ffff703c5e0 140737337607648
r12 0x404c40 4213824
r13 0x7fffffffe180 140737488347520
r14 0x0 0
r15 0x0 0
rip 0x496010 0x496010 <parseSVG+432>
eflags 0x10246 [ PF ZF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
A debugging session is active.
Inferior 1 [process 120570] will be killed.
Quit anyway? (y or n) [answered Y; input not from terminal]
[+] crash file ===> ./crashes/SIGSEGV.PC.7f8e371974d9.STACK.badbad0d4cce199d.CODE.128.ADDR.(nil).INSTR.[NOT_MMAPED].2019-07-24.18:05:33.75589.fuzz
===========================================================
原理分析
调试,运行,崩溃
查看一下相关变量
pwndbg> p/x h->flags
Cannot access memory at address 0x998c5a4368625de7
pwndbg> p/x h
$1 = 0x998c5a43686190bf
查看一下内存布局
所以h作为一个指针,这个地址,肯定是错的
下断点,重新调试
看一下没出问题前h的值
指向这个堆
目前没有任何问题,但从刚刚崩溃中可以看到h的值会被修改为一个无效地址
所以监控一下h的值,如果发生变化,就断下
pwndbg> watch h!=0xa228030
继续执行
在执行strncpy时断下来了,看一下调用栈,并定位一下出错代码
好了,出错位置找到了
在这个位置下一个断点,重新执行
看看执行这句后会有什么效果
h已经变为了一个无效指针。
来看看为什么,重点在strncpy函数
strncpy(tempVal, tk->val + 1, tk->length - 2);
其中tempVal定义
char tempVal[kMaxName];
kMaxName定义
#define kMaxName 64
tempVal是一个64字节长度的字符数组
再来看看tk->length - 2数据
pwndbg> p/x tk->length-2
$6 = 0xab
pwndbg> p tk->length-2
$7 = 171
所以tempVal数组执行完strncpy是会溢出的
那溢出一定会覆盖h的值吗?答案是不一定,看你使用什么编译器了。
经过多次测试发现,如果使用gcc编译,那么就不会被覆盖,如果使用clang编译就会被覆盖至于为什么,其实直接看反汇编代码就懂了
gcc编译
clang编译
可以发现gcc把h这种重要的数据结构放在了距离rbp更远的地方,减少了被覆盖的风险。
利用这个漏洞,攻击者通过构建特定结构的svg的字体文件,很有可能会造成命令执行
总结
很不幸,分析完之后,发现利用afdko的最新代码并不能复现!
经过多次测试,发现afdko通过commit 973a8c929b4fb204dd8fcc84cd12ff02c1ea8aab
把这个洞给堵上了,堵上的原理就是,利用的poc.svg在执行到strncpy前就被断了。
但这个漏洞理论上还是存在的,因为strncpy执行前,现有代码还是没有对长度进行判断,但要是想绕过的话,需要进一步fuzz出能够触发这个洞的poc数据
连续两个洞,都是因为这一个commit,导致无法利用,真是心塞啊











