工业编程中的恶意代码及漏洞

作者: 天地和兴     消息来源: 网络安全应急技术国家工程实验室          消息类型: 行业新闻         发布日期:2020-08-28

【编者按】工业软件是制造业的信息化利刃,是联系传统工业生产与现代信息化的纽带。作为智能制造的承载,工业软件已深度融入工业设计和制造流程。从汽车和航空电子设备到制药和食品生产,机器人和其他可编程工业机械,现代制造业对可编程机械的依赖度很高。然而,这些可编程机械大多都是在数十年前设计的,至今仍得到广泛使用,各个制造商还为各自的机器构建了定制的专有编程语言和独特的生态系统。传统的、专用的、零散的技术,导致恶意的自动化逻辑且易受攻击。对此,趋势科技与米兰理工大学研究人员共同发布了《工业编程中易受攻击的恶意代码》研究报告,表明恶意攻击者可利用工业可编程环境中存在的漏洞执行恶意操作,并持续潜伏在智能工厂中。研究人员发现,利用漏洞可能引起的后果包括:窃取机器人数据、通过网络更改机器人的动作、动态恶意软件、非常规远程代码执行漏洞、有针对性的自我传播恶意软件。同时,研究人员提出短期、中期及长期缓解或解决该工业编程环境问题的策略和建议。
机器人和其他可编程工业机械是制造业的支柱。没有它们,现代经济所依赖的大规模和快节奏的生产将根本不可能。从汽车和航空电子设备到制药和食品生产,关键行业都依靠这些机器来执行精确而高效的动作。

但是,尽管现代制造业对它们的依赖程度很高,但这些机器本身都依赖于数十年前设计的传统技术。尽管是在相对遥远的过去发明的,但驱动它们的技术仍在当今得到广泛使用。他们的各个制造商还为各自的机器构建了定制的专有编程语言和独特的生态系统。对此,趋势科技与米兰理工大学共同发布《流氓自动化:工业编程中的易受攻击和恶意代码》研究报告,并表示这些条件意味着这些机器可能具有漏洞,知识渊博的攻击者可能会利用这些漏洞执行恶意操作,并在智能工厂中持续存在。


一、传统技术与智能工厂

可编程工业机器用于全球智能工厂中的复杂自动化例程。它们针对特定的重复性任务进行了编程,例如拾取和放置物品、移动负载、焊接和切割。
驱动这些机器的技术与用于创建网站或移动应用程序的更知名的技术有很大不同。控制过程工程师和系统集成商开发了自动化任务程序,这些程序使用供应商特定的编程语言来定义机器的动作。
对此,基于对八种流行的工业自动化编程语言的技术分析,研究人员发现,导致漏洞或被恶意行为者滥用的根本原因是强大的原语组合,这些原语允许对低级系统资源的不间断访问,从而创建传统扫描程序无法检测到的新的自我传播恶意软件。尽管这些原语本身并不代表安全风险,但它们可能被误用,它们会严重影响机器人的安全性、操作人员的安全性以及连接的系统。这些问题很难解决,因为它们是机器设计所固有的问题,并且不会轻易取代旧的编程环境。
不幸的是,无法解决这些安全漏洞可能会造成高昂的破坏性后果。攻击者可以利用它们在智能工厂中默默进行监视和侦察。或者,攻击者可能会采取更激进的行动,改变产品质量、停止生产线、甚至窃取有价值的知识产权。
但是,攻击者需要拥有大量资源并深入了解目标的工作环境。只有高级的国家级攻击者才能尝试这种性质的黑客攻击。
一  核心问题:传统的、易受攻击的、零散的技术
即使驱动机器人和其他可编程工业机器的自动化技术与运行在Windows服务器上的经典web应用程序完全不同,但也可能受到完全相同的已知漏洞类别(如路径遍历和代码注入)的影响,并可能成为恶意软件的攻击目标。对此,研究人员将说明用于工业自动化的传统技术如何为恶意软件作者提供一套全新的被忽视的武器和漏洞利用场所。
漏洞和恶意软件是任何安全事件背后的两个主要因素。如果没有漏洞,攻击者将无法进入目标工业系统的第一步。如果没有编写和运行恶意软件的可能性,攻击者将无法操作攻击并实现持久化。有了漏洞和新的编写和隐藏恶意软件的方法,高级恶意行为者可以获得访问权限并在工业环境中持续存在。
在用于控制过程自动化的编程和执行环境中,完全缺乏资源隔离(例如权限系统)意味着没有防止攻击发生的权宜之计。
传统编程语言
工业自动化程序、脚本或任务程序依赖于驱动当前和未来智能工厂的传统技术。它们是控制工业机器人和类似可编程机器自动运动的程序。它们是由现场专家使用特定于供应商的编程语言编写的,称之为“工业机器人编程语言”(“IRPLs”)或简单的“传统语言”。
易受攻击或恶意的自动化逻辑
像任何工程工件一样,任务程序可能包含不安全的代码。可能存在漏洞,即错误引入的编程错误,使系统易受攻击。或者,它们可能包含恶意功能,这些功能本质上是为恶意目的编写的代码(例如,接管工厂进行勒索攻击)。
之所以可以在自动化例程中隐藏自定义恶意代码,是因为传统语言提供了丰富而复杂的功能,而不仅仅是简单的自动化指令(例如向上移动机械臂、捡起工件、向下移动机械臂、释放工件)。
这些丰富而复杂的特性使控制过程工程师可以自由地编写任务程序,执行诸如从网络接收数据或对文件进行读写等一系列操作。然而,由于这些平台未实现对这些高级功能的中介访问,因此又为新的漏洞创造了基础,并允许恶意行为者滥用这些漏洞来编写恶意软件。
零碎的专有技术
通用和主流编程语言如C、C++、C、java、PHP和Python都有代码检查器,可以发现不安全的模式。然而传统语言不存在此类工具,因此很难自动化进行安全检查。

