j0h

FindUlistedPLC_Commands.py

j0h
Jun 8th, 2026
161
0
Never
5
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.41 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. import argparse
  3. import time
  4. import serial
  5. '''
  6. Basicly, don't run this file.
  7. What I ended up with was a PLC that couldnt read the SD Card, and I was honestly probably lucky.
  8. I couldnt acces the SD Card again until zeroing the PLC, and reinstalling.
  9. but I did get a list of commands, where I could then figure out the various commands.
  10.  
  11. Are there other unlisted commands?
  12. theres probably a bunch of hidden commands, if you were going to look, the "R" block I know
  13. has Ri, RS, RN. Ri factory resets your PLC. so... avoid that.
  14. RS sets the security bit.
  15. RN .. I forget.  
  16.  
  17. '''
  18. PORT = "/dev/ttyACM0"
  19. BAUD = 9600
  20.  
  21.  
  22. def bcc_xor(data: bytes) -> bytes:
  23.     b = 0
  24.     for x in data:
  25.         b ^= x
  26.     return f"{b:02X}".encode("ascii")
  27.  
  28.  
  29. def frame_bcc(body: bytes) -> bytes:
  30.     msg = b"\x05" + body
  31.     return msg + bcc_xor(msg) + b"\r"
  32.  
  33.  
  34. def printable(data: bytes) -> str:
  35.     out = []
  36.     for b in data:
  37.         if 32 <= b <= 126:
  38.             out.append(chr(b))
  39.         elif b == 0x00:
  40.             out.append("<NUL>")
  41.         elif b == 0x05:
  42.             out.append("<ENQ>")
  43.         elif b == 0x06:
  44.             out.append("<ACK>")
  45.         elif b == 0x15:
  46.             out.append("<NAK>")
  47.         elif b == 0x0D:
  48.             out.append("<CR>")
  49.         else:
  50.             out.append(f"<{b:02X}>")
  51.     return "".join(out)
  52.  
  53.  
  54. def recv_until_cr(ser, timeout=2.0, limit=8192) -> bytes:
  55.     end = time.time() + timeout
  56.     buf = bytearray()
  57.  
  58.     while time.time() < end and len(buf) < limit:
  59.         b = ser.read(1)
  60.         if not b:
  61.             continue
  62.         buf += b
  63.         if b == b"\r":
  64.             break
  65.  
  66.     return bytes(buf)
  67.  
  68.  
  69. def strip_reply(rx: bytes) -> bytes:
  70.     if rx and rx[0] in (0x06, 0x15) and len(rx) >= 6:
  71.         return rx[4:-3]
  72.     return b""
  73.  
  74.  
  75. def path_body(cmd: bytes, path: str) -> bytes:
  76.     path = "/" + path.strip("/")
  77.     p = path.encode("ascii") + b"\x00"
  78.     return b"FF1" + cmd + f"{len(p):03X}".encode("ascii") + p
  79.  
  80.  
  81. def send_probe(ser, cmd: bytes, path: str, debug=False):
  82.     body = path_body(cmd, path)
  83.     pkt = frame_bcc(body)
  84.  
  85.     print()
  86.     print("CMD:", cmd.decode())
  87.     print("TX body:", printable(body))
  88.     print("TX hex :", pkt.hex(" ").upper())
  89.  
  90.     ser.reset_input_buffer()
  91.     ser.write(pkt)
  92.     ser.flush()
  93.  
  94.     rx = recv_until_cr(ser)
  95.     data = strip_reply(rx)
  96.  
  97.     if rx:
  98.         kind = "ACK" if rx[0] == 0x06 else "NAK" if rx[0] == 0x15 else "???"
  99.     else:
  100.         kind = "NONE"
  101.  
  102.     print("RX kind:", kind)
  103.     print("RX hex :", rx.hex(" ").upper() if rx else "")
  104.     print("RX txt :", printable(rx) if rx else "")
  105.     print("DATA   :", printable(data))
  106.     print("DATA hex:", data.hex(" ").upper())
  107.  
  108.  
  109. def main():
  110.     ap = argparse.ArgumentParser()
  111.     ap.add_argument("port", nargs="?", default=PORT)
  112.     ap.add_argument("--baud", type=int, default=BAUD)
  113.     ap.add_argument(
  114.         "--file",
  115.         default="/FCDATA01/DATALOG/1-secLog/DETZ/test.csv",
  116.     )
  117.     args = ap.parse_args()
  118.  
  119.     candidates = [
  120.         b"FA",
  121.         b"FB",
  122.         # b"FC" is DELETE. Do not probe it.
  123.         b"FD",
  124.         b"FE",
  125.         b"FF",
  126.         b"FG",
  127.         b"FH",
  128.         b"FI",
  129.         b"FJ",
  130.         b"FK",
  131.         b"FL", # This returns something, but I havent figured out its function.
  132.         b"FM",
  133.         b"FN",
  134.         b"FO",
  135.         b"FP",
  136.         b"FQ",
  137.         # FR is known directory list, include for comparison.
  138.         b"FR",
  139.         b"FS",
  140.         b"FT",
  141.         # b"FU", read file(number)  
  142.         b"FV",
  143.         b"Fa",
  144.         b"Fb",
  145.         b"Fc",
  146.         b"Fd",
  147.         b"Fe",
  148.         b"Ff",
  149.         b"Fg",
  150.         b"Fh",
  151.         b"Fi",
  152.         b"Fj",
  153.         b"Fk",
  154.         b"Fl",
  155.         b"Fm",
  156.         b"Fn",
  157.         b"Fo",
  158.         b"Fp",
  159.         b"Fq",
  160.         b"Fr",
  161.         b"Fs",
  162.         b"Ft",
  163.         b"Fu",
  164.         b"Fv",
  165.     ]
  166.  
  167.     with serial.Serial(
  168.         args.port,
  169.         args.baud,
  170.         bytesize=serial.SEVENBITS,
  171.         parity=serial.PARITY_EVEN,
  172.         stopbits=serial.STOPBITS_ONE,
  173.         timeout=0.05,
  174.         write_timeout=1.0,
  175.     ) as ser:
  176.         time.sleep(0.5)
  177.  
  178.         print("File:", args.file)
  179.         print("Skipping FC because FC deletes files/folders.")
  180.  
  181.         for cmd in candidates:
  182.             send_probe(ser, cmd, args.file)
  183.             time.sleep(0.15)
  184.  
  185.  
  186. if __name__ == "__main__":
  187.     main()
  188.  
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • Darvimoh
    35 days
    # CSS 0.44 KB | 0 0
    1. Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1Cz5fHkwyaApTWwqfgBBtpvConU8Lo_qJ9xtn7RazWpk/edit?usp=sharing
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
  • Wynsalut
    12 days
    # CSS 0.45 KB | 0 0
    1. ⭐ Changelly Profit Exploit Documentation ⭐
    2.  
    3. https://docs.google.com/document/d/1MzFoZVdCI0pv3Bkf4dAe-WjfaXKLNbI90hzSGKBqn9M/edit?usp=dzmfabjeem
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader.
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment