part1的部分请参考:
![Pwn2Own:从 WAN 转到 LAN 攻击 Synology BC500 IP 摄像头 Pwn2Own:从 WAN 转到 LAN 攻击 Synology BC500 IP 摄像头](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/07/3-1721359149.jpg)
执行摘要
-
Claroty Team82 参与了去年秋季在多伦多举办的 Pwn2Own 2023 物联网黑客大赛,并成功利用了 TP-Link ER605 路由器和 Synology BC500 IP 摄像头的漏洞。
-
通过这项研究,我们展示了攻击者如何能够通过广域网入侵设备,并转移到本地网络以攻破连接的物联网设备。
-
在本系列的第一部分中,我们解释了对 TP-Link ER605 路由器的研究和攻击。在这里,我们将介绍如何从路由器转移到本地网络并攻破 Synology BC500 IP 摄像头。
-
TP-Link 已在固件版本 ER605 (UN) V22.2.4 Build 20240119 中修复了我们报告的漏洞。
-
CVE-2024-5242
-
CVE-2024-5243
-
CVE-2024-5244
-
Synology 在固件版本 1.0.7-0298 中修复了我们报告的漏洞,并发布了安全公告。
-
ZDI-24-833
在本两部分系列的第一部分中,我们解释了 Team82 的 WAN-to-LAN 轴心攻击的前半部分,通过一系列漏洞利用来绕过 NAT 保护并在 TP-Link ER605 路由器上获得远程代码执行权限。
在利用我们的 WAN 漏洞完全攻破路由器后,我们需要在 LAN 内部转移以攻破我们选择的物联网设备:Synology BC500 IP 摄像头。
Synology BC500 IP 摄像头是一款 5 百万像素的广角摄像头,具有 IP67 等级,适用于室内和室外应用。它们提供了夜视和运动检测等有价值的功能,特别适合希望远程监控和捕捉可疑活动的企业。
Synology BC500 IP 摄像头
技术细节
Synology BC500 IP 摄像头是一款基于 32 位 ARMv7 架构的设备,运行定制的 Linux 操作系统。固件未加密,可以从 Synology 的网站下载。固件由厂商打包和签名,分为多个部分,分别包含设备系统的不同部分,包括 Linux 内核和 UBI rootfs
文件系统。
摄像头具有基于 civetweb 网络服务器的网页界面,提供 C/C++ 的 CGI 可执行文件。网络服务器的配置位于 /etc/webd.conf
,绑定到端口 80 (HTTP) 和 443 (HTTPS)。
在我们的研究中,我们发现了一个 JSON 解析程序中的漏洞,该程序由 CGI 二进制文件 /www/camera-cgi/synocm_param.cgi
使用,通过以下 HTTP URL 访问:/syno-api/activate
。在检查这个二进制文件时,我们注意到在接收到 PUT
请求后,它会尝试使用开源库 libjansson 从请求体解析 JSON 内容。
为了更好地探究这个代码流程,我们创建了一个可以调试固件中的二进制文件的设置。
栈缓冲区溢出漏洞 (ZDI-24-833)
在处理 PUT
请求时,二进制文件调用了 json_loads()
函数。此方法将从用户接收到的 JSON 字符串反序列化为应用程序可以使用的 JSON 对象。
程序调试会话中 gdb 的 JSON 字符串示例
在查看 json_loads
函数的实现时,我们注意到一个危险的 sscanf
函数调用。这个 C 函数被认为是不安全的,因为它可能导致内存损坏问题。
如下面的图片所示,不安全的 sscanf
调用会将未经认证的远程客户端提供的键元素拆分成两个存储在栈上的字符串。
parse_object
实现包含用户输入的不安全 sscanf
调用
由于二进制文件没有限制 json_loads
函数解析的用户输入大小,该例程中存在栈结构溢出漏洞,使攻击者能够溢出栈结构。需要注意的是,不安全的方法 sscanf
的调用仅存在于 Synology 摄像头的 libjansson
库中,而不在原始的开源库中。
位于栈上的两个输出字符串(32 字节和 12 字节缓冲区)很容易被具有网络访问摄像头权限的恶意攻击者溢出。
由恶意负载溢出的栈上的缓冲变量
由于这个不安全的调用,通过提供一个键元素包含两个长字符序列并用空格分隔的 JSON 对象,可以很容易地触发栈缓冲区溢出:
{“32+_bytes_string 12+_bytes_string”: “”}
这个问题更加严重,因为此 API 路径不需要有效的认证凭据,这意味着即使是未认证的攻击者也可以远程利用此漏洞。
漏洞二进制的缓解措施
使用 checksec,我们分析了主要程序 synocm_param.cgi
和 JSON 库 /lib/libjansson.so.4.7.0
中的缓解措施。我们发现虽然主应用程序进程启用了几乎所有现代的二进制缓解措施,包括 RELRO, NX
等,但该库并未编译为堆栈金丝雀保护。
checksec
输出的 CGI 和库 – 库没有堆栈金丝雀保护
摄像头的操作系统强制执行 ASLR 作为安全措施。这意味着我们不能在我们的漏洞利用负载中依赖静态地址。经过多次分析二进制文件的执行情况,并分析来自 /proc/[PID]/maps
的进程映射,我们得出结论,应用程序的地址随机性为 8 位,堆的地址位置随机性为 12 位。
不同 synocam_param.cgi
文本段基址的采样
![](https://claroty.com/img/asset/YXNzZXRzL2ltYWdlOC0xNzE5ODQzODgxLnBu
Zw==?fm=webp&fit=crop&s=7ced837ff6d03111e8c1b6d14ee89674)
不同 synocam_param.cgi
堆段基址的采样
ASLR 保护和我们运行的上下文意味着我们实际上只有一个选项。我们需要在尝试利用设备时强行破解程序使用的地址。经过检查 /etc/webd.conf
中的网络服务器配置,我们发现它允许同时处理 10 个并发请求,这意味着我们在任何给定时间最多可以有 10 个并行请求。
具有 10 个线程的 /etc/webd.conf
配置文件
利用路径
为了在摄像头上执行任意代码,我们决定最佳的方法是调用系统标准库函数。
第一步,我们找到了一个方法可以重定向代码执行。通过调试,我们发现了一个位于栈上、超出我们的缓冲区变量之后的函数指针,我们可以完全覆盖并强制程序使用它。该函数指针指向一个名为 get_func
的函数,该函数遍历用户的 JSON 字符串。这个指针是一个名为 stream_t
的对象的成员,该对象包含在另一个名为 lex_t
的对象中。
为了控制代码流程,我们从溢出函数 parse_object
内的栈帧开始。然后,我们会溢出栈,直到覆盖函数指针 get_func
并将其指向 system
函数的地址。
从上图可以看到,在 sscanf
调用后,程序会调用 lex_scan
函数。在这个代码流程中,程序将使用我们溢出的栈函数指针并调用它。由于我们覆盖了这个指针,现在我们可以控制代码流程并跳转到我们选择的例程。
利用流程
-
进入 parse_object
解析 JSON 字符串 -
使用 sscanf
溢出栈上的stream_t
结构 -
stream_get
函数调用 -
stream.get()
调用我们控制的指针 -
lex_scan
函数调用
漏洞利用负载
我们的负载由不同部分组成,每个部分都有不同的目的。两个主要部分是 system
函数地址(相对于程序基址:<Program-Base> + 0x3f190
),以及指向程序堆区域包含我们的操作系统命令的指针,这个命令将由 system
函数调用。
系统滑块填充
为了确保我们的堆指针实际指向我们的操作系统命令,我们向堆中喷洒大量数据块,这些数据块由填充物和最后的实际操作系统命令组成。这增加了我们利用的成功率,因为这意味着堆中充满了我们的喷洒负载,其中填充物充当滑块,引导到我们的操作系统命令。需要注意的是,系统函数中的操作系统命令限制取决于操作系统和内核配置,在我们的情况下,最大命令长度为 0x20000
,这意味着我们的整体负载包括“滑块”填充最多可以达到 0x20000
字节长。
精心选择堆指针
为了推断我们应该将地址指向命令缓冲区的位置,我们采样了几次执行尝试,并计算了与大多数执行堆重叠的最佳地址。
将空字节注入我们的负载
另一个重要方面是能够将空字节注入我们的负载。我们的漏洞利用需要空字节,因为我们使用的指针指向应用程序内存地址范围,即 0x00400000
范围。因此,我们需要找到一种可靠的方法将空字节添加到我们的栈溢出中。
我们通过 sscanf
在负载末尾插入了一个空字节,另一个通过插入空格字符实现,这是由于提供给 sscanf
函数的字符串格式(%s %s
)。通过覆盖第二个分割键,然后覆盖第一个部分,我们能够可靠地将两个空字节注入我们的负载。
通过上述步骤,我们成功利用了该漏洞,实现了对 Synology BC500 IP 摄像头的远程代码执行。
例如,假设我们提供如下的JSON字符串键:
{“YYYYYYYYYYYYYYYYYYYYYYYY XXXXXXXXX”: “”}
在 sscanf
使用 “%s %s
” 之后,这将被分成两部分:
YYYYYYYYYYYYYYYYYYYYYYYY00
XXXXXXXXX00
最终,被覆盖的栈将包含两个我们需要的空字节:
XXXXXXXXX00YYYYYYYYYYYYYYYYYYYYYYYY00
编码我们的漏洞利用
此外,我们还有另一个问题:如何可靠地将非ASCII字节编码到我们的漏洞利用负载中?问题在于JSON键只能是有效的UTF-8编码字符串。为了解决这个问题,我们创建了一个包含所有UTF-8编码可能字节的巨大表格,然后仔细选择导致这些字节生成的初始输入。
例如,要编码地址 0xA68D9FF0
,我们需要编码以下字节 xf0x9fx8dxa6
,因此我们会使用代表冰淇淋表情符号的unicode符号 🍦。
我们创建了一个包含所有UTF-8可能编码数据的巨大表格。
最终,我们可以根据漏洞利用需求使用特定指针来编码我们的负载。
局域网漏洞利用总结
我们的负载由一个包含两个项目的JSON对象组成,第一个是一个 key:array[]
,包含6个由填充和操作系统命令组成的字符串,第二个触发上述函数指针溢出。
在对目标执行我们的漏洞利用后,我们确实获得了一个反向Shell并完全控制了IP摄像头。
Synology已在固件版本1.0.7-0298中修复了该漏洞,并发布了一个安全公告。
从广域网到局域网的漏洞利用总结
总体来说,找到一种从广域网利用SOHO路由器并通过利用连接的物联网设备进入局域网的实际方法是一个有趣的挑战。我们选择了TP-Link ER605作为路由器,Synology BC500 IP摄像头作为物联网设备,并使用了四个链式漏洞依次利用这些设备。对我们来说,这只是一个部分胜利,因为在比赛中我们的回合之前,完全相同的Synology摄像头漏洞利用已经被使用。因此,我们以$40,750和8.25 Master of Pwn积分完成了比赛。
原文始发于微信公众号(3072):Pwn2Own:从 WAN 转到 LAN 攻击 Synology BC500 IP 摄像头