zoukankan      html  css  js  c++  java
  • [工控安全][原创]西门子PLC固件逆向之定位s7comm协议的一个切入口

    [原创]西门子PLC固件逆向之定位s7comm协议的一个切入口

    mailto:wangkai0351@gmail.com

    【未经同意禁止转载】

    鉴于本博客涉及的信息安全技术具有破坏计算机信息系统的风险,建议读者在学习/研究/探讨之前,确保已经充分了解以下内容:

    本博客所讨论的技术仅限于研究和学习,旨在提高计算机信息系统的安全性,严禁用于不良动机,任何个人/团队/组织不得将其用于非法目的,否则后果自负,特此声明。

    Choice,the problem is choice!

    在西门子PLC CPU固件逆向工程的研究工作中[1],我常常找不到一个合适的切入点。

    众所周知,一个CPU芯片私有、嵌入式操作系统私有、文件系统私有、应用层协议栈私有,甚至开发以上软件的编译器都是私有,并且没有符号表symbol table时,逆向工作是多么的困难。这和常见的物联网设备逆向[2]的难度是不可同日而语的。

    那么,没有头绪的情况下,我并没有choice的空间,只有妄图依靠灰箱知识找到一个突破口。

    我们知道s7comm的protocol id是0x32,所以使用“== 0x32”这个条件去全局搜索反编译结果,搜索结果如下

    Line 112668:         if ((piParm1 == 0x32) && (piParm1[0x16] == 0x14)) {
    Line 391457:     if (bVar1 == 0x32) {
    Line 446366:   if (psParm1 == 0x32) {
    Line 491055:   if ((((pcParm1 == 0x32) && (pcParm1[1] == 0x01)) && (pcParm1[10] == 0xf0)) &&
    Line 492543:   if (pcVar4 == 0x32) {
    Line 530415:     if (uParm2 == 0x32) goto LAB_00241bd0;
    

    我很快定位到491055行这条语句,如下所示。

    undefined4 s7comm_job_setup_communication_judge(char *pcParm1)
    //当然,在没有符号表的情况下,这个函数名是我自己修改的
    {
      undefined4 uVar1;
      
      if ((((*pcParm1 == 0x32) && (pcParm1[1] == 0x01)) && (pcParm1[10] == 0xf0)) &&
         ((*(short *)(pcParm1 + 0xc) != 0 && (*(short *)(pcParm1 + 0xe) != 0)))) {
        uVar1 = 1;
      }
      else {
        uVar1 = 0;
      }
      return uVar1;
    }
    

    看到这个非常冗长的判断条件自然令人兴奋,它和我们熟悉的s7comm协议中建立应用层连接的报文似乎存在千丝万缕的关系。

    我们找到一个s7comm协议的数据包例子,对比s7comm_job_setup_communication_judge函数的判断条件和真实的setup communicaiton报文有什么关系?

    我以网络上公开的一个s7comm数据包集合为例[3],下图展示了我要分析的一条setup communicaiton报文。

    从上图中抽出s7comm应用层的字段描述和值,摆在下面。

    //job_setup_communication报文应用层payload
    0000   32 01 00 00 02 00 00 08 00 00 f0 00 00 01 00 01   2...............
    0010   01 e0                                             ..
    
    Header: (Job)
        Protocol Id: 0x32
        ROSCTR: Job (1)
        Redundancy Identification (Reserved): 0x0000
        Protocol Data Unit Reference: 512
        Parameter length: 8
        Data length: 0
    Parameter: (Setup communication)
        Function: Setup communication (0xf0)
        Reserved: 0x00
        Max AmQ (parallel jobs with ack) calling: 1
        Max AmQ (parallel jobs with ack) called: 1
        PDU length: 480(字节?)
    

    接着,我们细致分析固件中这条判断条件

      if ((((*pcParm1 == 0x32) && (pcParm1[1] == 0x01)) && (pcParm1[10] == 0xf0)) &&
         ((*(short *)(pcParm1 + 0xc) != 0 && (*(short *)(pcParm1 + 0xe) != 0)))) {
    

    分开来写,

    条件1)s7comm.header.protid == 0x32,s7comm

    条件2)s7comm.header.rosctr == 0x01,Job

    条件3)s7comm.param.func == 0xf0,Setup communication

    条件4)s7comm.param.maxamq_calling != 0,Max AmQ calling

    条件5)s7comm.param.maxamq_called != 0,Max AmQ called

    可以看出,这五个判断条件和s7comm数据包实例中字段是可以一一对应上的,且符合我们对s7comm协议的灰盒知识。

    由此,印证了我们之前的推论,s7comm_job_setup_communication_judge函数是判断PLC设备接收到的某条报文是不是符合条件的s7comm.header.rosctr为job&&s7comm.param.func为setup communication报文。

    我们找到了s7comm_job_setup_communication_judge作为西门子PLC CPU设备固件逆向的一个突破口,围绕这个突破口,我们展开下一阶段的工作设想。

    从s7comm_job_setup_communication_judge函数向前看

    1. 函数判断条件中那没有涉及到的字段有

      1)s7comm.header.redid

      2)s7comm.header.pduref

      3)s7comm.header.parlg

      4)s7comm.header.datlg

      5)s7comm.param.setup_reserved1

      6)s7comm.param.pdu_length

      为什么没有判断,job_setup_communication中各个字段有什么作用?

    2. s7comm_job_setup_communication_judge函数的输入极有可能是socket_recv的报文队列,它的地址是什么?

    3. socket_recv函数和这个队列的关系?

    从s7comm_job_setup_communication_judge函数向后看

    1. 如果s7comm_job_setup_communication_judge函数输出等于1,下面PLC应该构造ack_data_setup_communication报文,构造函数是什么?
    2. 构造好的ack_data_setup_communication报文,如何通过socket_send函数发送出去?

    以上问题,我们日后将一一尝试解答。

    致谢

    感谢众多安全研究员公开发表自己的研究成果,并热情地回复我的疑问,这些人包括但不限于Dillon Beresford/Ali Abbasi/Thomas Weber/Ralf Ramsauer/Gene blue。


    1. 我手上under test的西门子PLC CPU模块属于早期的S7-1200系列(十分抱歉,我不能公开该设备的订货号、固件版本等指纹信息),它既支持s7comm协议,也支持s7comm-plus协议;因为产品硬件版本和固件版本太低,极大概率不支持s7comm-plus-plus协议。我使用IDA Pro和Ghidra等工具反汇编/反编译了该设备的固件。 ↩︎

    2. 《揭秘家用路由器0day漏洞挖掘技术》 ↩︎

    3. https://github.com/gymgit/s7-pcaps/blob/master/snap7_s300_setupCommunication.pcapng ↩︎

  • 相关阅读:
    古谚、评论与论断、名篇与名言
    重读《西游记》
    重读《西游记》
    命名之法 —— 时间、季节、地点
    命名之法 —— 时间、季节、地点
    文言的理解 —— 古时的称谓、别称、别名
    文言的理解 —— 古时的称谓、别称、别名
    Oracle GoldenGate for Oracle 11g to PostgreSQL 9.2.4 Configuration
    瀑布 敏捷 文档
    POJ 1325 ZOJ 1364 最小覆盖点集
  • 原文地址:https://www.cnblogs.com/bianmu-dadan/p/12684571.html
Copyright © 2011-2022 走看看