IRPLs不是基于常见的运行时或体系结构,比如主流操作系统。每个OEM定义自己的语言,还定义运行时和任务程序将运行的底层环境。有些是基于实时操作系统(RTOS),但总体上没有标准化。每个IRPL的语义也是唯一的,并且与通用编程语言显著不同。有些功能,如IRPLs中的字符串操作或加密操作,要么不存在,要么不如传统语言那样先进。尽管这样做会使编程不易出现漏洞,并为适当的安全措施提供正确的构建块。


二  根本原因:对系统资源的强大、非中介访问
2017年,研究人员研究了典型的工业机器人的攻击面,并展示了软件堆栈中的一系列漏洞如何导致完全的攻击损害,甚至允许攻击者完全控制机器人。在这项研究中,研究人员增加了一部分软件攻击面,并展示了控制过程工程师如何像计算机程序员那样引入漏洞。
图1 软件堆栈的层次(包括自动化任务程序)以及它们各自的漏洞可能会影响到什么
如图1所示,攻击者可以发现并利用操作系统或工业机器固件、应用程序接口(例如用于创建、构建和执行代码的编译器或解释器)或应用程序(如机器上运行的服务)中的漏洞。研究人员对八个工业机器人平台的技术分析揭示了自动化任务程序如何形成软件堆栈的另一层,以及它们的漏洞如何在软件堆栈的较低层被利用。
研究人员发现,这些问题的根本原因是允许对资源进行低级访问(如网络和文件系统访问)的强大功能和缺乏隔离(权限系统)的结合。在此,研究人员将重点介绍如果使用不当或可能被滥用来实施恶意软件的三个主要功能。
访问文件和目录
标有“文件系统”和“目录列表”的语言具有打开、读取和写入文件(访问配置参数、写入日志信息、存储程序状态)或目录的低级功能。虽然这些功能有明显的合法用例,但它们可能被滥用来窃取数据并加载攻击向量(如利用漏洞的有效载荷)。
例如:利用这些功能读取机器人文件系统中存储的敏感文件的易受攻击的程序,可能被攻击者利用来窃取机密,包括宝贵的知识产权。知识产权通常是国家级攻击者的目标,在地下市场以非常高的价格进行交易。
在运行时从文件加载和运行代码
标有“从文件加载模块”或“按名称调用”的语言具有与通用语言的函数指针类似的功能。它们简化了动态调用过程,允许控制过程工程师编写模块化程序。这些是最强大、最危险的功能之一,因为它们允许在运行时更改任务程序的流程。
这些功能的合法用例是允许控制过程工程师编写可重用的程序,并将其组合成复杂的自动化程序。然而,它们可能被滥用以实现类似dropper的恶意软件,或者可能是RCE漏洞的原因。
示例:一个任务程序从从未用加密哈希验证过的文件中加载自动化例程(在这些环境中很少使用加密原语)可以很容易地隐藏恶意功能,而这些功能将无法被检测到,除非有专门针对此类情况的文件扫描程序。因此,攻击者可以保持持久化,甚至随着时间的推移升级其恶意软件。
通信功能
所有语言都具有通信功能,这使得任务程序能够促进机器人与外部系统的接口。接口操作的例子包括从外部程序接收实时位置坐标,与视觉系统交互,以及向外部系统发送反馈以进行日志记录。
通信原语是必不可少的,但是在编程级别完全缺乏强大的身份验证和访问控制,使得控制过程工程师很难创建与外部世界通信的安全程序。
工业机器人控制器具有身份认证和访问控制系统,但它们是粗粒度的。这意味着他们不会考虑攻击者可以利用自动化代码中的漏洞或在现有程序中隐藏恶意代码。因此,工业机器人控制器的安全特性允许或拒绝程序从头到尾运行。与现代应用程序和操作系统一样,目前还没有内置的基于身份验证数据交换的白名单或黑名单连接的方法。
二、攻击后果及影响(案例)

