专栏首页ffffffff0x[ffffffff0x] 工控协议:S7COMM协议分析(下)
原创

[ffffffff0x] 工控协议:S7COMM协议分析(下)

前言

在上一篇文章中,我们介绍了S7Comm协议的S7Comm Header和Job 和 Ack_Data机制。本篇文章,我们将继续介绍S7Comm协议的Userdata 协议拓展并结合pcap流量包实际分析。


Userdata 协议拓展

UserData 用于编程/调试、读取 SZL、安全功能、时间设置,循环读取等。

Parameter 结构如下:

  • 1 (3 bytes):参数头(Parameter head);
  • 2 (1 byte):参数长度(Parameter length),它的可能是8字节或12字节;
  • 3 (1 byte):未知定义;
  • 4 (1/2 byte,高位):参数类型(Type);
  • 5 (1/2 byte,Low nibble):功能组(Function group);
  • 6 (1 byte):子功能码(SubFunction);
  • 7 (1 byte):序号。

转换工作模式(Mode-transition 0x0)

当功能组为转换工作模式(Mode-transition)时,请求报文中是没有 Data 部分的,而主要起作用的是子功能码(Subfunction),常见的子功能码有:

  • STOP(0x00):STOP 模式;
  • Warm Restart(0x01):暖启动;
  • RUN(0x02):RUN 模式;
  • Hot Restart(0x03):热启动;
  • HOLD(0x04):HOLD 模式;
  • Cold Restart(0x06):冷启动;
  • RUN_R (H-System redundant)(0x09):H-System 冗余运行;
  • LINK-UP(0x0B):LINK-UP 模式;
  • UPDATE(0x0C):UPDATE 模式。

程序员命令(Programmer commands 0x1)

程序员命令(Programmer commands)主要是工程师用于编程或调试,比如:监视/修改变量、读取修改诊断数据。所有的子功能码有:

  • 请求诊断数据(Request diag data (Type 1)):0x01;
  • 变量表(VarTab):0x02;
  • 读取诊断数据(Read diag data):0x0c;
  • 移除诊断数据(Remove diag data):0x0e;
  • 清除(Erase):0x0f;
  • 强制(Forces):0x10;
  • 请求诊断数据(Request diag data (Type 2)):0x13;

请求报文的结构如下:

  • 1 (1 byte) : 返回码;
  • 2 (1 byte) :Transport sizes,指的数据类型,通常有 bit、byte等;
  • 3 (2 bytes) : 往后的数据长度;
  • 4 (1 byte) : Unknown;
  • 5 (1 byte) : 报文类型(type of data),分为请求(0x14)、响应(0x04);
  • 6 (2 bytes) : Item count和Item data的长度(Byte count);
  • 7 (20bytes) : Unknown;
  • 8 (2bytes) : Item 个数;
  • 9 (varibalebytes) : Item 1;
    • 1 (1 byte) : 区域(Area);
    • 2 (1 byte) : 长度(Length (repetition factor));
    • 3 (2 bytes) : 模块号(DB number);
    • 4 (2 bytes) : 偏移地址(Startaddress)。
  • n (varibalebytes) : Item n;

