CVE ID: CVE-2020-12763
漏洞描述
TRENDnet(趋势网络) ProView Wireless camera TV-IP512WN 1.0R 1.0.4 版本中的 RTSP 数据包在处理过程存在缓冲区溢出漏洞。攻击者可利用该漏洞执行代码或导致拒绝服务。漏洞发生在 /sbin 目录下的二进制文件 rtspd 中,该文件主要负责处理设备接收到的 RTSP 连接。当文件在解析 RTSP header 的 “Authorization: Basic” 字段时,由于字段内容的长度不确定,程序又没有对拷贝到栈上的内容长度进行检查限制,因此可能会导致缓冲区溢出,更严重的是该漏洞无需登录授权便可以触发。
在探讨技术细节前请注意以下几点:
1、漏洞是在该型号产品最新版本的固件中发现的。
2、漏洞已经上报厂商 TRENDnet。
3、TRENDnet 认为该产品已停产,所以拒绝漏洞验证。
漏洞产品
厂商: TRENDnet
影响产品:ProView Wireless N Network Camera TV-IP512WN (Version v1.0R)
固件:FW_TV-IP512P_512WN(1.0.4).zip
SHA-1:B27998BBB4C8503E9314730F504E389B56AD6F6C
产品链接:https://www.trendnet.com/support/support-detail.asp?prod=175_TV-IP512WN
产品图片
固件详情
漏洞分析
需要澄清的一点是,受新冠疫情影响,我很难买到这次分析用的无线摄像头设备,也就无法实际触发该漏洞,所以我是通过静态分析发现的这个漏洞。为方便读者理解,我会把反编译后的代码截图放到文章里,并对大部分函数和变量进行了重命名。
这次漏洞是典型的 CWE-120 栈溢出错误,错误可被利用于远程执行代码(RCE)或拒绝服务(DOS)攻击。溢出发生在 sbin 目录下的二进制文件 rtspd,该文件主要负责处理设备接收到的 RTSP 连接请求。
函数 parse_auth_header(address 0x11a18)解析 Authorization: Basic header 的时候会发生栈溢出,函数被调用时传入两个缓冲区参数,第一个存放 RTSP header,第二个用来存放解析后获得的 header 值,下图为反编译后的函数代码。
图 A:校验头解析函数 parse_auth_header 反汇编代码
我们来试着理解下这个函数:
- 1、如上图代码所示,10-17 行是一个循环,从缓冲区第一个字符开始搜索 header 字符串 “Authorization: Basic”,如果找到就断开循环,然后将指针 src_buf_ptr 前移 0x15 个字节(长度刚好指向 header 值的内容)。
2、调用 strstr 函数查找换行符 “\r\n”,返回一个 char 指针 newline_ptr。
3、将前面两个指针相减,获得的差值便是 Authorization: Basic header 值的长度。
4、函数 memcpy 把 src_buf_ptr 指针指向的 header 值内容拷贝到缓冲区 dest_buf 里面,程序执行到这一步时可能会发生溢出错误,因为程序没有检查 dest_buf 的长度是否足够容纳 header 值的内容,如果内容过长的话就会导致 dest_buf 缓冲区溢出,接下来我会证明这一点。
先来看下传给函数的参数是什么。
将地址为 0x11ae8 的函数重命名为 check_authentication,函数中调用了parse_auth_header 函数,请看下图的反汇编代码。
图 B:check_authentication 函数反汇编代码
可以看到,parse_auth_header 是在第 35 行被调用的,第一个参数来自调用函数check_authentication 的最后一个指针参数 param_4(此处原文作者描述和所给图片有出入,所以稍有修改),第二个参数是一个 char 型指针,指向的缓冲区大小为 64,希望你能明白这里的问题所在:
传入 parse_auth_header 的第二个缓冲区参数大小是固定的(64 个字节),而当函数拷贝数据时又没有校验数据长度是否在缓冲区大小范围内。
发现这个问题并不难,但我们怎么知道函数处理的数据是来自 socket 呢?问得好,先找到调用 check_authentication 的函数,重命名为 is_client_authenticated,下图为反汇编后的函数代码:
图 C:函数 is_client_authenticated 的反汇编代码
check_authentication 函数在第 23 行被调用,根据其返回值,程序会判断下一行的 if 代码块是否执行。if 代码块(24-35 行)除了在控制台输出文件名和函数名,还会将一行拼接有 RTSP/1.0 401 Unauthorized 内容的字符串作为 send 函数的参数,而 send 函数用于向 socket 写入数据,这就证明了之前的一系列函数是在做权限校验工作,如果 Authorization Basic header 内容过长的话,就会触发溢出漏洞。
继续探究,找到所有 is_client_authencticate 函数的调用,这能帮助我们更好地了解程序何时进行权限校验,请看下面的函数调用情况:
图 D
图 E
图 F
图 G
图 H
图 I
如上图代码所示,当触发摄像头的暂停,设置,播放,拆分等功能时,程序就会调用函数 is_client_authencticate,以检查收到的功能请求授权是否合法,返回值为 0 表示校验通过,然后实现功能,否则程序直接返回。
这篇 维基百科 介绍了 RTSP 的协议格式,进一步印证了上面我们看到的图 D – 图 I 中的各个功能。
另外需要注意的一点是,由于这个 bug 是在解析 Authorization header 时触发的,也就意味着无需授权就能够执行 RCE,这在很大程度上加剧了漏洞的严重性。
结论
我们看到了数据包解析代码里一个小小的 bug 就能导致缓冲区溢出,也见识了攻击者是怎样绕过权限校验触发漏洞的,虽然还没法写出一个行之有效的 PoC 来证明 RCE ,但是我会在文章第二部分试着搭建 qemu 环境,模拟运行二进制文件,通过创建远程 socket 连接的方式实现 RCE,触发漏洞,然后大功告成!
From 新概念研究中心