AMNESIA33 协议栈漏洞之CVE-2020-17437分析

  • A+
所属分类:逆向工程

[email protected]海特实验室

漏洞概述

上周,国外安全实验室 Forescout Research Labs 公布了一个关于存在于多个 TCP/IP 协议栈漏洞,其漏洞影响了数百万IoT设备,并且有一些是属于严重的内存破坏漏洞,可以利用漏洞通过精心构造的恶意数据控制程序执行流,造成潜在的远程命令执行的效果。

其中受影响的协议包括:

  1. picoTCP (picoTCP-NG)

  2. uIP

  3. Net/Nut

  4. FNET

漏洞分析

这里选择了对多个受影响的协议栈中的 picoTCP 协议的某个漏洞做一个分析,漏洞发生的位置和成因是其协议栈在处理 icmpv6 数据包时,没有对数据包的长度做校验,导致返回响应报文时发生了整数溢出漏洞,进而造成了内存破坏漏洞。

icmpv6 数据包格式

icmpv6 协议可以看作是 icmp 数据包在 ipv6 上的形式,使用 wireshark/tcpdump 抓包的方式在 wireshark 中分析其数据包结构。首先在本地使用 ping6 命令对 eth0 网卡发送 icmpv6 数据包,并使用 tcpdump 进行抓包:

AMNESIA33 协议栈漏洞之CVE-2020-17437分析


将抓取到的数据包加载到 wireshark 中,在 wireshark 的 preference -> Layout 中,将 panel 设置成 Packet Diagram 即可看到数据包的各个字段的结构。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析


根据上图的结构可以看出,icmpv6 数据包是位于 ipv6 层面之上的网络层协议,协议的几个字段可以分为 Type、Code、Chceksum、Target、Option。

  • 在某些情况下可以将 Target、Option 看作是 icmpv6 的 data 部分,如下图。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析


其中 Type 字段的值和 icmp 协议类似,用来指定 icmpv6 数据包的报文类型,如应答、响应等。下图(参考链接1)为其报文类型的各个值:

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

Code 字段为报文类型中使用的代码。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

源码分析

根据参考链接二给的参考信息可知,漏洞点位于源码 pico_icmp6.c 文件中的 pico_icmp6_send_echoreply 函数,根据函数名可知此函数的功能主要是处理 icmpv6 协议数据包的请求,并对请求作出响应。

在代码的第一个 memcpy 函数中,将 echo->payload 复制到 reply->payload 指针表示的内存段中,复制的大小为 echo->transport_len - PICO_ICMP6HDR_ECHO_REQUEST_SIZE 大小。这里 echo 结构体是用户传入的 icmpv6 协议数据包结构体,echo->transport_len 和 echo->payload 分别为 icmpv6 数据包报文的总长度和 payload 数据体字段(指针类型),都为可控值,而 PICO_ICMP6HDR_ECHO_REQUEST_SIZE 的值在代码中固定为 8。

  1. static int pico_icmp6_send_echoreply(struct pico_frame *echo)

  2. {

  3. struct pico_frame *reply = NULL;

  4. struct pico_icmp6_hdr *ehdr = NULL, *rhdr = NULL;

  5. struct pico_ip6 src;

  6. struct pico_ip6 dst;


  7. reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, echo->dev, (uint16_t)(echo->transport_len));

  8. if (!reply) {

  9. pico_err = PICO_ERR_ENOMEM;

  10. return -1;

  11. }


  12. echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;

  13. reply->payload = reply->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;

  14. reply->payload_len = echo->transport_len;


  15. ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr;

  16. rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr;

  17. rhdr->type = PICO_ICMP6_ECHO_REPLY; // 129 -> 0

  18. rhdr->code = 0;

  19. rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id;

  20. rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq;



  21. memcpy(reply->payload, echo->payload, (uint32_t)(echo->transport_len - PICO_ICMP6HDR_ECHO_REQUEST_SIZE));




  22. rhdr->crc = 0;

  23. rhdr->crc = short_be(pico_icmp6_checksum(reply));

  24. /* Get destination and source swapped */

  25. memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6);

  26. memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6);

  27. pico_ipv6_frame_push(reply, &src, &dst, PICO_PROTO_ICMP6, 0);

  28. return 0;

  29. }

