不安全的设计
在前一段时间,对市面上的常见的组态软件(包括三菱,组态王,施耐德,西门子等上位机软件)进行安全测试时发现不仅国内的组态软件存在组态工程密码绕过问题,一些国外的大厂也存在类似的问题,包括硬编码的密码,组态工程密码没有作为密钥加密组态工程文件,不安全的算法实现等。
对于硬编码密码的漏洞(如CNVD-2019-30119),厂商快速完成了修复,移除了硬编码密码,但是组态工程文件没有得到“真正”的保护。大多数存在漏洞的组态软件仅仅将用户输入的密码与真正的密码(或者密码hash)进行对比,而没有使用输入的密码加解密组态工程文件,这就导致无论输入什么密码,都可以通过逆向手段找到关键的跳转语句,修改指令让校验流程始终走向正确的分支(如下图所示)。对于这类的安全问题,解决方法只能是花费大量的时间和精力重新设计加密机制,并且需要敦促用户使用更新补丁。这便造成了很多厂商认为这类问题无关紧要,不愿花更多资源投入到漏洞的修复当中。
更安全的工程加密机制
毫无疑问,组态工程文件加密的算法实现一定是需要让组态工程密码参与到数据的加解密运算中,否则使用密码的任何加密存储形式(sha1 ,md5,sha256等hash算法)都是没有作用的。在设计组态工程加密的机制要考虑以下原则:
加密算法必须保证非常可靠,能够防止攻击者从加密的密文反向推出明文或者密钥。在这里,可以选择AES(Advanced Encryption Standard)这类非常成熟的加密算法。
足够长度的salt是必须的,将salt值附加到密码后面作为加解密密钥以此来保证密钥强度,这样可以有效抵御字典暴力攻击。
考虑到用户如果忘记密码,软件生产商必须有能力从用户的组态工程文件中恢复密码(当然留下后门密码肯定是不可取的),所以必须将正确的加密密钥通过非对称算法(如RSA2048)加密存到工程文件中,一旦证明了该组态工程文件是该用户所有的,软件生产厂商可以使用拥有的私钥去解密密文从而恢复密码。
算法选择应该尽量选择现成加密库的算法,例如OpenSSL,减少开发商编写代码的成本。
加密流程如下图所示:
一旦存在有些粗心的用户忘记了自己的组态工程密码,只要能证明该组态工程文件为自己所有,那么用户就可以通过开发商找回密码。具体找回密码流程如下图所示:
工程密码保护
对于组态工程密码来说,当用户输入正确的组态工程密码后,上位机软件会用该密码解密组态工程文件,并需要将密码一直存在于内存中,直到用户关闭组态工程文件才会将内存中保存的工程密码(期间用户可能修改密码)作为密钥加密组态工程文件并进行保存。整个生命周期如下图所示:
可以看出,正确的密码一直保存在内存中,直到工程被关闭。所以,对于内存中的密钥也需要一定的保护措施,防止其他恶意软件在组态工程文件打开的情况下通过读取进程内存空间的方法窃取到敏感的密钥信息。Windows系统已经内置了一些的函数保护敏感的内存信息(如CryptProtectMemory/CryptUnProtectMemory),Linux平台上的开发者也可以选择开源的第三方安全组件实现内存敏感信息加密。
总结
组态工程加解密实现的方法有很多种,本文提供的方法只是一个简单的例子,读者可以举一反三,探索出适合自己的加解密方式。工业控制系统安全不仅需要用户提高安全意识,同时也需要软硬件生产厂商高度重视,为用户提供更好的服务。
【本文是51CTO专栏作者“绿盟科技博客”的原创稿件,转载请通过51CTO联系原作者获取授权】