Amazon Echo Dot Explorations (Part 1)

David Weinstein
Nov 7, 2016 · 11 min read

I received an Amazon Echo dot as a birthday gift a couple of weeks ago and this weekend was a great chance to start tinkering with it.

While I definitely have an interest in the Internet of Things (IoT) world, I spend most of my time in mobile security as Director of Research at NowSecure. So, as a security researcher I couldn’t help but feel skeptical about the security implications of having an always-listening device in my small apartment. I already have a few of those in the form of cell phones, so I figured what the heck… why not give this Echo Dot a try?

Echo Dot Setup

My first step was to search on Google about Echo’s setup process. If you turn on the device prematurely, the Alexa voice will tell you to continue setup via “your Alexa app.”

I ended up finding the Amazon support page, which explains that you can setup Alexa-enabled devices using the following options:

  • Appstore
  • Google Play
  • Amazon Appstore
  • Web browser

Alternately, you can go to https://alexa.amazon.com from Safari, Chrome, Firefox, Microsoft Edge, or Internet Explorer (10 or higher) on your Wi-Fi enabled computer.

The browser option seemed the most interesting at the time as my immediate question was: How is Amazon going to setup my device from my browser within the browser’s sandbox? It sounded interesting and likely susceptible to mistakes. I also wanted to compare my Echo user experience to my experiences using a Google Chromecast and Internet-enabled Sony television. :-)

Therefore, I decided to live on the wild side and try this https://alexa.amazon.com approach first. What follows is an exploration of the browser-based setup process with eye towards security vulnerabilities. I hope to address the mobile app registration approach in a future post.

Login

Initially, the setup page was served up over HTTPS, which serves to protect the username and password from being sent in the clear:

Start out on (secure) HTTPS page

The login page certificate info:

Valid certificate for signing into my Alexa account at Amazon

However, right after hitting the login button I was redirected to a page served back on alexa.amazon.com and suddenly everything had been downgraded to plain-old (insecure) HTTP:

Here I get redirected back to alexa.amazon.com over (unsecure) HTTP
No longer connected over HTTPS

From here an attacker in a MITM position could try and keep the user operating in the clear, or steal any session cookies as sent in the requests from the browser to alexa.amazon.com. This seemed particularly strange as most of the other Amazon services I’ve interacted with do use TLS to protect sensitive communications.

OAuth Sign-in

I started recording the login process in my browser via the developer tools to better understand what Amazon is doing with its users’ login info. Please note that I’ve masked out various tokens and identifiers in the following examples. I noticed that Alexa leverages an OpenID provider at Amazon via pitangui:

GET /ap/signin?showRmrMe=1&openid.return_to=https%3A%2F%2Fpitangui.amazon.com&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=amzn_dp_project_dee&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0& HTTP/1.1
Host: www.amazon.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://alexa.amazon.com/spa/index.html
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8
Cookie: x-wl-uid=1vKj5xxxxxxxxxxxdxxxxxxxxxxxxxxxxx0=; s_vnum=xxxxxxxxx%26vn%3D1; s_ppv=61; csrf=618530715; session-id-time=XXXXXX; s_dslv=1478470805464; s_dslv_s=First%20Visit; s_c27=201994280; s_cc=true; s_fid=xxxxxxx-xxxxx; s_nr=1478471564887-New; s_invisit=true; s_sq=%5B%5BB%5D%5D; appstore-devportal-locale=en_US; session-id=153-xxxxx-xxxxx; csm-hit=xxxxx+s-xx|xxxxxxxxxx; ubid-main=163-xxxxx-2xxxxxxx311

First we’re redirected to pitangui.amazon.com:

HTTP/1.1 302 Found
Server: Server
Date: Sun, 06 Nov 2016 22:39:37 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 0
Connection: keep-alive
Strict-Transport-Security: max-age=47474747; includeSubDomains; preload
x-ua-compatible: IE=edge
Pragma: No-cache
Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Location: https://pitangui.amazon.com?openid.assoc_handle=amzn_dp_project_dee&aToken