如果这里用户构造一个恶意的 icmpv6 数据包,控制 echo->transport_len 字段的值小于 8,那么两个变量相减之后将发生整数溢出,在代码中体现为 memcpy 函数的第三个参数为一个很大的数值,此时如果控制 echo->payload 为一个长度足够长的字符串时,在将复制到 reply->payload 内存段就会发生一个内存溢出。

reply 为指向 pico_frame 结构体的指针,reply->payload 指向了 icmpv6 的 data 字段。

  • 关于 picoTCP 协议栈环境搭建见下文。

漏洞环境搭建

将 picoTCP 协议栈的项目代码从 github 上 clone 到本地,直接 make 编译即可。

  1. git clone https://github.com/tass-belgium/picotcp.git

  2. apt-get install git check vde2 libvdeplug2-dev libpcap0.8-dev openvpn wireshark

  3. cd picotcp

  4. TAP=1 make -j8

  5. TEST=1 make test

编译完成之后,在当前的 build/ 目录或者根目录下的 build 目录下会生成编译好的链接库和可执行文件。./build/test 目录下为协议作者给的 picoapp6.elf、picoapp.elf 两个实例程序。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析


根据作者在 github 上 README.md 的描述可以很容易的搭建起 ipv4 的测试环境,但是并没有给出 ipv6 中 icmpv6 的 tap/tun 虚拟网卡的搭建环境,这里还是踩了不少坑,这里给出使用 tun 虚拟网卡搭建 icmpv6 环境的步骤。

首先在 test 目录下运行下面的命令,在 mytun 网卡上虚拟出 aaaa::1 这个 ip:

  1. sudo ./picoapp6.elf --tun mytun,aaaa::1,ffff::,,,,

另起一个窗口进行 tun 虚拟网卡的网络配置:

  1. sudo ip addr add 192.168.1.1 dev mytun

  2. sudo ifconfig mytun add aaaa::3/64

之后就可以使用 ping6 -I mytun aaaa::1 命令成功 ping 通 aaaa::1 这个 ipv6 地址。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

漏洞复现

接着使用动态调试看查看需要构造的 payload。首先使用 gdb 调试引擎起一个调试脚本:

  1. sudo gdb -ex 'file picoapp6.elf'

  2. -ex 'set args --tun mytap,aaaa::1,ffff::,,,,'

  3. -ex 'b pico_icmp6_process_in'

  4. -ex 'b pico_icmp6_send_echoreply'

  5. -ex 'r'

  • 这里还需要手动分配 mytun 网卡的 ipv4 和 ipv6 地址。

这里使用 python 的 scapy 模块进行 icmpv6 数据包发送,该模块详细的用法见参考链接。首先构造正常的 icmpv6 报文如下:

  1. from scapy.all import *


  2. addr = 'aaaa::1'

  3. payload = 'A'


  4. base = IPv6(dst=addr)


  5. '''构造icmpv6报文作为ipv6的扩展部分'''

  6. extension=ICMPv6EchoRequest(data=payload)

  7. packet = base/extension


  8. sendp(packet,iface='mytun',verbose=True)

gdb 中断点断下之后,单步到 memcpy 函数的调用处,查看 echo 的结构体:

AMNESIA33 协议栈漏洞之CVE-2020-17437分析


发现这里的 transport_len 占 9 个字节的大小,payload 为传入的 icmp6 的 data 部分,占一个字节,因此可知这里的 transport_len 减去 payload 的 8 个字节长度刚好为 icmpv6 的 Type、Code、Checksum 的字段大小。

根据源码分析和调试分析得知,这里的 echo->transport_len 的值在 pico_icmp6_send_echoreply 函数传入时就已经赋值,重新在源码中搜索该函数的引用,找到 pico_icmp6_process_in 函数,其中在 PICO_ICMP6_ECHO_REQUEST 分支处的 f 变量的值即为传入函数的 echo 参数。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

在 pico_icmp6_process_in 函数处下断点,重新进行调试,查看 f 的成员变量的值,发现 len 和 net_len 分别为 49 和 40:

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

  • f->net_hdr - f->buffer 刚好为 0.

此时在 tcpdump 中抓下此 icmpv6 数据包,在 wireshark 中查看报文结构,可以很清晰的发现这里整个 ipv6 的报文长度为 49 ,icmpv6 的报文长度为 9,因此可以得知的 echo->transport_len 的值为整个 icmpv6 的报文长度:

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

此时就可以构造一个畸形的 icmpv6 报文(见 POC 小节)发送到 mytun 虚拟网卡,即可触发整数溢出漏洞。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