响应报文结构如下:

  • 1 (1 byte) : 返回码;
  • 2 (1 byte) :数据类型(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 往后的数据长度;
  • 4 (1 byte) : Unknown;
  • 5 (1 byte) : 报文类型(type of data),分为请求(0x14)、响应(0x04);
  • 6 (2 bytes) : Item count 和 Item data 的长度(Byte count);
  • 7 (4bytes) : Unknown;
  • 8 (2bytes) : Item 个数;
  • 9 (varibalebytes) : Item 1;
  • 1 (1 byte) : 返回码;
  • 2 (1 byte) :数据类型(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 往后的数据长度;
  • 4 (varibale bytes) : Data。
  • n (varibalebytes) : Item n;

块功能(Block functions 0x3)

块功能(Block functions)是用于操作块,所有的子功能码有:

  • 0x01:列举所有块(List blocks);
  • 0x02:列举块类型(List blocks of type);
  • 0x03:读取块的信息(Get block info)。

CPU功能(CPU functions 0x4)

CPU 功能(CPU functions)是用于操作块,所有的子功能码有:

  • 0x01:读系统状态列表(Read SZL);
  • 0x02:消息服务(Message service);
  • 0x03:诊断消息(Diagnostic message),PLC 的诊断消息;
  • 0x05:ALARM_8 显示(ALARM_8 indication), PLC 使用ALARM_8 SFBs 来显示报警消息;
  • 0x06:NOTIFY 显示(NOTIFY indication),PLC 使用 NOTIFY SFBs 来显示 NOTIFY 消息;
  • 0x07:ALARM_8 锁定(ALARM_8 lock), 需要通过 HMI/SCADA 锁定ALARM 消息;
  • 0x08:ALARM_8 取消锁定(ALARM_8 unlock), 需要通过 HMI/SCADA 取消锁定 ALARM 消息;
  • 0x09:SCAN 显示(SCAN indication),PLC 显示 SCAN 消息;
  • 0x0b:ALARM 确认(ALARM ack),报警信息已在 HMI/SCADA 中得到确认;
  • 0x0c:ALARM 确认显示(ALARM ack indication), 从 CPU 到 HMI 的确认报警显示;
  • 0x0d:ALARM 锁定显示(ALARM lock indication),从 CPU 到 HMI 的锁定报警显示;
  • 0x0e:ALARM 取消锁定显示(ALARM unlock indication),从 CPU 到 HMI 的取消锁定报警显示;
  • 0x11:ALARM_SQ 显示(ALARM_SQ indication),PLC 使用 ALARM_SQ/ALARM_DQ SFCs 来显示 ALARM 消息;
  • 0x12:ALARM_S 显示(ALARM_S indication),PLC 使用 ALARM_S/ALARM_D SFCs 来显示 ALARM 消息;
  • 0x13:ALARM 查询(ALARM query),HMI/SCADA 查询 ALARM;
  • 0x16:NOTIFY_8 显示(NOTIFY_8 indication)。

子功能码有4种不同的功能类型:

  • 系统状态列表(SZL)

系统状态列表(德语:System-ZustandsListen,英语:System Status Lists)用于描述可编程逻辑控制器的当前状态。SZL的内容只能通过信息功能进行读取,而不能修改。换言之,部分列表是虚拟列表,只在有特殊请求时由CPU的操作系统所创建。

系统状态列表包含下列内容的有关信息:

  • 系统数据
  • CPU 中的模块状态数据
  • 模块的诊断数据
  • 诊断缓冲区

如果要读取系统状态列表,则需要使用参数 SZL-ID 和 INDEX 指定要读取的内容。比如:读取 PLC 的名称,那 SZL-ID 是 W#16#011C,INDEX 是 W#16#0001

每个部分系统状态列表都有一个编号。可以根据编号输出完整的部分列表或摘录。预定义了可能的部分列表摘录,并由一个数字标识。SZL-ID 由部分列表的编号、部分列表摘录的编号和模块等级组成。

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (2 bytes):SZL-ID;
  • 5 (2 bytes):SZL-Index;

响应报文 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (2 bytes):SZL-ID,部分列表摘录的 SZL-ID,以 W#16#xy1C 为例,常见的 SZL-ID 如下:
    • W#16#001C:所有组件的标识;
    • W#16#011C:一个组件的标识;
    • W#16#021C:H系统中一个CPU的所有组件的标识;
    • W#16#031C:H系统中所有冗余CPU的一个组件的标识;
    • W#16#0F1C:仅限SSL部分列表报头信息;
  • 5 (2 bytes):SZL-Index,不同的 SZL-ID 那 SZL-Index 不一样。以 W#16#011C 和 W#16#031C 的部分列表摘录的组件标识:
    • W#16#0001:自动化系统的名称;
    • W#16#0002:模块名称;
    • W#16#0003:模块的设备标识;
    • W#16#0004:版权;
    • W#16#0005:模块的序列号;
    • W#16#0007:模块类型名称;
    • W#16#0008:存储卡的序列号在不能插入存储卡的模块中,不提供 数据记录;
    • W#16#0009:CPU 模块的制造商和配置文件;
    • W#16#000A:模块的 OEM ID(仅限 S7-300);
    • W#16#000B:模块的位置指定;
  • 6 (2 bytes):部分列表的长度(SZL partial list length in bytes),不同的 SZL-ID 那长度不一样;
  • 7 (2 bytes):部分列表的个数(SZL partial list count);
  • 8 (34 bytes):SZL 1;
  • n (34 bytes):SZL n;
  • 消息服务(Message service)

消息服务(Message service)主要用于订阅事件,比如:切换工作模式事件、系统诊断事件等。

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (1 byte):订阅事件(Subscribed events),常见的事件有:
    • 0x01(MODE):切换工作模式;
    • 0x02(SYS):系统诊断;
    • 0x04(USR):用户定义的诊断消息;
    • 0x08:未知;
    • 0x10:未知;
    • 0x20:未知;
    • 0x40:未知;
    • 0x80(ALM):程序块消息,附加字段中的消息类型;
  • 5 (1 byte):未知(Unknown);
  • 6 (varibale bytes):用户名(Username);

响应报文 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (1 byte):订阅的结果:
  • n (4 bytes):预留(Reserved 2)
  • 诊断消息(Diagnostic message)

诊断消息(Diagnostic message)通常是诊断缓冲区中的数据

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (2 bytes):事件 ID(Event ID);
  • 5 (1 byte):优先级(Priority class);
  • 6 (1 byte):OB 编号(OB number);
  • 7 (2 bytes):DatID;
  • 8 (2 bytes):附加信息(Additional information 1);
  • 9 (4 bytes):附加信息(Additional information 2);
  • 10 (8 bytes):时间戳;

每个事件都分配有事件 ID,而事件 ID 的结构如图

那事件 ID 的内容,包括:

  • 0-7位:事件编号(Event Number);
  • 8-11位:识别(IDs),标识符用于区分事件的类型。
  • 12-15位:事件等级(Event Class)
  • 告警消息及告警查询

在这里,把 ALARM_8 显示(0x05)、NOTIFY 显示(0x06)、ALARM_8 锁定(0x07)、ALARM_8 取消锁定(0x08)、SCAN 显示(0x09)、ALARM 确认(0x0b)、ALARM 确认显示(0x0c)、ALARM 锁定显示(0x0d)、ALARM 取消锁定显示(0x0e)、ALARM_SQ 显示(0x11)、ALARM_S 显示(0x12)、ALARM 查询(0x13)、NOTIFY_8 显示(0x16)共13个子功能归纳为告警信息。

  • ALARM 查询(0x13)

请求报文的 Data 结构如下:

* 1 (1 byte) : 返回码(return code);
* 2 (1 byte) : 数据传输大小(Transport sizes);
* 3 (2 bytes) : 以此往后的数据长度;
* 4 (1 byte):功能标识(Function identifier);
* 5 (1 byte):消息对象个数(Number of message objects);
* 6 (varibale byte):Message Object 1;
  * 1 (1 byte):Variable specification;
  * 2 (1 byte):以下规范地址的长度(Length of following address specification);
  * 3 (1 byte):Syntax Id;
  * 4 (1 byte):Unknown;
  * 5 (1 byte):查询类型(Querytype),类型有:
    * 0x01:告警类型(ByAlarmtype);
    * 0x03:事件ID(ByEventID);
    * 0x08:Unknown;
    * 0x09:Unknown;
  * 6 (1 byte):Unknown;
  * …
* …

响应报文 Data 结构如下:

* 1 (1 byte) : 返回码(Return code);
* 2 (1 byte) : 数据传输大小(Transport sizes);
* 3 (2 bytes) : 以此往后的数据长度;
* 4 (1 byte):功能标识(Function identifier);
* 5 (1 byte):消息对象个数(Number of message objects);
* 6 (1 byte) : 数据传输大小(Transport sizes);
* 7 (2 bytes) : 完整数据长度,也就是以此往后的数据长度;
* 8 (varibale byte):Message Object 1;
  * 1 (1 byte) :长度(Length of dataset);
  * 2 (2 bytes):Unknown;
  * 3 (1 byte):告警类型(Alarmtype);
  * 4 (4 bytes):事件ID;
  * 5 (1 byte):Unknown;
  * 6 (1 byte):事件状态(EventState);
  * 7 (1 byte):AckState going;
  * 8 (1 byte):AckState coming;
* …
* n (varibale byte):Message Object n;ALARM 显示、ALARM 锁定/解锁、ALARM 确认、NOTIFY 显示

往往这类报文都是以PUSH的形式存在, Data 结构如下:

* 1 (1 byte) : 返回码(Return code),具体的可参考6.6;
* 2 (1 byte) : 数据传输大小(Transport sizes),具体可参考6.4.2;
* 3 (2 bytes) : 以此往后的数据长度;
* 4 (8 bytes):事件时间,如果subfunc是0x09,那长度为2 bytes;
* 5 (1 byte):功能标识(Function identifier);
* 6 (1 byte):消息对象个数(Number of message objects);
* 7 (varibale byte):Message Object 1;
  * 1 (1 byte):Variable specification;
  * 2 (1 byte):长度(Length of following address specification);
  * 3 (1 byte):Syntax Id,常见的结构标识可参考6.5;
  * 4 (1 byte):相关值数目(Number of associated values);
  * 5 (4 bytes):事件ID;
  * `6 (1 byte):事件状态(EventState);`
  * `7 (1 byte):状态(State);`
  * `8 (1 byte):AckState going;`
  * `9 (1 byte):AckState coming;`
  * `10 (varibale bytes):Associated value 1;`
    * `1 (1 byte) : 返回码(Return code);`
    * `2 (1 byte) : 数据传输大小(Transport sizes);`
    * `3 (2 bytes) : 长度;`
    * `4 (varibale bytes):Data;`
  * `...`
  * `n (varibale bytes):Associated value n;`
* …
* n (varibale byte):Message Object n;

安全功能(Security 0x5)

安全功能(Security)是用于安全设置,比如:设置 PLC 密码,所有的子功能码有:

  • 0x01:PLC 密码(PLC password);
  • 0x02:清除密码(Clear PLC password)。

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 数据长度;
  • 4 (varibale byte):Data;

响应报文 Data 结构如下:

  • 1 (1 byte) : 返回码(Return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;

PBC BSEND/BRECV 0x6

  • PBC:Programmable Block Functions,可编程块函数,比如:SFB/FB;
  • BSEND/BRCV:到通信伙伴的固定数据块传送。也就是说,在通信伙伴中的接收函数(BRCV)接受该数据之前,数据传送不会结束。

时间功能(Time functions 0x7)

时间功能(Time functions)是用于时间设置,比如设置时间,所有的子功能码有:

  • 0x01:读时间(Read clock);
  • 0x02:设置时间(Set clock);
  • 0x03:读时间(Read clock (following));
  • 0x04:设置时间(Set clock)。

读取时间的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 以此往后的数据长度。

设置时间的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (10 bytes):时间戳。流量包分析

这里我们使用snap7本地模拟相应的请求流量,并抓包查看。

块功能(Block functions 0x3)

  • 列举所有块(List blocks)
    • 请求
  • 响应
  • 列举块类型(List blocks of type)
    • 请求
  • 响应
  • 读取模块的信息(Get block info)
    • 请求

CPU功能(CPU functions 0x4)

  • 系统状态列表(SZL)
    • 请求
  • 响应

安全功能(Security 0x5)

  • PLC密码(PLC password)
  • 请求

Data 是 64 67 02 06 62 65 17 10

* 第1位:0x64 ^ 0x55 = 0x31,则值是1;
* 第2位:0x67 ^ 0x55 = 0x32,则值是2;
* 第3位:0x02 ^ 0x55 ^ 0x64 = 0x33,则值是3;
* 第4位:0x06 ^ 0x55 ^ 0x67 = 0x34,则值是4;
* 第5位:0x62 ^ 0x55 ^ 0x02 = 0x35,则值是5;
* 第6位:0x65 ^ 0x55 ^ 0x06 = 0x36,则值是6;
* 第7位:0x17 ^ 0x55 ^ 0x62 = 0x20,则值是 (空);
* 第8位:0x10 ^ 0x55 ^ 0x65 = 0x20,则值是 (空);
  • 响应

时间功能(Time functions 0x7)

  • 读时间(Read clock);
    • 请求
  • 响应

总结

本文,我们分析了S7Comm协议的Userdata 协议拓展部分。通过与pcap流量包的结合分析,可以更加直观的了解其原理和交互过程,学习S7Comm协议对于工控安全非常重要,在之后的文章里,我们还将继续学习modbus和Ethernet/IP协议相关内容。


本文作者 r0fus0d

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [ffffffff0x] 工控协议:S7COMM协议分析(上)

    在上一篇文章中,我们通过模拟器环境实现了S7-300的启停实验。本次文章,我们将详细介绍S7comm协议的S7Comm Header和Job 和 Ack_Dat...

    r0fus0d
  • 西门子S7comm-plus通信过程及重放攻击分析

    西门子PLC广泛应用于工业控制系统。本文主要利用手上S7-1200 V3.0.2 固件版本的PLC和TIA13等环境进行S7comm-plus加密协议初步分析及...

    FB客服
  • 原创 | S7Comm-Plus协议分析之数据区访问

    概述:西门子PLC使用私有协议进行通信,端口为102。西门子PLC协议有3个版本,S7Comm协议,早期S7CommPlus协议和最新的S7CommPlus协议...

    绿盟科技研究通讯
  • 西门子S7系列PLC安全防护研究

    近年来,随着中国制造的不断崛起,工业控制系统已成为国家关键基础设施的重中之重,工控系统的安全问题也随之而来。工控产品的多样化,造成了工控系统网络通讯协议不同,大...

    FB客服
  • 协议分析|HTTP协议浅析

    HTTP和HTTPS Cookie、Session HTTP请求方法(Get/Post) 一次HTTP请求的过程 一次请...

    Ms08067安全实验室
  • [ffffffff0x] 工控安全:S7-300启停实验

    西门子(SIEMENS)公司的 PLC 产品包括 LOGO、S7-200、S7-1200、S7-300、 S7-400、S7-1500 等。西门子 PLC 在我...

    r0fus0d
  • Http协议分析

    HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目...

    用户2909867
  • [linux][network]ICMP协议分析

    前言: ICMP比较基础,说简单不简单,说难不难。 简单在于字段少,不能携带用户数据,没什么地方可以玩出太多花样;一般和它相关的就是ping和tracerout...

    皮振伟
  • 工业控制系统蜜罐的初步介绍

    随着科技的发展,工业控制系统逐渐的接入互联网,而当前互联网上存在着大量的攻击,直接影响着工业控制系统的安全,工控系统面临的安全形势也越来越严重。2010年的伊朗...

    FB客服

扫码关注云+社区

领取腾讯云代金券