X-Frame-Options: SAMEORIGIN
Set-Cookie: ap-fid=””; Domain=.amazon.com; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ap/; Secure
Set-Cookie: ubid-main=162–0697489–2101231; Domain=.amazon.com; Expires=Sat, 01-Nov-2036 22:39:37 GMT; Path=/
Set-Cookie: session-token=”xx/y//zz=”; Version=1; Domain=.amazon.com; Max-Age=630720000; Expires=Sat, 01-Nov-2036 22:39:37 GMT; Path=/
Set-Cookie: x-main=XXXXXXXXXXX; Domain=.amazon.com; Expires=Sat, 01-Nov-2036 22:39:37 GMT; Path=/
Set-Cookie: at-main=Atza|xxxxxxxxxxx; Domain=.amazon.com; Expires=Sat, 01-Nov-2036 22:39:37 GMT; Path=/; Secure; HttpOnly
Set-Cookie: sess-at-main=”yyyy/xxxxxxxxxxxxxxxx/M=”; Version=1; Domain=.amazon.com; Path=/; Secure; HttpOnly
Vary: Accept-Encoding,User-Agent
p3p: policyref=”http://www.amazon.com/w3c/p3p.xml",CP="CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC “

After the redirect, the browser posts the username/password info via a form body:

POST /ap/signin?ie=UTF8&pf_rd_r=yyyyyyy&pf_rd_m=xxxxxx&pf_rd_t=6301&pf_rd_i=amzn_dp_project_dee&pf_rd_p=xxxxx&pf_rd_s=signin-slot HTTP/1.1
Host: www.amazon.com
Connection: keep-alive
Content-Length: 1349
Pragma: no-cache
Cache-Control: no-cache
Origin: https://www.amazon.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: https://www.amazon.com/ap/signin?showRmrMe=1&openid.return_to=https%3A%2F%2Fpitangui.amazon.com&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=amzn_dp_project_dee&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8

Session cookies

Looking at the full HAR response, it includes a questionable Set-Cookie:

 “name”: “Set-Cookie”,
“value”: “session-token=\”xx/y//zz==\”; Version=1; Domain=.amazon.com; Max-Age=630720000; Expires=Sat, 01-Nov-2036 22:39:37 GMT; Path=/”

There are two notable things going on here. First, some cookies are not marked secure or http-only. Secondly, some cookies are valid for a really, really long time (01-Nov-2036?!), which was bizarre considering Amazon had requested I login twice within a short timeframe.

At the very least, and in accordance with best practices, Amazon should have set all cookies to be marked http-only and secure.

Without further investigation, I hope that this session token is useless on its own, or that one of the other cookies that was set with http-only and secure is needed to actually do something heinous with my account. But that’s for a later post perhaps where I will try and explore what can be done with the tokens that aren’t being properly protected.

Of course I wonder if the cookie would be set in the mobile apps incorrectly like this…

Re-auth

After picking the type of device in the SPA, I was asked to login once again over TLS protected endpoint, and once again redirected to the HTTP (not HTTPS) Alexa page to continue setup. Huh? I just auth’d 2 seconds ago… strange UX.

Setup process

From here, Amazon provides instructions on how to setup the Echo Dot: plug it in to a power source etc. They explain that the device will setup its own wireless network that will have the format Amazon-XXX. So my question was: How is this page going to connect to the Echo once I’ve joined that network?

A little investigation in my browser’s javascript console and I see some errors:

Failed XHR attempts to connect to the echo

Perhaps they’re using an HTTP request or a WebSocket?

Bingo:

Some failed XHR requests

These look like attempts to connect to device via XHR from the SPA. Saving these as curl requests for later…

curl ‘http://10.201.126.241:8080/OOBE' -H ‘Accept: text/plain, */*; q=0.01’ -H ‘Referer: http://alexa.amazon.com/spa/index.html' -H ‘Origin: http://alexa.amazon.com' -H ‘User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36’ -H ‘Content-Type: application/x-www-form-urlencoded; charset=UTF-8’ — data ‘[1,”ping”,1,0,{}]’ — compressed

It seems second attempt was made at another LAN address. Perhaps for supporting two different types of products or if I had selected the wrong device on the first setup screen?

curl ‘http://192.168.11.1:8080/OOBE' -H ‘Accept: text/plain, */*; q=0.01’ -H ‘Referer: http://alexa.amazon.com/spa/index.html' -H ‘Origin: http://alexa.amazon.com' -H ‘User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36’ -H ‘Content-Type: application/x-www-form-urlencoded; charset=UTF-8’ — data ‘[1,”ping”,1,0,{}]’ — compressed

So OOBE most likely stands for out of box experience.

Turning the Echo On

Up until now I had only been exploring the webpage. Now it was time to actually plug the device in so I could see the interaction that happens between the browser and the device.

Once turned on, the Echo starts up a local access point lacking network protection. This is similar to how the Chromecast worked, and is pretty standard for other gadgets such as wifi-enabled drones.

Wifi

It looks like the device sets up a predictable SSID (over 802.11n) and the device I’ve got is using the 10.201.126.x subnet. I suspect the other range could be for the older Echo devices?

Continuing our setup exploration

Like any pen-tester might, I wanted to explore what ports and for those open ports, what network services the Echo Dot was exposing during the setup process. Also I can use this to compare after I finish setting things up what is exposed to the local network.

± nmap -A -T4 -v -v -v 10.201.126.241

PORT STATE SERVICE REASON VERSION
443/tcp open tcpwrapped syn-ack
8080/tcp open http-proxy syn-ack
| http-methods:
|_ Supported Methods: POST OPTIONS

So obviously ports 443 and 8080 are potentially being used on the Dot during initialization. Perhaps later there might be additional ports available for new services, or maybe everything will be performed via the RPC interface.

RPC

I confirmed that my browser was using the RPC service exposed by connecting my computer to the Echo Dot’s wireless network where I could see the request and response flow.

Here we can see one of the XHR requests to “ping” the Echo Dot to see if it’s available. The browser continuously pings until a device responds, which then allows the setup process in the browser to continue.

ping-pong

So now we can try out the XHR request to see how the device responds:

POST /OOBE HTTP/1.1
Host: 10.201.126.241:8080
Accept-Encoding: deflate, gzip
Accept: text/plain, */*; q=0.01
Referer: http://alexa.amazon.com/spa/index.html
Origin: http://alexa.amazon.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 17
HTTP/1.1 200 OK
Content-Length: 29
Content-Type: text/plain
Connection: close
Allow: POST, OPTIONS
Access-Control-Allow-Origin: http://alexa.amazon.com
[1,”ping”,2,0,{“0”:{“tf”:1}}]%

So we’ve learned that the echo will respond to the RPC in a JSON-RPC format. This JSON-RPC format turns out to be Thrift.

Other requests

What happens if we swap out the ping string in the request?

POST /OOBE HTTP/1.1
Host: 10.201.126.241:8080
Accept-Encoding: deflate, gzip
Accept: text/plain, */*; q=0.01
Referer: http://alexa.amazon.com/spa/index.html
Origin: http://alexa.amazon.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 18
HTTP/1.1 200 OK
Content-Length: 74
Content-Type: text/plain
Connection: close
Allow: POST, OPTIONS
Access-Control-Allow-Origin: http://alexa.amazon.com
[1,”login”,3,0,{“1”:{“str”:”Invalid method name: ‘login’”},”2":{“i32”:1}}]

Obviously I could probably try and guess some other commands, but instead I decided to track the commands being used specifically during the registration process.

Connection success

Now I can continue the setup. So that I can watch all the requests being made over XHR to the Echo, I set an XHR breakpoint for any URLs with the string :8080 present.

The browser then periodically pings by making requests that would normally route once back online:

In order to track whether the browser is on the Dot’s network or back online, it pings out periodically

Next breakpoint learns us a new RPC api method called getDeviceDetails:

The getDeviceDetails RPC command requested via XHR

Let’s call it before the browser does, just in case it changes somehow:


$ curl -v -i ‘http://10.201.126.241:8080/OOBE' -H ‘Accept: text/plain, */*; q=0.01’ -H ‘Referer: http://alexa.amazon.com/spa/index.html' -H ‘Origin: http://alexa.amazon.com' -H ‘User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36’ -H ‘Content-Type: application/x-www-form-urlencoded; charset=UTF-8’ — data ‘[1,”getDeviceDetails”,1,0,{}]’ — compressed
* Trying 10.201.126.241…
* Connected to 10.201.126.241 (10.201.126.241) port 8080 (#0)
> POST /OOBE HTTP/1.1
> Host: 10.201.126.241:8080
> Accept-Encoding: deflate, gzip
> Accept: text/plain, */*; q=0.01
> Referer: http://alexa.amazon.com/spa/index.html
> Origin: http://alexa.amazon.com
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.35 Safari/537.36
> Content-Type: application/x-www-form-urlencoded; charset=UTF-8
> Content-Length: 29
>
* upload completely sent off: 29 out of 29 bytes
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Length: 1889
Content-Length: 1889
< Content-Type: text/plain
Content-Type: text/plain
< Connection: close
Connection: close
< Allow: POST, OPTIONS
Allow: POST, OPTIONS
< Access-Control-Allow-Origin: http://alexa.amazon.com
Access-Control-Allow-Origin: http://alexa.amazon.com
<
* Closing connection 0
[1,”getDeviceDetails”,2,0,{“0”:{“rec”:{“1”:{“str”:”\”Device X.X.X(558xxxxxx)\””},”2":{“str”:”AC63Bxxxxxxx”},”3":{“rec”:{“1”:{“str”:””},”2":{“i32”:0},”3":{“tf”:1},”4":{“i32”:0},”5":{“tf”:1},”6":{“i32”:1},”7":{“tf”:0}}},”4":{“str”:”0.0.0.0"},”5":{“rec”:{“1”:{“str”:” — — -BEGIN CERTIFICATE — — -\nMIIDczCCAlugxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=\n — — -END CERTIFICATE — — -\n”}}},”6":{“str”:”G090LF09xxxxxxx”},”7":{“tf”:1},”8":{“lst”:[“str”,3,”en-US”,”en-GB”,”de-DE”]},”9":{“lst”:[“str”,7,”WW”,”US”,”JP”,”DE”,”GB”,”IN”,””]},”10":{“lst”:[“str”,9,”en-US/ALEXA”,”en-US/AMAZON”,”en-US/ECHO”,”en-GB/ALEXA”,”en-GB/AMAZON”,”en-GB/ECHO”,”de-DE/ALEXA”,”de-DE/AMAZON”,”de-DE/ECHO”]},”11":{“str”:”A3S5BH2HU6VAYF”},”12":{“i32”:2}}}}]%

This is cool… This looks like it’s probably the public certificate for the device… something Amazon can use to verify data sent by the device, or to encrypt data that only the device should be able to decrypt with its private key.

Extracting the certificate and running it through openssl CLI:

$ openssl x509 -in getDeviceDetails-response-x509.txt -text 
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
xx:xx:xx:xx:xx:xx:xx:xx
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=CA, L=Cupertino, O=Lab126, CN=setup
Validity
Not Before: Oct 10 21:42:18 2016 GMT
Not After : Oct 11 21:42:18 2142 GMT
Subject: C=US, ST=CA, L=Cupertino, O=Lab126, CN=setup
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (2048 bit)
Modulus (2048 bit):
00:ec:a2:c7:1e:0d:24:fb:da:05:67:41:a6:f3:26:
0f:eb:22:f6:ef:aa:47:20:98:5e:b5:ab:77:9a:ab:

6b:3f:98:30:d1:eb:45:96:85:47:52:87:74:72:84:
ef:9f:7b:b7:ac:50:5d:96:62:c7:bb:56:70:64:a9:
88:aa:d1:7b:d6:70:f3:a7:9d:7b:d8:96:ac:5c:0f:
46:44:dd:77:d6:65:29:5f:cc:8d:9a:d9:15:be:27:
69:93:1d:77:8c:34:2f:82:30:be:ba:e4:d2:81:be:
58:c5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
73:XX:XX:XX:XX:5D:16:3C:4E:77:ED:XX:XX:XX:XX:XX:XX:XX:26:52
X509v3 Authority Key Identifier:
keyid:XX:XX:XX:F5:XX:5D:16:XX:XX:77:XX:XX:XX:E4:XX:22:XX:XX:26:XX
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
3e:54:1b:ba:37:21:6b:4d:da:0b:0b:19:3b:05:25:f0:d1:de:

ef:59:07:6d:67:da:f9:23:78:f5:a7:3d:14:4f:d4:c4:5b:4c:

c3:a3:c4:0e:82:d8:c1:77:fe:d6:f7:e5:3e:64:a9:d9:f6:a5:
8e:82:45:eb:2b:5a:0d:74:a1:6a:15:2a:b4:e3:ec:dc:17:8b:
….
32:0f:4d:0b

Definitely some good info to glean from this. It looks like a certificate minted by Lab126. In case you didn’t know, Lab126 is the company behind other Amazon hardware like the Kindle, Fire tablets, and well, duh, the Amazon Echo.

Since this is part of the setup process, I wonder what would happen if I sent Amazon a different public key during registration, one that I created instead of the one from the device for which I would otherwise not have the corresponding private key. Then in theory any messages encrypted for my device could be decoded before I send them over during a MITM attack. Lastly, since this entire session has basically been happening in plaintext, both on and off the Echo Dot’s Wifi network, I suspect the identifying info in this request can be captured upstream.

Conclusion

In this post we learned a little about the browser-based Amazon Echo setup process, how the browser connects to the Echo Dot, and a little info about what might be transmitted back to Amazon.

There’s definitely some big questions about why this setup process happens in the clear after logging in via Amazon’s OAuth over TLS. It would be good to see if I can actually create the MITM scenario as this could be very useful for continuing to study the communication between Amazon’s backend and the device always listening in my apartment.

Thanks for reading…