这里的崩溃原因是因此程序开启了 AddressSanitizer 检测到了非法内存越界写,抛出了强制结束程序的信号。

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

漏洞证明

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

总结

仔细观察此整数溢出漏洞并不是很好利用,因为这里 icmpv6 报文的 data 字段部分无法直接控制,只能通过构造一个小于 8 字节的畸形 icmpv6 报文造成一个内存越界写的内存破坏漏洞,最多在开启 AddressSanitizer 保护时造成程序的 crash,导致拒绝服务。

参考文章

  1. https://www.cnblogs.com/ys-ys/p/10263479.html

  2. https://www.forescout.com/company/resources/amnesia33-how-tcp-ip-stacks-breed-critical-vulnerabilities-in-iot-ot-and-it-devices/

  3. https://i.blackhat.com/eu-20/Wednesday/eu-20-dosSantos-How-Embedded-TCPIP-Stacks-Breed-Critical-Vulnerabilities.pdf

  4. AMNESIA33:开源TCP/IP协议栈系列漏洞分析与验证

  5. scapy 模块使用手册

HatLab知识星球

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

关于我们

AMNESIA33 协议栈漏洞之CVE-2020-17437分析

人才招聘

一、物联网安全研究员(硬件安全方向)

工作地点:

1.杭州;

岗位职责:
1.嵌入式方向的安全漏洞挖掘;
2.嵌入式系统硬件软件设计与研发。
任职要求:
1.熟练使用C语言,可规范使用指针,结构体,联合体;
2.熟练使用Linux操作系统,理解Makefile原理并可编写Makefile文件;
3.了解数字电路原理,具有较扎实的计算机系统结构知识,理解操作系统原理;
4.了解WEB或PWN方向的漏洞挖掘过程,会使用相关工具如Zap、IDA等,会自行编写漏洞利用工具。
加分项:
1.具有网络安全公司实习经验;
2.具有网络安全赛事经验;
3.有设计电路板原理图和四层PCB布局经验;
4.熟练焊接0402,0201,QFN,BGA等元器件封装;
5.有AVR,ARM,MIPS,Xtensa等内核的MCU/SoC开发经验;
6.向知名平台提交过物联网方向的漏洞报告。


二、物联网安全研究员(固件安全方向)

工作地点:

1.杭州;

岗位职责:
1. 物联网通用协议、组件、操作系统漏洞挖掘与漏洞复现;
2. 物联网设备漏洞挖掘与漏洞复现;
3. 参与创新物联网安全研究项目;
任职要求:
1.具有二进制漏洞挖掘经验,熟悉ARM、MIPS等其他架构的漏洞利用技巧;
2.熟练掌握gdb、IDA等工具的使用;
3.具有一定的硬件基础和动手能力,掌握常见的嵌入式设备固件提取及解包的方法;
4.至少掌握一门编程语言,如C/C++/Perl/Python/PHP/Go/Java等。
加分项:
1.具有知名物联网设备/网络设备漏洞挖掘成果证明;
2.参加CTF比赛并获奖;
3.参与GeekPWN、HackPWN等智能设备破解大赛并取得成绩。


三、物联网安全研究员(无线电安全方向)

工作地点:

1.杭州;

岗位职责:
1. 无线通信协议的通用漏洞挖掘;
2. 无线通信应用系统的漏洞挖掘,如智能设备等。
任职要求:
1. 掌握无线通信基本原理及数字信号处理理论,熟悉各种调制解调算法,信道编码算法等;
2. 熟悉C/C++、MatLab、Python等编程语言;
3. 熟悉至少一种常见无线通信协议及其安全问题,如Wi-Fi、Bluetooth、Zigbee、4/5G等;
4. 熟练掌握SDR外设和GNURadio等工具的使用。
加分项:
1. 具有信息安全公司实习经验;
2. 有嵌入式固件逆向分析经验;
3. 参加CTF比赛并获奖;
4. 有智能设备的破解经验;
5. 通信工程、信息安全专业。



感兴趣的小伙伴请联系姜女士,或将简历投送至下方邮箱。(请注明来源“研究院公众号”)

联系人:姜女士
邮箱:[email protected]
手机;15167179002,微信同号

本文始发于微信公众号(安恒信息安全研究院):AMNESIA33 协议栈漏洞之CVE-2020-17437分析

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: