基于CODESYS软件PLC的“震网式”攻击

admin 2022年1月12日07:00:04评论169 views字数 4561阅读15分12秒阅读模式
作者 | 博智安全非攻研究院赵富乾 [email protected]

 前言

震网(Stuxnet)攻击事件虽然已经过去了10年有余,除了使用了多个0day的使用外,对西门子Step7和Siemens系列PLC的攻击方式也一直被工业安全领域所关注。10年来随着技术的不断发展,软件PLC以其开放性和便捷性在工业领域被越来越多的使用,这其中的代表厂商之一就是CODESYS。早在1984年Ken Thompson就设想了一种植入编译器的病毒,本文使用震网的思想,成功对CODESYS编译系统进行了拦截,在IDE无感的前提下,在PLC中植入了反弹shell。

 Stuxnet回顾

我们知道Stuxnet使用了多个0day、远程代码执行、本地提权、感染LNK、感染step7工程等等,相关细节本文在此不做赘述。进行了这些骚操作并找到自己的目标后,震网病毒就开始了它真正的攻击行为,劫持Step7并通过Step7控制与之相连的西门子S7 PLC。
Step7是西门子的集成开发环境(IDE),开发人员需要通过Step7将控制逻辑编写成STL (structured text lanague), 一种类似FORTRAIN的语言,并将STL编译成机器码,下载到PLC中执行。
基于CODESYS软件PLC的“震网式”攻击
震网攻击Step7的方式是将一个恶意的s7otbxdx.dll替换掉了s7otbxsx.dll, 这个dll的主要作用是与PLC进行通信,包括:1.接受编译后的字节码并传承给PLC,2.将PLC中的程序显示到Step7用于调试。
而恶意的dll会在写入PLC的时候加入自己的字节码,而当Step7检查代码的时候返回正常代码,使得IDE无法发现代码已被改动。.
基于CODESYS软件PLC的“震网式”攻击
这种攻击方式具有极强的隐蔽性,专业性和针对性,在十多年后的今天看来仍然令人叹服。时至今日,工控系统的安全已经引起了广泛的重视,工控领域的技术也有了长足的进步,此类攻击是否还有可能发生呢?我们针对另外一家市场规模巨大的厂商CODESYS产品进行了研究和尝试。

 CODESYS介绍和分析

CodeSys是全球最著名的PLC软件研发厂家德国3S(SMART,SOFTWARE,SOLUTIONS)公司发布的一款与制造商无关编程软件及工控设备内核。因为CodeSys作为“工控界的安卓”被广泛使用在工控设备中,据官方统计使用CodeSys解决方案的知名企业超过500家,CodeSys市场占有率为35%。此次我们分析的主要是目标是CodeSys编程软件和CodeSys软件PLC。
首先我们从工控开发者使用的角度看CodeSys的产品体系。CodeSys工程是一个开发任务各种资源的集合,和现代编程语言的工程十分相似。CodeSys支持多种编程语言,其中主要的一种语言是Structed txt 也叫ST或者STL。ST 语法上类似Fortran, Level上和C语言比较接近,可以操作指针,可以借助库函数手动管理内存。在工程中开发者可以引入各种库,这种库包括各种支持功能,例如文件操作,字符串操作,串口操作,CanBus操作等,这些库多数是CodeSys官方提供的。工程中开发者可以加入可视化组件,用于展示和监控控制系统的状态。工程中开发者可以对工程进行编译,可以对工程进行模拟执行,可以将工程下载到PLC中执行。
基于CODESYS软件PLC的“震网式”攻击

编译系统

从模块上分,CodeSys产品大致可以分为IDE集成开发系统,编译系统,运行时系统,其中IDE主要用于交互,执行时系统主要用于支撑软件PLC的运行,编译系统主要功能是将源代码编译成目标可执行应用。这里着重分析的是编译系统。
CodeSys的IDE和编译器系统是使用.net开发的,我们可以通过反编译了解其内部构造和原理。使用dnspy软件对CodeSys进行动态和静态分析,尽管.net的静态可以还原到近似于源代码的形式,但CodeSys对大量的内部代码进行了名称混淆,给静态分析带来一定的干扰,由于所有的攻击方法都是基于对目标的认识,因此实际分析的过程是一个比较漫长和艰苦的过程。

基于CODESYS软件PLC的“震网式”攻击

 编译器前后端

CodeSys有独立设计实现的完整的编译器体系,使用插件构架,可以动态支持多编译器版本,编译器采用分离的前后端,用以适配多语言和多平台。编译器前端主要的工作是解析并检查源文件,并将源文件生成语法树AST以提供给后端,后端则是根据目标设备选择代码生成器生成目标机器码,生成的只执行代码具有代码区、数据区,重定位区等。

基于CODESYS软件PLC的“震网式”攻击

 编译过程

CodeSys编译器进行工程编译可分为五个阶段:

1. 类型化 (Typification) 分析函数和类型定义,做基本的检查
2. 后类型化 (AfterTypification) 分析函数实现,基于类型化信息,进行进一步检查
3. 重定位 (Location) 针对使用地址,动态内存,多态等需要重定位的代码提取重定位信息
4. 类型检查 (TypeCheck)
5. 代码生成 (CodeGeneration) 从AST生成目标机器码
其中前4步主要都是编译器前端的工作,用于产生与平台无关的AST,而后端主要是第5步,根据平台生成相应机器指令。震网对于西门子PLC的攻击虽然也是基于对开发环境Step7的劫持进行,攻击注入的也是机器码,但劫持的环节依然是通讯模块。实际上震网对Step7的编译过程是没有进行干扰的。对CodeSys的编译体系有一定的了解后,我们要问:有没有可能针对编译体系对PLC展开攻击?

 CodeSys编译系统攻击