一  窃取机器人数据
路径遍历漏洞可能具有未经确认的网络数据流的任务程序,可使攻击者能够窃取记录目标机器人运动的日志文件,该日志文件可能包含诸如知识产权(例如产品构建方式)之类的敏感信息。然后,攻击者可以访问其他目录中的其他文件(包括包含身份验证机密的文件),并使用这些文件最终访问计算机的控制台。

图2 易受攻击的自动化逻辑:从未经确认的(例如文件、网络、串行)数据到读/写文件访问
二  通过网络更改机器人的动作
“运动服务器”自动化程序可驱动连接的机器人。攻击者可以利用其中一个程序中的漏洞进行攻击,并通过欺骗网络数据包来移动机器人。在为所有主要工业机器人编写的开源项目ROS-Industrial中,如果未正确配置安全系统,则可能发生这种类型的操纵。在正确配置和部署安全系统的情况下,攻击者将很难造成破坏性的移动,尽管攻击者仍然可能会造成意想不到的小动作并中断生产过程。
图3 安全系统配置不当时漏洞的影响:机器人的“手”,即末端执行器,就位(左)和脱落后的末端执行器(右)
趋势科技和米兰理工大学研究人员已与ROS-Industrial进行协调,以缓解他们发现的影响控制工业机器人的ROS-Industrial驱动程序的安全性问题。对此,ROS-Industrial联盟发布了一份指导性报告,以帮助用户提高其安全性。美国网络安全和基础设施安全局(CISA)的工业控制系统网络紧急响应小组(ICS-CERT)也发布了一份报告,确认了其调查结果的严重性,并确认了建议的缓解策略。
三  动态恶意软件
在该场景中,研究人员假设机器人运行一个由系统集成商编写的任务程序,工厂认为该程序是可信的。这意味着系统集成商创建的任何任务程序的部署都不需要对程序代码进行特殊的安全检查。但是,系统集成商可能已受到危害,或者所讨论的任务程序可能来自配置错误或易受攻击的网络连接存储。
低水平攻击者可以直接替换任务程序来改变机器人的自动化程度,并且很有可能被注意到。但高级攻击者知道,如果任务程序是用支持动态代码加载和网络原语(例如ABB、Comau、Denso或Fanuc)的编程语言编写的,他们可能会选择更隐蔽、更持久的方法。
高级攻击者只需稍微修改原始任务程序的源代码,就可以包含一个网络例程,该例程从外部(或隐藏文件)获取恶意代码,然后使用动态加载将其作为正常自动化循环的一部分运行,有效地创建了一个恶意软件删除程序,如图4所示,是研究人员用工业机器人的编程语言编写的。POC表明,可以使用外部程序将代码加载到机器人控制器并执行它。
图4 研究人员用工业机器人编程语言编写的恶意软件删除程序
从这里开始,攻击者可以下载并执行任何第二阶段的恶意软件,这些恶意软件可能会执行进一步的恶意操作,如网络目标枚举、文件收集和数据过滤。
四  非常规远程代码执行漏洞
研究人员故意用恶意功能编写了如图4所示的代码,这是通过滥用动态代码加载实现的。另一面是一个良性的程序,该程序合法地使用此类特性来动态加载代码,或者如图5所示,根据外部输入调用某些功能。控制过程工程师可能已经创建了该程序,但可能忘记了对加载的代码进行完整性检查。
图5 易受攻击的逻辑示例:从未确认(例如文件、网络、串行)数据到命令调用
因此,如果机器人运行如图6所示的代码,则很容易受到(部分)远程代码执行(RCE)的攻击。幸运的是,研究人员只发现了这此类漏洞的一个实例,且仅在一个演示程序中发现了它。研究人员希望该程序永远不会被用于教授如何编写代码,或者更糟的是,生成产品代码。如图5所示,这意味着攻击者可以在机器人上调用任意功能,并对物理世界产生实际影响,具体影响可能因系统的配置和部署方式而异。在错误的时间调用合法的自动化例程至少会导致一些停机时间。
图6 可能导致远程代码执行的易受攻击的代码加载程序
五  有针对性的自我传播恶意软件
研究人员发现,传统编程是如此强大,以至于能够创建具有蠕虫行为的目标恶意软件,并能够在自动化平台的逻辑级别进行自我传播。一旦感染新机器人后,蠕虫将开始扫描网络以寻找其他潜在目标,并利用网络漏洞进行传播。一个更全面的恶意软件还包括一个文件收集例程,以泄露在每个受感染目标上发现的所有相关数据。研究人员发现,这种自我传播的恶意软件在演示程序任务程序中传播所需的大多数先决条件,部分易受远程代码执行的影响,即攻击者可以调用代码中已声明的任意功能。
图7 研究人员编写的蠕虫恶意软件POC的网络扫描程序
三、缓解策略及安全编程准则

