CVE-2020-10611:在 TRIANGLE MICROWORKS SCADA 数据网关上实现代码执行
DNP3简介
如果您不是ICS / SCADA系统的普通用户,则可能不熟悉分布式网络协议3(DNP3)通信协议集。DNP3主要用于SCADA主站,远程终端单元(RTU)和智能电气设备(IED)之间的通信。它的采用主要是在公用事业领域,包括电力和水。它提供了丰富的功能集,包括数据分段,错误检查和通用数据类型,这使该协议比旧的ICS协议更强大。相对于网络的OSI模型,DNP3定义了第2层(数据链路)协议。该协议还定义了类似于OSI层4的传输层和类似于OSI层7的应用层。
GTWLib.dll
库中有两个漏洞可用于利用该服务。
错误1:公开未初始化的内存
当报告给定类型的DNP3数据集描述符元素的数据时,首先将给定元素的值添加到输出缓冲区。然后,将输出缓冲区光标增加一个用户指定的最大大小值。不会检查max-size值,以确保对于给定类型来说max-size值不会太大。设置类型UINT
(类型代码:2)的元素的最大尺寸字段时,输出值尺寸为恒定尺寸4,而输出缓冲区光标仍按用户定义的最大尺寸递增。随着完整的输出缓冲区在响应中发送,这将泄漏比向请求实体添加到输出缓冲区更多的数据。
结合没有将输出缓冲区初始化为常量值(malloc
使用)的事实,这导致公开了与分配的缓冲区相对应的内存的先前内容。
错误2:更新数据集原型时的类型混淆
数据集描述符允许用户定义自定义数据类型。为了允许类型重用,DNP3标准允许数据集描述符合并数据集原型。数据集原型定义了一个由原始数据类型列表组成的子类型。数据集描述符可以包含对数据集原型的引用,以合并嵌入式数据结构。
修改数据集元素的内容时,其内容将根据存储在基础数据集中的类型进行更新。但是,不会检查以确定元素的类型在上一次修改和当前修改之间是否已更改。值更新时,其当前值被视为存储在基础数据集原型中的值。
当字符串(类型代码为5的OSTR类型)被更新时,将检查是否已经分配了缓冲区来保存字符串的内容。如果存在指向缓冲区的指针,realloc
则用于修改分配以适应新要求的大小。
在以下一系列交互中:
1-创建数据集原型以指定双 精度值(FLT
类型代码4和大小8)
2-使用原型创建数据集描述符
3-将数据集描述符的float元素的当前值设置为0x9090909090909090
4 -将原型成员的类型更改为OSTR
5-修改现值
用户控制的值被视为指针,然后将其重新分配给用户控制的大小。这导致了触发任意的原语realloc
:
realloc(controlled_ptr, controlled_size)
where 1 <= controlled_size <= 0x100.
开发
指针泄漏
DNP3输出缓冲区的分配大小可以配置,默认大小为0x800。如果攻击者可以控制0x800大小的缓冲区中先前包含的数据,则可以使用Bug 1(如上所述)泄漏该缓冲区中的大多数字节。
当汇总来自数据集描述符的“当前值”时,将分配一个表示当前值的0x28大小的项目数组。根据基础数据集元素的类型,指针可以驻留在项目中。
通过创建具有51个元素的数据集描述符,0x33*0x28==0x7f8当为所请求的当前值提供答案时,将分配的缓冲区。如果输出缓冲区的分配回收了以前包含此数据项数组的缓冲区,则指向用户控制的数据的指针将泄漏。
内存损坏
使用针对错误2所述的技术并了解指针泄漏带来的受控指针,攻击者可以制作指针并触发这些缓冲区的重分配以创建悬空指针。这允许从现在释放的缓冲区中读取值。缓冲区被另一个对象回收后,攻击者可以使用相同的技术再次分配该缓冲区。攻击者可以使用悬空指针重复泄漏缓冲区内存的内容。
使用悬挂指针从已知对象中泄漏数据还可以通过函数指针和vptrs揭示DLL的基地址。
首先,攻击者释放了他们在先前步骤中泄漏的缓冲区之一的内容。然后,它们触发相同大小的分配。接下来,他们用假对象填充分配。至此,他们已经用有效载荷回收了该对象。最后,触发类型混淆条件以劫持控制流。
在这种情况下使用的受害对象类型是保存数据集原型本身的数据收集类。
利用缓解措施
至于漏洞利用缓解措施,指针泄漏会绕过ASLR,并且在此二进制文件中未启用CFG。其他缓解措施在此UAF方案中不相关。
结论
Triangle MicroWorks将这些错误修补为 CVE-2020-10611 和 CVE-2020-10613。您还可以在ICS-CERT咨询ICSA-20-105-03上引用这些错误 。该修复程序的一部分包括在网关中禁用数据集。再次感谢Tobias Scharnowski,Niklas Breitfeld和Ali Abbasi提供了本文所包含的许多信息。他们的DNP3攻击演示当然是Pwn2Own Miami的亮点,我们希望在未来的比赛中能看到他们。