.net代码劫持

在分析的基础上,我们需要实现对CodeSys 编译器.net代码的修改。直接patch IL的代码修改方式不适合大量的修改,而且在处理第三方引用和字符串上有很多不便,因此转向hook方法。目前使用的是Playhooky库 (https://github.com/wledfor2/PlayHooky) ,该hook的主要原理是动态修改要hook的函数,将其改为:
mov r11,replacementSite
jmp r11
的形式。这种hook的主要局限在于不能返回调用原始函数。因此必须谨慎选择hook的目标。于是代码劫持的过程为:
1. 注入一个native dll (dllloader)到codesys进程
2. dllloader加载一个.net库(hijack)并执行
3. hijack库中执行hook,对codesys函数进行替换

针对前端的攻击

对编译前端攻击的主要思路是追踪编译流程,在一个合适的地方,对编译的源文件或者中间结果进行篡改。经过分析,我们选择:
LanguageModelManagerConsolidated.CreateScanner函数作为攻击目标,因为这个函数接受一个ST代码字符串的输入作为入参:
IScanner CreateScanner(string stText, bool bIncludeComments, bool bIncludeEndOfLines, bool bIncludePragmas, bool bIncludeWhitespaces)
生成的IScanner对象会被后面的文本解析所使用,并传递给编译器后端。因此攻击方法就是劫持这个函数,将ST源码替换成恶意的。
以一个演示性质的分类流水线工程为例,此项目展示一个垃圾分离器,能将各种不同类型的物品在流水线上分类并计数。
基于CODESYS软件PLC的“震网式”攻击
当物品为怪物时,则暂停流水线,同时alarm灯亮。
基于CODESYS软件PLC的“震网式”攻击
我们劫持并替换部分ST代码,替换PLC_PRG的部分代码,
基于CODESYS软件PLC的“震网式”攻击
注入Codesys后重新编译代码执行
基于CODESYS软件PLC的“震网式”攻击
怪物直接掉了下去,而流水线没有停止,而是显示FINISHED;这在实际工业场景中可能是某种灾难性的结果,而这一切从工程代码中看不出任何异常。

 针对后端的攻击

针对编译器前端的攻击虽然能避免跨平台问题但是ST的表达能力毕竟有限,难以进行进一步的控制。那么能不能把远控后门直接写入到编译后的代码中呢?答案是肯定的。
跟踪分析编译器代码生成组件,发现对模拟器和Windows版PLC的代码生成库为code386, 其中Generate函数接收一个pou,并获取AST语法树,遍历语法树进行代码生成。
publicvoid Generate(ICompiledPOU cpou, bool bKeepCodeList)      {          this.Generate(cpou,cpou.ParseTree as ISequenceStatement, bKeepCodeList, null);     }
代码检查绕过
对code386进行劫持过程中,发现IDE启动编译会立即退出,刚开始以为是代码的问题,经过调试发现,是由于CodeSys主动对调用栈的所有模块进行了校验,检查是否存在第三方程序,如果有即主动退出:
基于CODESYS软件PLC的“震网式”攻击
经过分析,发现该检查方法会放过mscorlib,即微软的.net库,于是我们把劫持的库的名字改成”mscorlib”即可绕过此检查过程。

shellcode植入

首先使用metasploit生成一个reverse_tcp shellcode
基于CODESYS软件PLC的“震网式”攻击
劫持Generate函数,当代码生成的函数是我们要替换的函数时,直接替换为shellcode作为生成结果。
基于CODESYS软件PLC的“震网式”攻击
重新生成工程并下载到PLC中执行,监听的handler立即收到反弹的shell:
基于CODESYS软件PLC的“震网式”攻击

 总结

此项研究在CodeSys V3.5 SP17上进行测试,成功在模拟器和CodeSys Control Win上实现了攻击,攻击的前提是能注入dll到CodeSys IDE进程中。虽然针对工控系统的劫持类攻击的研究很多,但直接从编译系统着手的似乎并不是很多。从攻击者角度来看,此类攻击有两个特点:
1. 针对编译器的攻击方式很难做得通用,因为编译过程一般比较复杂并且和程序逻辑本身无关,要取巧就只能针对某一个特定得点展开
2. 分析的难度往往大于实施攻击的难度,从防御的角度来讲,此类攻击隐蔽性较强,受的攻击的面可能很大(编译链条的各处都可能受到攻击),工控系统相对封闭,更缺少有效的手段去反制。目前来说可能的对抗措施有:1、提高分析的难度;2、提供编译中间状态和编译结果的校验工具,让运维和开发人员可以校验编译器是否被干扰。

参考文献:

Stuxnet ‐ Infecting Industrial ControlSystems
Applying a Stuxnet Type Attack to a ModiconPLC (CVE-2020-7475)
Remote code Execution On EcoStruxure PLCsimulator (CVE-2020-28211, CVE-2020-28212, CVE-2020-28213)
Stuxnet-in-a-Box: In-Field Emulation andFuzzing of PLCs to Uncover the Next Zero-Day Threat in Industrial ControlSystems
Applying a Stuxnet Type Attack to aSchneiderModicon PLC


原文来源:关键基础设施安全应急响应中心
“投稿联系方式:孙中豪 010-82992251   [email protected]
基于CODESYS软件PLC的“震网式”攻击

原文始发于微信公众号(网络安全应急技术国家工程实验室):基于CODESYS软件PLC的“震网式”攻击

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月12日07:00:04
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   基于CODESYS软件PLC的“震网式”攻击http://cn-sec.com/archives/733993.html

发表评论

匿名网友 填写信息