一  缓解方法
研究人员的发现与当前产品难以改变的设计选择有关。因此,研究人员预计在不同的阶段实施不同的缓解方法。如图8所示,研究人员提出这些方法供OT工程师、系统集成商和原始设备制造商考虑或部署。
图8 研究人员在不同阶段提出的缓解方法,以及谁可以考虑或部署这些方法
究中提出的问题只能通过长期解决方案来完全解决,但是控制过程工程师、系统集成商和原始设备制造商(OEM)可以采用短期和中期缓解策略来增强安全性工业编程环境。
短期措施
• 使用网络分段来隔离需要处理来自其他网络的数据的计算机。
• 采用网络和端点保护,以最小化漏洞利用或恶意代码感染的风险。
• 实施适当的源代码管理过程,包括自动或定期进行手动源代码审查。
中期措施
• 开发安全性库(例如密码原语),使开发人员可以轻松实现输入验证和身份验证。
• 提供运动服务器的参考实现,以允许机器以高级方式接收经过消毒的运动数据。
• 实施积极的修补脆弱的任务计划为周期性的源代码审查中发现的缺陷补救措施。
长期措施
• 通过设计确保主要通过将安全功能集成到编程语言中来确保下一代可编程工业机器的安全。
• 在运行时,使用机器控制器上的权限系统 实现细粒度的权限分离。
• 实施代码签名,以确保未篡改工业机器上运行的代码。
二  安全编程清单
与处理不可信输入和输出的任何软件应用程序一样,自动化任务程序必须用适当的安全机制进行设计、实现、配置和部署。安全指南在图9中进行了概述。
图9 处理不可信数据的工业自动化任务程序的安全指南摘要
在编写任务程序时,控制过程工程师和系统集成商应记住以下基本检查清单:
• 将工业机器视为计算机,将任务程序视为强大的代码。
• 验证所有通信。
• 实施访问控制策略。
• 执行输入验证(如适用)。
• 始终执行输出消毒。
• 在不暴露细节的情况下实施正确的错误处理。
• 有适当的配置和部署程序。
• 实现工业自动化代码的变更管理过程。
三  身份验证和访问控制
与其他系统(通过网络、串行端口或总线)通信的任务程序应验证所有消息,以确保它们来自授权方,如图10所示。然而,这一原则也有例外。一方面,来自连接到机器人工作站的传感器的简单数据很少会成为攻击者控制的输入。但是,在某些情况下,攻击者能够利用传感器跳过隔离,并将数据注入机器人的自动化程序中。
图10 使用访问控制(如未经授权的功能调用)并进行RCE攻击预防
即使有网络级别的安全措施(例如防火墙)可以确保机器人只能从指定的端点接收数据,任务程序也应该将输入视为不可信的。这是为了保护授权的端点不受危害,在这种情况下,攻击者可以与任务程序通信。
在语言中没有可靠的加密支持来实现身份验证可能会导致保护不足。但是,简单的身份验证会提高攻击者对基线的限制(无身份验证)。与通用编程语言一样,需要IRPLs中适当的密码支持和库来弥补这一差距。
根据任务程序的逻辑,控制过程工程师和系统集成商可能需要准备一个访问控制策略,例如,是否应该平等对待所有经过身份验证的请求。例如,如果他们正在实现一个需要文件访问的任务程序(例如,读取或写入日志数据),则必须将范围仅限于特定目录。
四  输入验证
通过网络、串行端口或总线与其他系统通信的任务程序应该验证入站数据的内容,以确保它们符合预期的格式和内容,如图11所示。

