工控渗透框架ISF:PLC密码检测 – 作者:andiSEC

前言

上一篇《信息收集篇》中我们讲了如何使用ISF框架发现工控设备,那么有些小伙伴就会问了,发现工控设备之后能做些什么呢?答案是很多,比如:查看设备有没有密码保护?有密码保护能不能破解?破解后都能做些什么等等问题。为了让大家循序渐进地学会工控相关的安全攻防,我们需要先学习一些工控的相关知识。本篇我们就来讲讲与暴力破解相关的基础知识,为后续暴力破解做好准备。

首先,为了能让工业机器相对“智能”,就需要一个可以控制这些机器的设备来控制它,而这个设备应该具备通用性和可复用性,这就是PLC类设备。一个通用的,可重复改写的逻辑控制设备。人们可以通过编写一些程序下载到PLC中,然后PLC通过读取这些程序以达到“智能”控制的效果。

好了,大家都知道PLC的基本功能后,那么就会有一个永恒的问题,一般有用的东西就会涉及到安全问题,既然你能通过编写程序让PLC控制设备,那么就会有别有用心的人也想控制它,所以,这里就涉及到PLC的保护机制。PLC的保护机制和我们常用的手段一样,就是通过设置密码进行保护。

了解完这些基本知识之后,让我们来看一下PLC是怎么进行密码设置的,设置后是怎么保护PLC的。还是和以前一样,我们通过工控实验箱来演示,实验箱实物图如下:

图片[1]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科

图片[2]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科

注:实验箱中各设备的功能与连线这里就不多介绍了,不知道的同学可以看上篇文章。

连接PLC

实验箱通电后,用一根网线将电脑与实验箱进行互联,然后就可以使用“STEP 7-MicroWIN SMART”配置PLC,以及编程软件下载,编写程序等操作。(不同厂家和不同型号的PLC需要不同的控制软件,我们的PLC型号是SMART200)

图片[3]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科

点击“PLC”—“查找CPU”,扫描到一台PLC设备(为什么是扫描的是CPU而不是扫描PLC呢?请自行百度)

图片[4]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科

通过扫描识别到PLC后,点击“确定”该软件就与plc成功连接,当前界面就是PLC编程界面。

密码配置

图片[5]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科

双击“CPU ST20”打开“系统块”设置页面,在“安全”标签中密码设置选项中就可以设置密码了,密码保护一共分为4个级别,S7‑200 SMART CPU 的默认密码级别是“完全权限”(1 级),:

  1. 完全权限(1 级):提供无限制访问CPU所有功能。
  2. 读取权限(2级):用户可以不受限制地读取和写入CPU数据和上传程序。下载程序、强制存储器位置或对存储卡进行编程时需要密码。
  3. 最低权限(3级):用户可以不受限制地读取和写入CPU数据和上传程序。上传或下载程序、强制存储器位置或对存储卡进行编程时需要密码。
  4. 不允许上传(4 级):该级别的密码保护将阻止程序上传(即使输入正确的密码)。该选项不允许项目比较。其它CPU功能的保护方式与最低权限密码相同。

知道了PLC密码保护的相关知识后,我们随便找一个密码级别(这里我们使用只读),设置好密码后下载程序到PLC中,然后再次通过下载程序就需要输入密码(上面密码保护级别里说过,只读级别下载时需要输入密码),结果如下图所示:

图片[6]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科

PLC密码保护检测

废话不多说,直接上图:

图片[7]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科图片[8]-工控渗透框架ISF:PLC密码检测 – 作者:andiSEC-安全小百科

是不是很简单,如果还想验证其它密码保护级别,可以通过上面的上步骤重新修改PLC的密码保护级别,然后再通过ISF中的s7_200_password_check模块进行验证。说到这个模块仔细的同学应该已经发现,上一篇文章里提到的从github中clone的ISF项目里没有s7_200_password_check模块啊,你这个模块是哪里来的?

ISF模块添加

