A vulnerability affects all tested Puwell camera models exposing the proprietary control protocol over TCP port 23456. The protocol does not implement any authentication or authorization mechanism, allowing an unauthenticated attacker to issue privileged commands by sending specially crafted TCP packets directly to the device.
An attacker able to establish network connectivity to the device (for example from the same local network or through the vendor's peer-to-peer connectivity mechanism when enabled) can interact directly with the proprietary TCP service without possessing valid credentials.
The protocol processes privileged commands without validating the client's identity or session state. As a result, an attacker can perform sensitive operations including:
Successful exploitation allows an unauthenticated attacker to access and control all functionality exposed through the proprietary control protocol.
Firmware reverse engineering revealed the protocol structure by analyzing debug strings and packet processing routines. These routines expose the packet layout, opcode dispatch logic, and payload parsing, making it possible to reconstruct valid protocol messages.
The following excerpts illustrate how protocol fields and command handlers were identified:
Figure 1 : Decompiled code showing opcode handling
Figure 2 : Decompiled code showing protocol mode parsing
Figure 3 : GPIO function responsible for pan/tilt motor control
Figure 4 : Decompiled validation routine showing pan and tilt processing
The reconstructed packet format is shown below:
Figure 5 : Binary protocol header
The Session field present in the protocol header is never validated or associated with an authenticated connection. Any arbitrary value is therefore accepted, eliminating the need to negotiate or obtain a legitimate session identifier before issuing privileged commands.
The following Python proof of concept demonstrates that the TCP service exposed on port 23456 accepts and processes protocol messages without requiring authentication or session establishment.
Codeimport socket
import struct
TARGET_IP = "192.168.2.42"
SESSION = 0xbadc0de0
FIELD = 0x02963ED5
OP_HEARTBEAT = 0x0001
def build_packet(opcode, payload):
header = struct.pack("<IIII", 0xFFEEDDCC, opcode, SESSION, len(payload))
return header + payload
payload = struct.pack("<II", 0, FIELD) + b"\x00" * 20
packet = build_packet(OP_HEARTBEAT, payload)
sock = socket.create_connection((TARGET_IP, 23456))
sock.sendall(packet)
response = sock.recv(1024)
print(response.hex())
sock.close()
The transmitted packet follows the proprietary protocol implemented by the device.
Receiving a valid response confirms that the device processes protocol messages without authenticating the client or validating the supplied session identifier. Once communication has been established, additional opcodes can be transmitted to invoke privileged functionality, including pan/tilt control, LED control, audio playback, and device reboot, demonstrating the absence of authentication and authorization within the protocol implementation.