# IEC60870 协议浅析

最近经常碰到 IEC60870 协议的题目,就拿巅峰极客 2022 决赛 babyProtocol 来记录一下

# IEC60870

首先先大致了解一下这个协议的子协议

1
2
3
4
5
IEC 101(任务相关)
IEC 102(电量相关)
IEC 103(保护相关)
IEC 104(101的网络版)
IEC ASDU(基于101/104的应用服务数据单元传输)

还有一些技巧

1
2
3
筛选iec60870_asdu
关注IOA的值
可尝试用type进行分类

接着分析一下报文,例如以下报文:

1
6812500002000f01030005060e0000640000001c

借用网上拉下来的一张分析截图

image-20240922190231930

我的数据和截图中的数据并不一样,但都是一段完整的 IEC104 报文,68 即为头部开始数据标志,而后面跟着的 1 字节便是数据报文长度我这里为 16 进制的 12 也就是 18 字节(从发送序号开始算)

这样的话我们就可以知道:带上头部 1 字节的 68 和报文长度 1 字节,总共的头部可以算做 15 字节,剩下的便是数据。以我这段数据来看 640000001c 便是数据

# babyProtocol

接着看看题目,先看下协议分级

image-20240922190905793

发现 icmp 也有数据,可以先不管放在一边,过滤 iec60870_asdu 看看

image-20240922190948535

发现最显眼的就是后面 IOA 块数据的变动

按照对报文的分析仔细看看每一个数据包,发现 IOA 为 1 时 binary counter 的值为 102 也就是 f,IOA 为 2 时 binary counter 的值为 108 也就是 l

image-20240922192300120

image-20240922192243792

以此类推,最终的 flag 就能被推断出来

但是手撸还是很麻烦的,仔细看下报文

image-20240922192454207

可以发现 IOA 的值就在我们所说的 15 字节报文头中的倒数第三个字节也就是报文头部的第 13 字节

并且最后一个字节所对应的字段 IV 是用来判断该值是否为有效的

image-20240922192709440

image-20240922192731098

随便翻翻可以知道并不是所有的值都是有效的,但是唯一方便的就是不管是索引值还是数据值,甚至 IV,都在我们所需要提取的报文当中,这样可以直接用脚本切片来判断和排序即可

这里南溟 NaN 师傅博客上的脚本已经十分完整了,引用一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
data = """680407000000
68040b000000
6812000002000f0103000506010000660000001b
6812020002000f0103000506010000660000001c
6812040002000f0103000506030000610000001b
680401000600
6812060002000f01030005060b0000640000001a
6812080002000f0103000506080000620000001b
68120a0002000f01030005060c0000390000001a
680e00000c0064010601020000000014
680e0c00020064014500020000000014
68120e0002000f0103000506110000380000001b
6812100002000f0103000506150000300000001a
680401001200
6812120002000f01030005061a00006500000018
6812140002000f01030005061e00003800000017
6812160002000f01030005062700003500000017
6812180002000f01030005061800006400000017
680401001a00
68121a0002000f01030005060500007b0000001b
68121c0002000f0103000506030000610000001c
68121e0002000f01030005060500007b0000001c
6812200002000f0103000506060000360000001b
6812220002000f01030005060a0000340000001b
6812240002000f01030005060c0000390000001b
680401002600
6812260002000f0103000506140000350000001b
6812280002000f01030005061700003900000017
68122a0002000f01030005061900006300000017
68122c0002000f01030005061900006300000018
68122e0002000f01030005061b00002d00000097
680401003000
6812300002000f01030005061c00006400000018
6812320002000f01030005061e00003800000018
6812340002000f01030005062700003500000018
6812360002000f01030005061800006400000018
680401003800
680401000200
6812380002000f0103000506040000670000001b
68123a0002000f0103000506030000610000001d
68123c0002000f0103000506040000670000001c
68123e0002000f01030005060500007b0000001d
680401004000
6812400002000f0103000506060000360000001c
6812420002000f0103000506070000380000001b
6812440002000f0103000506080000620000001c
6812460002000f0103000506090000330000001b
680401004800
6812480002000f01030005060d0000320000001b
68124a0002000f01030005060e0000640000001b
68124c0002000f01030005060a0000340000001c
68124e0002000f0103000506090000330000001c
6812500002000f01030005060e0000640000001c
680401005200
6812520002000f01030005060f0000380000001a
6812540002000f01030005060f0000380000001b
6812560002000f0103000506140000350000001c
6812580002000f01030005060e0000640000001d
68125a0002000f0103000506160000330000001b
68125c0002000f01030005061900006300000019
680401005e00
68125e0002000f01030005061c00006400000019
6812600002000f01030005062700003500000019
6812620002000f0103000506270000350000001a
6812640002000f0103000506010000660000001d
6812660002000f01030005060200006c0000001b
6812680002000f0103000506030000610000001e
68126a0002000f0103000506040000670000001d
680401006a00
68126c0002000f01030005060500007b0000001e
68126e0002000f0103000506060000360000001d
6812700002000f0103000506070000380000001c
6812720002000f0103000506080000620000001d
6812740002000f0103000506090000330000001d
6812760002000f01030005060a0000340000001d
6812780002000f01030005060b0000640000001b
68127a0002000f01030005060c0000390000001c
680401007a00
68127c0002000f01030005060d0000320000001c
68127e0002000f01030005060e0000640000001e
6812800002000f01030005060f0000380000001c
6812820002000f0103000506100000610000009a
6812840002000f0103000506110000380000001c
6812860002000f0103000506120000340000001b
6812880002000f0103000506130000340000001c
68128a0002000f0103000506140000350000001d
680401008a00
68128c0002000f0103000506150000300000001b
68128e0002000f0103000506160000330000001c
6812900002000f01030005061700003900000018
6812920002000f01030005062800007d00000017
6812940002000f0103000506190000630000001a
6812960002000f01030005061a00006500000019
6812980002000f01030005061b00002d00000098
68129a0002000f01030005061c0000640000001a
680401009a00
68129c0002000f01030005061d00003600000018
68129e0002000f01030005061e00003800000019
6812a00002000f01030005061f00003100000017
6812a20002000f01030005062000003900000017
6812a40002000f01030005062100006400000016
6812a60002000f01030005062200003200000016
6812a80002000f01030005062300003300000015
6812aa0002000f01030005062400003600000016
68040100aa00
6812ac0002000f01030005062500003200000016
6812ae0002000f01030005062600006400000016
6812b00002000f0103000506270000350000001b
6812b20002000f01030005061800006400000019
6812b40002000f01030005062500003200000017
68040100b600
6812b60002000f01030005061d00003600000019
6812b80002000f0103000506060000360000001e
6812ba0002000f0103000506040000670000001e
6812bc0002000f0103000506010000660000001e
68040100be00
6812be0002000f01030005060200006c0000001c
6812c00002000f0103000506100000610000009b
6812c20002000f01030005062400003600000017
68040100c400
6812c40002000f0103000506090000330000001e
6812c60002000f0103000506100000610000009c
6812c80002000f0103000506060000360000001f
68040100ca00
6812ca0002000f01030005062200003200000017
6812cc0002000f01030005062400003600000018
6812ce0002000f01030005062600006400000017
6812d00002000f01030005062000003900000018
68040100d200
6812d20002000f01030005060200006c0000001d
6812d40002000f01030005060200006c0000001e
6812d60002000f01030005060500007b0000001f
6812d80002000f01030005060b0000640000001c
6812da0002000f0103000506110000380000001d
68040100dc00
6812dc0002000f01030005062600006400000018
6812de0002000f01030005061c0000640000001b
6812e00002000f0103000506040000670000001f
6812e20002000f0103000506080000620000001e
68040100e400
6812e40002000f01030005060d0000320000001d
6812e60002000f01030005060a0000340000001e
6812e80002000f0103000506080000620000001f
6812ea0002000f01030005061a0000650000001a
68040100ec00
6812ec0002000f01030005062000003900000019"""
dic = {}
for i in data.splitlines():
if len(i) == len("6812000002000f0103000506010000660000001b"):
index = int(i[-16:-14], 16) - 1
c = chr(int(i[-10:-8], 16))
valid = bin(int(i[-2:], 16))[2:]
if valid.zfill(8)[0] == "0":
dic[index] = c
for i in range(0, 50):
if i in dic:
print(dic[i], end="")
else:
print("", end="")

当然,这里观察还可以发现只有 IOA 为 16 和 27 时 IV 为 Invalid,可以手动将这几条剔除,减轻脚本的工作量,这样脚本便可以不判断是否有效,只要排序并将数据转为 ASCII 码即可,这里编写了一个该思路的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
hex_strings = [
"6812000002000f0103000506010000660000001b",
"6812020002000f0103000506010000660000001c",
"6812040002000f0103000506030000610000001b",
"6812060002000f01030005060b0000640000001a",
"6812080002000f0103000506080000620000001b",
"68120a0002000f01030005060c0000390000001a",
"68120e0002000f0103000506110000380000001b",
"6812100002000f0103000506150000300000001a",
"6812120002000f01030005061a00006500000018",
"6812140002000f01030005061e00003800000017",
"6812160002000f01030005062700003500000017",
"6812180002000f01030005061800006400000017",
"68121a0002000f01030005060500007b0000001b",
"68121c0002000f0103000506030000610000001c",
"68121e0002000f01030005060500007b0000001c",
"6812200002000f0103000506060000360000001b",
"6812220002000f01030005060a0000340000001b",
"6812240002000f01030005060c0000390000001b",
"6812260002000f0103000506140000350000001b",
"6812280002000f01030005061700003900000017",
"68122a0002000f01030005061900006300000017",
"68122c0002000f01030005061900006300000018",
"6812300002000f01030005061c00006400000018",
"6812320002000f01030005061e00003800000018",
"6812340002000f01030005062700003500000018",
"6812360002000f01030005061800006400000018",
"6812380002000f0103000506040000670000001b",
"68123a0002000f0103000506030000610000001d",
"68123c0002000f0103000506040000670000001c",
"68123e0002000f01030005060500007b0000001d",
"6812400002000f0103000506060000360000001c",
"6812420002000f0103000506070000380000001b",
"6812440002000f0103000506080000620000001c",
"6812460002000f0103000506090000330000001b",
"6812480002000f01030005060d0000320000001b",
"68124a0002000f01030005060e0000640000001b",
"68124c0002000f01030005060a0000340000001c",
"68124e0002000f0103000506090000330000001c",
"6812500002000f01030005060e0000640000001c",
"6812520002000f01030005060f0000380000001a",
"6812540002000f01030005060f0000380000001b",
"6812560002000f0103000506140000350000001c",
"6812580002000f01030005060e0000640000001d",
"68125a0002000f0103000506160000330000001b",
"68125c0002000f01030005061900006300000019",
"68125e0002000f01030005061c00006400000019",
"6812600002000f01030005062700003500000019",
"6812620002000f0103000506270000350000001a",
"6812640002000f0103000506010000660000001d",
"6812660002000f01030005060200006c0000001b",
"6812680002000f0103000506030000610000001e",
"68126a0002000f0103000506040000670000001d",
"68126c0002000f01030005060500007b0000001e",
"68126e0002000f0103000506060000360000001d",
"6812700002000f0103000506070000380000001c",
"6812720002000f0103000506080000620000001d",
"6812740002000f0103000506090000330000001d",
"6812760002000f01030005060a0000340000001d",
"6812780002000f01030005060b0000640000001b",
"68127a0002000f01030005060c0000390000001c",
"68127c0002000f01030005060d0000320000001c",
"68127e0002000f01030005060e0000640000001e",
"6812800002000f01030005060f0000380000001c",
"6812840002000f0103000506110000380000001c",
"6812860002000f0103000506120000340000001b",
"6812880002000f0103000506130000340000001c",
"68128a0002000f0103000506140000350000001d",
"68128c0002000f0103000506150000300000001b",
"68128e0002000f0103000506160000330000001c",
"6812900002000f01030005061700003900000018",
"6812920002000f01030005062800007d00000017",
"6812940002000f0103000506190000630000001a",
"6812960002000f01030005061a00006500000019",
"68129a0002000f01030005061c0000640000001a",
"68129c0002000f01030005061d00003600000018",
"68129e0002000f01030005061e00003800000019",
"6812a00002000f01030005061f00003100000017",
"6812a20002000f01030005062000003900000017",
"6812a40002000f01030005062100006400000016",
"6812a60002000f01030005062200003200000016",
"6812a80002000f01030005062300003300000015",
"6812aa0002000f01030005062400003600000016",
"6812ac0002000f01030005062500003200000016",
"6812ae0002000f01030005062600006400000016",
"6812b00002000f0103000506270000350000001b",
"6812b20002000f01030005061800006400000019",
"6812b40002000f01030005062500003200000017",
"6812b60002000f01030005061d00003600000019",
"6812b80002000f0103000506060000360000001e",
"6812ba0002000f0103000506040000670000001e",
"6812bc0002000f0103000506010000660000001e",
"6812be0002000f01030005060200006c0000001c",
"6812c20002000f01030005062400003600000017",
"6812c40002000f0103000506090000330000001e",
"6812c80002000f0103000506060000360000001f",
"6812ca0002000f01030005062200003200000017",
"6812cc0002000f01030005062400003600000018",
"6812ce0002000f01030005062600006400000017",
"6812d00002000f01030005062000003900000018",
"6812d20002000f01030005060200006c0000001d",
"6812d40002000f01030005060200006c0000001e",
"6812d60002000f01030005060500007b0000001f",
"6812d80002000f01030005060b0000640000001c",
"6812da0002000f0103000506110000380000001d",
"6812dc0002000f01030005062600006400000018",
"6812de0002000f01030005061c0000640000001b",
"6812e00002000f0103000506040000670000001f",
"6812e20002000f0103000506080000620000001e",
"6812e40002000f01030005060d0000320000001d",
"6812e60002000f01030005060a0000340000001e",
"6812e80002000f0103000506080000620000001f",
"6812ea0002000f01030005061a0000650000001a",
"6812ec0002000f01030005062000003900000019"
]