如上面细心网友发现的那样,github中的ISF项目确实没有今天要讲的这个模块,这也就是我们为什么要开发这个框架的原因,它是一套攻击框架,大家可以根据自己对PLC的研究成果,添加不同的功能模块,最后将所有的攻击模块都集成到这个框架中,我们就可以拥有一个强大的工控攻击工具。

接下来我们就通过上面的案例讲解一下,如何给ISF添加一个PLC密码检测模块,Iet’s go!

首先,你需要在ISF的module目录(例:/home/one/soft/isf/module/exploits/Siemens)下创建两个文件,名字任意(例:s7_200_password_check.py,s7_200_password_check.xml)

xml文件

<?xml version="1.0"?>

    <t:config id="7f1a1992802517842c14ddfd1a2e3a6b"
          name="s7_200_password_check"
          version="1.1.0"
          configversion="1.1.0.0"
          author="one"
          xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
          xmlns:t='tc0'>
    <t:inputparameters>
<t:parameter name="TargetIp" description="The Target ip address " type="IPv4"/> <t:parameter name="TargetPort" description="The Target Port" type="U16" default="102"/> </t:inputparameters> </t:config>

代码解释:

id:可以是这个模块名称的md5值,也可以复制我当前这个值,然后随变改几个字符即可

name:这里的name就是ISF框架use时的模块名称,也是py文件的名称

TargetIp和TargetPort:是你这个模块需要的参数

py文件

xml文件是用来配置py文件的参数,以及关联ISF框架的,而真正完成扫描或攻击功能的模块是在py里面编写的,下面我们来看s7_200_password_check.py模块是如何编写的。

#encoding:utf-8
import socket
import time
from core.exploit import *

class Check_passwd(BaseExploit):
    register_info = {
        'ID': 'ICF-2020-F0010009',
        'Name': 's7-200检查',
        'Author': 'one',
        'License': ISF_LICENSE,
        'Create_Date': '2020-06-04',
        'Description': '''可以显示密码状态''',
    }
    register_options = [
        mkopt_rport(102)
    ]       

    def exploit(self,*args,**kwargs):
        self.ip = self.TargetIp
        self.default_port = int(self.TargetPort)
        if self.default_port != 102:
            return False
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((self.ip, self.default_port))
            pp = "0300001611e00000000100c0010ac1020100c2020101".decode("hex")
            sock.send(str(pp))
            data = sock.recv(1024)

            pp = "0300001902f08032010000662100080000f0000001000101e0".decode("hex")
            sock.send(str(pp))
            data = sock.recv(1024)
            time.sleep(0.1)
            pp = "0300001f02f080320100000004000e00000401120a100200020000030005d0".decode("hex")
            sock.send(str(pp))
            data = sock.recv(1024)
            data2 = data.encode("hex")
            str_tmp = data2[-1:]
            print data2
            if str_tmp == '1':
                print "完全读取!"
                return True
            elif str_tmp == '2':
                print("只读!")
                return False
            elif str_tmp == '3':
                print('最低权限!')
                return False
            elif str_tmp == '4':
                print("不允许上传!")
                return False
            else:
                print("异常状态!")
                return False
        except Exception as e:
            print e,"执行错误"
            return False
MainEntry(Check_passwd, __name__)

代码解释:

import:三个导入自然不用说了

Check_passwd:构建模块时,一定要使用类,而不是函数,其次一定要继承BaseExploit

exploit:这个方法就是在ISF中配置完各种参数后,用于执行扫描或攻击的方法

pp:这里发送的数据大家先不用关心,后续文章会慢慢教大家怎么解析PLC协议

str_tmp:用sock发送完3组数据,并接收返回值后,取出最后一位进行判断,看到这里大家应该就能明白上面4种密码保护级别的1234是什么意思了吧

MainEntry:是将ISF框架接收到的参数发送给当前类,然后将检测结果显示出来

总结

好了今天的内容就讲到这里,是不是很简单,有没有想继续学下去的冲动,那就关注我们,一步一步用实例为你打开另一扇门。

来源:freebuf.com 2020-07-26 16:40:37 by: andiSEC

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论