OPC基金会于2006年开发,用于可靠和重要的工业网络中不同系统之间的数据安全传输。该标准是其前身OPC协议的改进版本,在现代工业环境中几乎“无处不在”,因其能够实现原始数据以及预处理信息的处理,并且实现了安全地从制造绩效到生产计划或者EOPC UAR层级的传输过程,通过该技术的应用能够消除空间时间的影响,任何地点和时间都可以授权应用。
基于不同供应商产品的监控系统通常使用是互不兼容的,通常是专有的网络通信协议。OPC网关或服务器用做不同工业控制系统与遥测、监控和遥控系统之间的接口,统一工业企业的控制流程;这种功能独立于制造厂商,属于一种操作系统和编程语言。
OPC UA是目前已经使用的工业标准的补充,更有效地对扩展性、工业互联网适应性以及独立性做了完善工作;研究OPC UA安全性,可以帮助工业自动化系统和工业软件的供应商实现对现代网络攻击的更高级别的保护,此外对其安全性研究的技术细节和发现有助于软件提供商控制其产品质量,也有助于安全研究人员对工业通讯协议的研究工作。
1 OPC UA的二进制安全性
OPC UA在设计之初是为支持两种数据类型的数据传输而设计的,即传统的二进制格式(用于以前版本的标准)和SOAP/XML。现在,SOAP/XML格式的数据传输已被安全界认为是过时的,在现代产品和服务中几乎没有再被使用。由于它在工业自动化系统中被广泛应用的前景是模糊的,因此将研究重点放在二进制格式上是明智的。
分析使用OPC UA的系统时发现,大多数执行文件使用了名为“uastack.dll”的链接库。通过搭建基于突变的fuzzing测试环境研究其安全性,算法结构为:读取输入数据数列、读取输入数据序列、对执行伪随机转换、通过网络将结果序列发送到程序作为输入、接收服务器的响应、重复。在开发了一组基本的突变(bitflip、byteflip、算术变异、插入幻数、重置数据序列、使用长数据序列)之后,研究人员成功地识别了uastack.dll中的第一个漏洞。它是一个堆损坏的漏洞,成功地利用它可以使攻击者执行远程代码执行(RCE),在这种情况下,他们就可以使用NT权限/系统特权。研究人员识别的漏洞是由处理数据的函数造成的,这些数据是从一个套接字中读取的,这些函数错误地计算了数据的大小,然后将数据复制到堆上创建的缓冲区中。
另外,在使用UA .NET堆栈的.NET应用程序的过程中,在分析wireshark中应用程序的流量时,注意到一些数据包有一个is_xml位字段,其值为0。在分析应用程序的过程中,研究人员发现它使用了XmlDocument函数,该函数很容易被.NET版本4.5和之前的XXE攻击所攻击。这意味着,如果我们将is_xml位字段的值从0更改为1,并将特制的XML数据包添加到请求主体(XXE攻击),将能够读取远程计算机上的任何具有NT权限/系统特权的文件,并且在某些情况下还可以执行远程代码执行(RCE)。
2 OPC UA协议分析
为了找出OPC基金会实施OPC UA协议的漏洞,研究包括:OPC UA栈(ANSI C、.NET、JAVA)、使用OPC UA栈的OPC Foundation应用程序(例如上述的OPC UA .NET Discovery Server)、其他使用OPC UA栈应用程序的软件开发人员。
2.1 将UA ANSI C栈进行Fuzzing测试化处理
使用OPC基金会开发者提供的标准链接库,通常难以发现其漏洞,通过使用OPC基金会提供的源码(包含于UA ANSI C栈的示例服务器),对其代码进行手工Fuzzing测试,有助于研究人员了解是否将新功能加入到UA ANSI C栈的特定实现中。
为加速Fuzzing测试,研究人员重载了网络函数socket/sendto/recvfrom/accept/bind/select,从本地文件读取输入的数据,而不是连接到网络。另外研究人员还使用AddressSanitizer(内存问题的排查工具和方法)编译了程序。为了将刚开始发现的一组示例集合在一起,我们使用了与第一个Fuzzing测试相同的技术,即使用抓包工具tcpdump从任意客户端应用程序中捕获流量。另外,通过改进Fuzzing测试技术,专门为OPC UA和特殊突变创建了字典。
从OPC UA中的二进制数据传输格式的规范可以看出,对于AFL来说,从OPC UA(\xff\xff\xff)中的一个空字符串的二进制转变为一个包含4个随机字节的字符串(如\x04\x00\x00\x00AAAA),是非常困难的。因此,开发了一个转变机制,它与OPC UA内部结构一起工作,根据它们的类型随时转变。包含所有改进的Fuzzing测试之后,可以在较短时间内(分钟级)发现程序的崩溃情况。崩溃时创建的内存转储的分析,能够识别UA ANSI C栈中的一个漏洞,如果该漏洞被利用,可能会导致DoS攻击。
2.2 利用Fuzzing分析使用OPC UA的应用程序
任何使用OPC UA协议栈的应用程序的两个主要函数都是OpcUa_Endpoint_Create和OpcUa_Endpoint_Open,OpcUa_Endpoint_Create函数为应用程序提供有关服务器和客户端之间可用的数据通信通道以及可用服务列表的信息。OpcUa_Endpoint_Open则定义了可用的网络和它将提供的加密模式。可用服务列表使用服务表来定义,该表列出了数据结构并提供了每个服务的详细信息。每一个结构都包含所支持的请求类型、响应类型以及在请求预处理和后处理期间将调用的两个回调函数。另外,预处理函数在大多数情况下都表示为“stubs”。将转换器代码包含在请求预处理函数中。该函数使用突变数据进行输入、输出与请求类型匹配的正确结构。这样可以跳过应用程序启动阶段,直接启动一个事件循环来创建一个单独的线程读取伪套接字等。使得Fuzzing测试从50个exec/s的数量级加速到2000个exec/s。
使用以这种方式改进的fuzzing测试方法,安全人员目前已经在OPC基金会应用程序中发现了很多漏洞。
2.3 分析使用OPC UA栈的第三方应用程序
在对OPC基金会产品完成了分析后,还应分析使用OPC UA栈的商业产品。利用渗透测试中使用的ICS系统,分析了一些他们客户的设备安全状况,选择不同厂商的几种产品,其中包括全球领先的解决方案。在得到批准后,研究人员就开始分析这些产品中OPC UA协议的实现过程。
在搜索二进制漏洞时,Fuzzing测试是最有效的技术之一。在以前的案例中,当分析Linux系统上的产品时,研究人员使用的就是源代码二进制检测技术和AFL Fuzzing测试器。但是,本文分析时使用的OPC UA栈的商业产品由于是在Windows上运行,对此,要用一种称为AFLFuzzing的测试器。简而言之,WinAFL是移植到Windows的AFLFuzzing测试器。但是,由于操作系统的不同,两个Fuzzing测试器在一些关键功能方面,还是有所不同的。由于WinAFL不是使用来自Linux内核的系统调用,所以它是使用WinAPI函数而不是静态源代码工具,它使用DynamoRIO动态检测二进制文件。总体而言,这些差异意味着WinAFL的性能显著低于AFL。
在WinAFL fuzzer的源代码中开发者留下Fuzzing测试网络应用程序的评论。根据这些评论,对网络Fuzzing测试进行一些修改。具体地,在模糊测试的代码中包含了与本地网络应用程序通信的功能。因此,Fuzzing测试器不会执行程序,而是通过网络将有效载荷发送到已在DynamoRIO下运行的应用程序。
但是,只能达到5 exec/s数量级的Fuzzing测试率,即使使用像AFL这样的智能Fuzzing测试器也会花费很长时间才能发现漏洞。因此,继续改进前文所述的Fuzzing测试方法进行脆弱性测试。
(1)改进突变机制,根据传输到OPC UA栈的数据类型来修改数据生成算法。
(2)为每种支持的服务创建了一组示例(pythonopcua库,其中包含了与几乎所有可能的OPC UA服务交互的功能)。
(3)当使用带有动态二进制工具的Fuzzing测试器来测试像这样的多线程应用程序时,在应用程序代码中搜索新程序是一项非常复杂的任务,因为很难确定哪些输入数据会导致应用程序的不正当行为。由于Fuzzing测试器是通过网络与应用程序通信的,并且研究人员可以在服务器的响应和发送给它的数据之间建立清晰的连接(因为通信是在一个会话的范围内进行的),所以研究人员不需要解决这个问题,而是利用一种算法,该算法可以在从服务器接收之前尚未观察到新响应时,简单地识别出新的执行路径。
经过改进,Fuzzing测试速度每秒执行次数从1次或2次增加到70次,这对于网络Fuzzing测试来说就非常好。基于此发现了另外两个无法使用智能Fuzzing测试识别的新漏洞。
3 OPC UA的脆弱性测试结论
截至2021年,上述漏洞已被识别和关闭,另外还发现了使用这些产品的商业应用程序中的一些漏洞。目前,已经向易受攻击软件产品的开发人员报告了所有发现的漏洞。
在大多数情况下,使用OPC UA栈的第三方软件中的漏洞是由于开发人员未正确使用OPC基金会uastack.dll库中实现的API功能而导致的,例如,传输的数据结构中的字段值被错误地解释。
另外,在某些情况下,产品漏洞是由商业软件开发商对uastack.dll库所做的修改引起的。例如,从套接字读取数据的函数的不安全实现。值得注意的是,OPC基金会最初计划实施的功能并未包含此漏洞。虽然并不知道开发者为什么要修改数据读取逻辑,但显然开发人员并没有意识到OPC基金会在其中包含的附加检查是多么的重要,因为一切安全功能是建立在附加检查之上的。
在分析商业软件的过程中发现开发人员已经从OPC UA栈实施示例中借用了代码,并将该代码逐字复制到其应用程序中。显然,他们认为OPC基金会确保这些代码片段的安全性与确保库中使用的代码安全性的方式相同。不幸的是,这个假设是错误的。
以上这些漏洞会导致黑客发起DoS攻击和远程执行代码。重要的是,在工业系统中,DoS攻击漏洞比任何其它漏洞造成的威胁都大。例如,工业控制系统中的拒绝服务可能导致企业遭受重大经济损失,并且在某些情况下甚至会导致施工过程中断和关闭。
4 结语
OPC基金会的开放源代码表明其发布的协议是开放的,并致力于让使用它的商业产品更加安全。同时,分析表明,目前OPC UA协议栈的实施不仅不普及,而且还存在一系列重大的基础问题。
首先,使用OPC UA栈的商业开发人员对OPCUA栈的设计意图不是很了解。该协议当前实现中存在着有大量的指针计算,不安全的数据结构,变化常量,函数之间复制的参数验证代码以及在代码中分散的其他过时特性。由于软件开发人员为了使他们的产品更安全,倾向于从代码中清除这些功能。但由于被删改的代码没有很好的记录机制,这使得在使用或修改过程中更容易引入其他错误。
其次,利用OPC UA的商业开发人员显然低估了OPC基金会联盟提供的所有代码的信任软件供应商。尽管API使用示例未包含在OPC基金会认证的产品列表中,但在API使用示例代码中留下漏洞是完全错误的。
OPC UA开发人员在进行产品安全测试时,并未使用类似于本文所描述的模糊测试技术。由于开放的源代码不包括单元测试或任何其他自动测试的代码,这就使得产品的开发人员在修改代码产品时,更加难以利用模糊测试技术来测试OPC UA栈的安全。
尽管OPC UA的开发人员试图确保他们的产品安全,但他们仍然忽视了安全编码的一些前提和技术。当前的OPC UA栈实现不仅不能保护开发人员免受一些小漏洞的影响,而且还容易引发更多的漏洞。考虑到现实情况,研究人员认为目前商业产品还是慎用OPC UA。
摘自《自动化博览》2022年5月刊