sorted_hex_strings = sorted(hex_strings, key=lambda x: int(x[24:26], 16))

unique_hex_strings = []
last_byte_13 = None

for hex_string in sorted_hex_strings:
byte_13 = hex_string[24:26]
if byte_13 != last_byte_13:
unique_hex_strings.append(hex_string)
last_byte_13 = byte_13

ascii_output = ""

for hex_string in unique_hex_strings:
byte_16 = hex_string[30:32]
byte_16_decimal = int(byte_16, 16)
ascii_char = chr(byte_16_decimal)

ascii_output += ascii_char

print(f"Concatenated ASCII: {ascii_output}")

根据上述所说的协议分级,发现 icmp 协议也拥有数据,可以过滤查看一下

image-20240922203226005

发现每条数据都可以和我们过滤 iec60870_asdu 对照上只是没有判断是否有效的依据,但是无效数据挺少的,这样就可以利用该协议和 tshark 去更方便地提取数据,再编写脚本

1
tshark -r data.pcapng -T fields -e "data.data" -Y "icmp" > output.txt

但是这样提取出来的数据长度和结构都与报文不相同,因此需要修改脚本,思路还是一样,就不过多叙述了

PS:关于该协议还有好多题目,都蛮有意思的,时间允许的话慢慢琢磨慢慢记录