Aperi'Cast

Aperi'CTF 2019 - Network (150 pts).

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:

insomnia

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!

Creased