图11 通过输入验证,意外数据被丢弃,从而防止任何试图影响机器人移动的尝试
实现正确的输入清理只需要基本的字符串和数据操作原语和比较运算符(例如,相等性测试)。正则表达式支持可能会有很大帮助,但必须小心使用,因为攻击者可能会手工编写特定的输入,从而导致正则表达式引擎崩溃。
五  错误处理
虽然在开发和测试过程中很有用,但未处理的错误可能会向正在探测目标或试图利用漏洞的攻击者泄露重要的内部细节。因此,应该进行适当的错误处理和输出清理,以隐藏这些细节,并使攻击者更难从外部对程序逻辑进行逆向工程,如图12所示。
 图12 通过正确的错误处理和输出清理,在侦察和准备阶段对攻击者有用的敏感信息可以被隐藏

每种编程语言都有适当的错误处理和调试功能,可以对这些功能进行调整,以便在生产环境中有选择地显示或隐藏敏感的细节。这些功能还可以将它们重定向到单独的文件或通过同一网络无法访问的专用日志记录工具。
例如,Comau机器人的编程语言PLD2支持“错误事件”的概念,其形式为“when error_type do[…]”,并允许用户进一步处理特定的错误。同样,Denso的PacScript语言定义了一系列错误代码,并允许用户等待特定的错误条件。
由于我们的示例并非详尽无遗,研究人员建议用户查阅所使用的编程语言手册中的错误处理功能,并熟悉其在测试平台程序上的输出(因为手册可能不会显示示例输出的全部细节)。
六  输出和日志清理
写在控制台、串行端口、日志记录工具或文件上的输出可能包含敏感的详细信息,例如IP地址、密码、会话令牌和API密钥,如图12所示。考虑到行业中IT/OT集成度的不断提高,有缺陷的输出净化可能会导致严重的数据泄漏。
重要的是要确保执行打印操作的所有代码(例如,到屏幕和文件)被删除或在不必要时忽略掉。程序员通常使用(或滥用)打印功能而不是适当的调试或日志记录工具。这些工具可以很容易地从一个地方关闭,而不是必须单独删除每一行代码。
除了泄漏数据外,未经确认的输出还可能为注入漏洞提供场所。如果一个程序的输出被另一个没有正确验证输入的程序处理,第一个程序的未经确认的输出可能会触发第二个程序中的漏洞。
七  配置、依赖关系和部署
确保任务程序在可能的最佳条件下运行是安全配置和部署的核心。例如,在过时的控制器软件或操作系统上运行的完全安全的任务程序会打开任务程序本身无法阻止的其他攻击可能性。
所有配置参数(包括IP地址、运动变量和文件位置)都应该与任务程序的实际代码清楚地分开,如果可能,最好保存在安全的内存或磁盘位置。
例如,Kuka编程语言将程序文件(.src)与数据定义(.dat)和后台任务(.sub)分开。这种默认的分离促进了良好的配置处理和部署实践。我们建议其他语言的用户采用类似的做法。
最后,由于可以在所有的IRPLs中编写可重用的库代码,所以检查导入了哪些依赖项非常重要。安全事件表明,由于包含不安全的库代码而传播的漏洞,以及通过依赖关系树或通过感染项目开发文件传播的恶意软件的影响。
八  控制过程代码的变更管理
研究人员与来自不同行业的20位领域专家进行了交谈,包括自动化工程师、系统集成商和装配线操作员。在咨询这些专家后,研究人员发现控制过程代码的生命周期相对简单。代码被创建(主要由系统集成商或临时程序员创建)、测试和部署。现如今大多数自动化代码是静态的,只有在重新设计装配线时才进行升级。但市场正朝着更灵活的制造流程发展,拥有模块化和可重新配置的机器人工作站,这些工作站可以自我组织、升级和更改代码,以满足生产期限。
在这种情况下,对代码具有完全的可见性和控制能力至关重要。10年前,跟踪代码依赖关系进行安全分析听起来是不必要的。如今,软件生命周期中不仅考虑了持续集成工具(如GitHub的安全特性),而且依赖性跟踪也通过软件物料清单(SBOM)得到改进。
工业自动化世界应该朝着类似的方向发展,开始实施源代码生命周期管理。
几十年前的工程师和设计师无法预料到当今存在和活跃的各种网络威胁。但是,既然这些问题已经暴露出来,并且通过设计实现安全性的重要性变得越来越明显,制造业的参与者就有机会设计未来智能工厂的安全性。
服务热线
025-8660 3700

微信公众号