According to a Gartner report from December 2012, “85 percent of all flat-panel TVs will be Internet-connected Smart TVs by 2016.” Forbes magazine gives some analysis about what is fueling this trend: http://www.forbes.com/sites/michaelwolf/2013/02/25/3-reasons-87-million-smart-tvs-will-be-sold-in-2013/ , The article makes a mention of “DIAL”, an enabling technology for second-screen features (which this post is about). With these new devices come new risks as evidenced in the following article: https://securityledger.com/2012/12/security-hole-in-samsung-smart-tvs-could-allow-remote-spying/ , as well as more recent research about Smart TV risks presented at the CanSecWest and DefCon security conference this year (2013).
For more details about about exactly what features a Smart TV has above and beyond a normal television, consult this WikiPedia article: http://en.wikipedia.org/wiki/Smart_TV.
This post introduces and describes aspects of “DIAL”, a protocol developed by Google and Netflix for controlling Smart TVs with smart phones and tablets. DIAL provides “second screen” features, which allow users to watch videos and other content on a TV using a smart phone or tablet. This article will review sample code for network discovery and enumerate Smart TV apps using this protocol.
Part 1: Discovery and Enumeration
Smart TVs are similar to other modern devices in that they have apps. Smart TVs normally ship with an app for YouTube(tm), Netflix(tm), as well as many other built-in apps. If you have a smartphone, then maybe you’ve noticed that when your smartphone and TV are on the same network, a small square icon appears in some mobile apps, allowing you to play videos on the big TV. This allows you to control the TV apps from your smartphone. Using this setup, the TV is a “first screen” device, and the phone or tablet functions as a “second screen”, controlling the first screen.
DIAL is the network protocol used for these features and is a standard developed jointly between Google and Netflix. (See http://www.dial-multiscreen.org/ ). DIAL stands for “Discovery and Launch”. This sounds vaguely similar to other network protocols, namely “RPC” (remote procedure call). Basically, DIAL gives devices a way to quickly locate specified networked devices (TVs) and controlling programs (apps) on those devices.
Let’s take a look at the YouTube mobile application to see how exactly this magic happens. Launching the YouTube mobile app with a Smart TV on network (turned on of course) shows the magic square indicating a DIAL-enabled screen is available:
Clicking the square provides a selection menu where the user may choose which screen to play YouTube videos. Recent versions of the YouTube apps allow “one touch pairing” which makes all of the setup easy for the user:
Let’s examine the traffic generated by the YouTube mobile app at launch.
- The Youtube mobile app send an initial SSDP request, to discover available first-screen devices on the network.
- The sent packet is destined for a multicast address (188.8.131.52) on UDP port 1900. Multicast is useful because devices on the local subnet can listen for it, even though it is not specifically sent to them.
- The YouTube app multicast packet contains the string “urn:dial-multiscreen-org:service:dial:1”. A Smart TV will respond to this request, telling YouTube mobile app its network address and information about how to access it.
A broadcast search request from the YouTube mobile app looks like this:
11:22:33.361831 IP my_phone.41742 > 184.108.40.206.1900: UDP, length 125 0x0010: .......l..+;M-SE 0x0020: ARCH.*.HTTP/1.1. 0x0030: .HOST:.239.255.2 0x0040: 55.250:1900..MAN 0x0050: :."ssdp:discover 0x0060: "..MX:.1..ST:.ur 0x0070: n:dial-multiscre 0x0080: en-org:service:d 0x0090: ial:1....
Of course, the YouTube app isn’t the only program that can discover ready-to-use Smart TVs. The following is a DIAL discoverer in a few lines of python. It waits 5 seconds for responses from listening TVs. (Note: the request sent in this script is minimal. The DIAL protocol specification has a full request packet example.)
! /usr/bin/env python import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(5.0) s.sendto("ST: urn:dial-multiscreen-org:service:dial:1",("220.127.116.11",1900)) while 1: try: data,addr = s.recvfrom(1024) print "[*] response from %s:%d" % addr print data except socket.timeout: break
A response from a listening Smart TV on the network looks like:
[*] response from 192.168.1.222:1900 HTTP/1.1 200 OK LOCATION: http://192.168.1.222:44047/dd.xml CACHE-CONTROL: max-age=1800 EXT: BOOTID.UPNP.ORG: 1 SERVER: Linux/2.6 UPnP/1.0 quick_ssdp/1.0 ST: urn:dial-multiscreen-org:service:dial:1 USN: uuid:bcb36992-2281-12e4-8000-006b9e40ad7d::urn:dial-multiscreen-org:service:dial:1
Notice that the TV returns a LOCATION header, with a URL: http://192.168.1.222:44047/dd.xml . The response from reading that URL leads to yet another URL which provides the “apps” link on the TV.
HTTP/1.1 200 OK Content-Type: application/xml Application-URL: http://192.168.1.222:60151/apps/ <?xml version="1.0"?><root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:r="urn:restful-tv-org:schemas:upnp-dd”> <specVersion> <major>1</major> <minor>0</minor> </specVersion> <device> <deviceType>urn:schemas-upnp-org:device:tvdevice:1</deviceType> <friendlyName>Vizio DTV</friendlyName> <manufacturer>Vizio Inc.</manufacturer> <modelName>Vizio_E420i_A0</modelName> <UDN>uuid:bcb36992-2281-12e4-8000-006b9e40ad7d M-SEARCH * HTTP/1.1 HOST: 18.104.22.168:1900 MAN: "ssdp:discover" MX: 3 ST: urn:schemas-upnp-org:device:MediaServer:1
At this point, the YouTube mobile app will try to access the “apps” URL combined with the application name with a GET request to: http:://192.168.1.222:60151/apps/YouTube . A positive response indicates the application is available, and returns an XML document detailing some data about the application state and feature support:
HTTP/1.1 200 OK Content-Type: application/xml <?xml version="1.0" encoding="UTF-8"?> <service xmlns="urn:dial-multiscreen-org:schemas:dial"> <name>YouTube</name> <options allowStop="false"/> <state>stopped</state> </service>
Those of you who have been following along may have noticed how easy this has been. So far, we have sent one UDP packet and issued two GET requests. This has netted us:
- The IP address of a Smart TV
- The Operating system of a Smart TV (Linux 2.6)
- Two listening web services on random high ports.
- A RESTful control interface to the TV’s YouTube application.
If only all networked applications/attack surfaces could be discovered this easily. What should we do next? Let’s make a scanner. After getting the current list of all registered application names (as of Sept 18, 2013) from the DIAL website, it is straightforward to create a quick and dirty scanner to find the apps on a Smart TV:
#! /usr/bin/env python # # Enumerate apps on a SmartTV # <email@example.com> # import urllib2 import sys apps=['YouTube','Netflix','iPlayer','News','Sport','Flingo','samba', 'tv.samba','launchpad','Pandora','Radio','Hulu','KontrolTV','tv.primeguide', 'primeguide','Tester','Olympus','com.dailymotion','Dailymotion','SnagFilms', 'Twonky TV','Turner-TNT-Leverage','Turner-TBS-BBT','Turner-NBA-GameTime', 'Turner-TNT-FallingSkies','WiDi','cloudmedia','freeott','popcornhour', 'Turner-TBS-TeamCoco','RedboxInstant','YuppTV.Remote','D-Smart','D-SmartBLU', 'Turner-CNN-TVE','Turner-HLN-TVE','Turner-CN-TVE','Turner-AS-TVE', 'Turner-TBS-TVE','Turner-TNT-TVE','Turner-TRU-TVE','Gladiator','com.lge', 'lge','JustMirroring','ConnectedRedButton','sling.player.googletv','Famium', 'tv.boxee.cloudee','freesat','freetime','com.humax','humax','HKTV', 'YahooScreen','reachplus','reachplus.alerts','com.reachplus.alerts', 'com.rockettools.pludly','Grooveshark','mosisApp','com.nuaxis.lifely', 'lifely','GuestEvolutionApp','ezktv','com.milesplit.tv','com.lookagiraffe.pong', 'Crunchyroll','Vimeo','vGet','ObsidianX','com.crossproduct.caster', 'com.crossproduct.ether','Aereo','testapp3e','com.karenberry.tv', 'cloudtv','Epictv','QuicTv','HyperTV','porn','pornz','Plex','Game', 'org.enlearn.Copilot','frequency', 'PlayMovies' ] try: url = sys.argv except: print "Usage: %s tv_apps_url" % sys.argv sys.exit(1) for app in apps: try: u = urllib2.urlopen("%s/%s"%(url,app)) print "%s:%s" % ( app, repr(str(u.headers)+u.read()) ) except: pass
Some of those app names appear pretty interesting. (Note to self: Find all corresponding apps.) The scanner looks for URLs returning positive responses (200 result codes and some XML), and prints them out:
$ ./tvenum.py http://192.168.1.222:60151/apps/ YouTube:'Content-Type: application/xml\r\n<?xml version="1.0" encoding="UTF-8"?>\r\n<service xmlns="urn:dial-multiscreen-org:schemas:dial">\r\n <name>YouTube</name>\r\n <options allowStop="false"/>\r\n <state>stopped</state>\r\n</service>\r\n' Netflix:'Content-Type: application/xml\r\n<?xml version="1.0" encoding="UTF-8"?>\r\n<service xmlns="urn:dial-multiscreen-org:schemas:dial">\r\n <name>Netflix</name>\r\n <options allowStop="false"/>\r\n <state>stopped</state>\r\n</service>\r\n'
Hopefully this article has been informative for those who may be looking for new devices and attack surfaces to investigate during application or penetration testing.