这个漏洞k0shl有分析过,我也是看了他的分析才决定自己分析一遍的,最终得到的结论也有一些差异。此外,由于tcpdump本身就是有源码的,所以我是从源码和gdb动态调试两个方向同时进行分析,更加方便理解。
kali 2020.3 x86
该文件可以通过运行上面的python文件获得。
24字节pcap_file_header
16字节pcap_pkthdr
数据
更详细的介绍会在3.1 构建自己的poc中。
使用gdb
执行tcpdump
,然后执行run -r crash
,因为访问未授权地址,程序停止执行:
执行bt
命令查看函数调用栈:
从该命令的输出中,可以看到漏洞出现时的函数调用情况,以及每个函数所在的文件及其位置。总结如下表:
从上面的信息,我们知道漏洞的发生是由于打印时引用了非法地址,但究竟是如何做到这一点的,还需要进一步分析。
跟随文件名及行数信息,找到savefile.c
中的pcap_offline_read
函数源码,在该文件的400
行,有一个函数调用status = p->next_packet_op(p, &h, &data);
,从该代码无法确定究竟调用了哪个函数,所以回到gdb
,在pcap_offline_read
函数处下断点b pcap_offline_read
,然后执行run -r crash
,n
步进到该处函数调用,s
步入:
发现该函数为sf-pcap.c
文件399
行的pcap_next_packet
,打开该文件定位到函数位置,回到gdb
步进查看函数执行流程。
根据上面对于执行流程的监控,可以发现pcap_next_packet
函数根据数据包头部的caplen
信息读入了8字节的数据0x0600ff40 0x007f72a0
。也就是说,pcap_offline_read
函数中的status = p->next_packet_op(p, &h, &data);
语句,参数data
最终指向的就是这8字节数据,参数地址为0x5ed560
。
回到pcap_offline_read
函数,第409行,执行了(*callback)(user, &h, data);
,即print_packet
函数。
找到tcpdump.c
文件中的print_packet
函数:
其中h
就是之前读取的头部信息,sp
就是8字节的数据。
需要注意的地方来了!
这里调用的就是print-802_15_4.c
中的 ieee802_15_4_if_print
函数,在该函数的最后,调用了ndo_default_print
:
之后的两个函数只是在添加参数的基础上调用新的函数,并没有什么内容:
直接查看hex_and_ascii_print_with_offset
函数:
该函数使用参数length
计算了一个长度用来控制循环,然后逐步访问参数cp
(也就是从数据包读入的数据)指向的内存空间,也就是这里发生了越界访问,导致了拒绝服务。
现在我们需要回顾一下length
参数究竟是什么了!
可能你会认为这个length
就是之前读入的caplen
,也就是0x8
,但事实并非如此。
上一小节中有一个加粗字体不知道你有没有注意到,就是在 ieee802_15_4_if_print
函数中,caplen
的值发生了变化。
让我们在gdb
中跟进一下这个函数,同时和源码对应,看一下这个函数做了一些什么:
根据上面的调试结果,该函数会对读取出来的数据中的前两个字节进行一些运算,计算出ieee802.15.4包的头部长度,这里计算出来的是0x12
,而ieee802.15.4包的总长度也只有0x8
,再减去前3个字节,最后得到的传入ndo_default_print
的参数caplen
就是一个负数了。
注:这里的计算涉及到了ZigBee包格式的问题,感兴趣的朋友可以参考这个网址
接下来我们直接在gdb
中步进到hex_and_ascii_print_with_offset
函数内,看一下长度计算那里的结果是什么。这里从汇编代码比较好:
注意到除法操作(右移一位)之后,原本的负数变成了极大的正数。
注意这里循环停止的判断方式,函数使用baseAddress+nshorts*2
的方式计算截至地址,但是由于整数溢出,导出结果小于基地址。这就导致判断循环结束的条件无法到达,函数会一直从基地址0x5ed575
开始遍历,最终访问到未授权的内存地址。
poc的python代码本身并没有什么需要分析的地方,就是把crash数据包的内容写入到了crash
文>件中,所以主要是看一下crash
文件的内容。再次贴一下它的内容:
0000h: D4 C3 B2 A1 02 00 04 00 | 00 00 00 F5 FF 00 00 00
0010h: 49 00 00 00 E6 00 00 00 | 00 80 00 00 00 00 00 00
0020h: 08 00 00 00 00 3C 9C 37 | 40 FF 00 06 A0 72 7F 00
0030h: 00 01 7F 00 00 EC 00 01 | E0 1A 00 17 67 2B 2B 2B
0040h: 2B 2B 2B 2B 85 C9 03 00 | 00 00 10 A0 26 80 18 27
0050h: 78 66 65 24 00 01 00 00 | 40 0C 04 02 08 0A 27 2C
0060h: 20 27 00 00 00 00 00 00 | 00 00 01 03 03 04
在1.4 crash文件介绍中,我已经简单介绍了该数据包的内容和结构。根据上面对于漏洞的分析,产生漏洞的主要原因就是内容中加粗的两个部分,这两部分的内容导入最终代码计算出来的ieee802.15.4包内容的长度是负数,从而产生整数溢出。
所以该漏洞的出现和00 3C 9C 37
没有关系,也和0030h-006Dh
的内容没有关系。
那么下面这个数据包应该也会引发漏洞:
我使用上面的数据构建了一个crash1
文件,在命令行执行tcpdump -r crash1
,确实引发的漏洞:
所以如果想要自己构建一个针对该漏洞的poc,只要了解pcap文件的格式就可以了。
上面的数据中,凡是没有明确要求的全部设成了0。注意caplen
字段,以及数据部分的前两个字节其实也不是固定的,只要最后能够计算出负数的长度就可以,可以根据源码自己选取字段内容。
最后组合成的数据包为:
使用tcpdump打开该数据包,也成功引发了漏洞。
把python代码中的buffer
改成自己构建的crash
文件内容,就是一个完整的poc了。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课