Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- import socket
- import random
- import time
- from ftplib import FTP, error_perm, all_errors
- HMI_IP = "192.168.1.150"
- DISM_PORT = 2537
- FTP_PORT = 2539
- """
- Explore IDEC HMI via FTP.
- Maintenance Protocol initializes the connection with:
- AB/LB/LF commands. the PC says: here is my 16 byte user,
- and 15 byte password.
- Then the HMI enstantiates the connection.
- while the user and pass will time out after 15 minutes,
- there doesn not seem to be an immediate limit on the number of sessions.
- This program lists files and folders, and does some naviations
- """
- START_DIRS = [".", "/", "tmp", "../", "/tmp", "exmem", "/exmem",]
- def rand_hex(n):
- return "".join(random.choice("0123456789abcdef") for _ in range(n))
- def bcc(body: bytes) -> int:
- x = 0x05
- for b in body:
- x ^= b
- return x
- def frame(seq: int, body: bytes) -> bytes:
- body2 = body + f"{bcc(body):02X}".encode("ascii") + b"\r"
- total_len = 19 + len(body2)
- header = bytes([
- 0x01,
- (total_len >> 16) & 0xff,
- (total_len >> 8) & 0xff,
- total_len & 0xff,
- 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- seq & 0xff,
- 0x01, 0x01, 0x01,
- 0x05,
- ])
- return header + body2
- def make_lb_body(username: str, password: str) -> bytes:
- user_field = username.encode("ascii").hex().encode("ascii").upper().ljust(64, b"0")
- doubled_pass = bytes((ord(ch) * 2) & 0xff for ch in password)
- pass_field = doubled_pass.hex().encode("ascii").upper().ljust(128, b"0")
- return b"00FFLB" + bytes([0xC0, 0x00, 0x01]) + user_field + pass_field
- def send_cmd(sock, seq, body, name):
- pkt = frame(seq, body)
- print(f"{name} TX:", pkt.hex(" "))
- sock.sendall(pkt)
- rx = sock.recv(4096)
- print(f"{name} RX:", rx.hex(" "))
- return rx
- def open_hmi_session(username, password):
- with socket.create_connection((HMI_IP, DISM_PORT), timeout=5) as s:
- send_cmd(s, 5, b"00FFAB", "AB")
- send_cmd(s, 6, make_lb_body(username, password), "LB")
- send_cmd(s, 7, b"00FFLF", "LF")
- def connect_ftp(username, password):
- last = None
- for attempt in range(1, 21):
- try:
- print(f"FTP attempt {attempt}/20")
- ftp = FTP()
- ftp.connect(HMI_IP, FTP_PORT, timeout=5)
- print(ftp.getwelcome())
- ftp.login(username, password)
- ftp.voidcmd("TYPE I")
- return ftp
- except all_errors as e:
- print("FTP not ready/login failed:", repr(e))
- last = e
- time.sleep(0.25)
- raise last
- def try_list(ftp, path):
- print("\n" + "=" * 70)
- print("PATH:", path)
- try:
- ftp.cwd(path)
- print("PWD:", ftp.pwd())
- except all_errors as e:
- print("CWD failed:", repr(e))
- return
- print("\nLIST:")
- try:
- lines = []
- ftp.retrlines("LIST", lines.append)
- for line in lines:
- print(" ", line)
- except all_errors as e:
- print("LIST failed:", repr(e))
- print("\nNLST:")
- try:
- names = ftp.nlst()
- for name in names:
- print(" ", name)
- except all_errors as e:
- print("NLST failed:", repr(e))
- def main():
- username = rand_hex(16)
- password = rand_hex(15)
- print("Using temporary FTP creds:")
- print("USER", username)
- print("PASS", password)
- open_hmi_session(username, password)
- ftp = connect_ftp(username, password)
- print("\nInitial PWD:", ftp.pwd())
- for path in START_DIRS:
- try_list(ftp, path)
- ftp.quit()
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment