Reading Time: 8 minutes

TL;DR Protocols like HTTP Live Streaming and MPEG-DASH are essential for efficient multimedia delivery and a seamless user experience, as they adjust content quality based on bandwidth. Streaming services using these protocols often impose regional content restrictions due to copyright or streaming rights. In this blog post, we explore how to analyze (with Burp) streaming services to detect what geolocation mechanisms exist. We also show a case study involving RTVE, Spain’s largest public media company, showing how improper implementation of regional content blocking allows unauthorized access to its content. Finally, we propose a simple solution for RTVE to prevent this issue.

Context

In the streaming era, protocols such as HTTP Live Streaming (HLS) and MPEG-DASH are essential for streaming multimedia content efficiently. HLS, developed by Apple, uses M3U8 files to list video segments and adjust the quality based on the available bandwidth. Similarly, MPEG-DASH uses MPD files for the same purpose. These protocols enable a seamless user experience through efficient content delivery.

Content delivery is often tied to copyright or broadcasting rights, which result in limitations on the regions where it can be played. A common mechanism used to enforce these restrictions is regional content blocking (or geoblocking). In this blog post, we analyze how regional content blocking was improperly implemented by RTVE, allowing media content to be accessed in regions where it should not be available. RTVE, Spain’s largest state-owned public media company, provides multi-station television (Televisión Española) and radio services (Radio Nacional de España), as well as online and streaming services (RTVE Play), which is the focus of our analysis.

Below, we present our threat model and detailed analysis to determine whether geo-blocking is correctly implemented at RTVE and identify any software flaws exist in their streaming protocol (spoiler alert: flaws do exist, or else there wouldn’t be a need for this post).

Threat Model

Many of RTVE’s streaming services are accesible only from Spain. Therefore, we consider an adversary located outside of Spain who has access to a VPN with a Spanish IP address. The adversary can turn the VPN on and off at will, using free VPN services that allow limited data usage. In vulnerable scenarios like the one we discuss here, the adversary can start streaming content while connected to the VPN and then disconnect, maintaining access to the content despite being outside the allowed region.

Streaming Protocol Identification

The first step is to identify which streaming protocol is being used. This can be done by inspecting the requests made by the web application. For this task, we use Burp Suite Community Edition (or simply Burp).

Setting Up Burp

After installing Burp, create a project with the standard settings (select “Use Burp Defaults”) — this is enough for our purposes. If you haven’t done yet, you need to configure Burp’s certificate in the browser as a trusted certificate to intercept and analyze HTTPS traffic. After importing the certificate and marking it as trusted, restart your browser. Verify that Burp is correctly intercepting HTTPS traffic before proceeding (e.g., try to navigate to an HTTPS website and check that Burp is intercepting traffic correctly). Once everything is set, we can start reviewing different streaming services :).

RTVE Streaming Protocol

Using the Proxy tool allows you to identify which requests are being used to detect the region where the content is being played.

We start by looking at the HTTP history window in the Proxy tab when connecting to some streaming content at RTVE.

Figure 1: Burp Suite HTTP Proxy window: RTVE Play website.

In the HTTP history window of the Proxy tab, we observe that an MPD file (file with extension .mpd) is received just before the stream starts (see Figure 1). This Media Presentation Description (MPD) file contains the metadata required by a DASH client to begin streaming.

Netflix Streaming Protocol

The logs sent to Netflix via the HTTP/1.1 POST request /log/www/cl/2 show the information about the Playback features detected by Netflix. In this case, the DASH protocol is (probably) used, since HLS is not supported.

{
  "name": "Playback FeatureDetection",
  "data":{
    "supportsHTML5withDRM": "yes",
    "supportsHTML5": "maybe",
    "determinedCapabilities":true,
    "canPlayHTML5":true,
    "canPlayHTML5WithDRM":true,
    "canPlayFlash": false,
    "TAG": "yes",
    "TAG UA":"maybe",
    "H264": "yes",
    "WEBM": "yes",
    "HLS":"no",
...
}

X Streaming Protocol

As for X, files with the m3u8 extension are received (see Figure 2). These types of files provide the presentation description of the transport stream (.ts files), which will be presented for video display using the HLS protocol.

Figure 2: Burp Suite HTTP Proxy window: X website.

This is an example of the data transmitted:

#EXTM3U
#EXT-X-VERSION: 6
#EXT-X-MEDIA-SEQUENCE: 0
#EXT-X-TARGETDURATION: 4
#EXT-X-PLAYLIST-TYPE: VOD
#EXT-X-ALLOW-CACHE: YES
#EXTINF:3.000,
/amplify_video/1307522080829837313/vid/0/3000/480x480/GBf65hNrxw6evl34.ts
#EXTINF:3.000,
/amplify_video/1307522080829837313/vid/3000/6000/480x480/15HzH5hyk5r3KJQk.ts
#EXTINF:3,000

YouTube Streaming Protocol

When accessing a YouTube video to watch it (for instance, this video), the HTTP/2 GET request returns an HTML document containing the following information about the webPlayer being used:

"webPlayerConfig":{
"useCobaltTvosDash":true,
...
}

Based on this information, we can deduce that DASH is used as the streaming protocol. No mpd, m3u8, or similar file sharing has been observed on YouTube.

France TV Streaming Protocol

France Télévisions (or France TV) is the French national public television broadcasting (it would be the equivalent of RTVE, but in France). It uses the DASH streaming protocol, since, as in RTVE, an .mpd file is received prior to the transmission of the content (see Figure 3).

Figure 3: Burp Suite HTTP Proxy window: France TV website.

Region Authorization Mechanisms

We will now explore how these platforms handle the process of determining whether the content the user wants to watch is allowed (or not) in the region they are connecting from.

To check how these mechanisms work, we have connected from different IP addresses, located in different countries, as appropriate.

Netflix Region Authorization Mechanism

On Netflix, region checking is constantly done using HEAD requests to check if the client’s location is valid. For instance:

HEAD /?o=1&v=111&e=1718833213&t=tJH7OwzGznYX... HTTP/1.1

This request validates the IP and returns a response indicating whether it is valid or not. For instance, a response to a valid request looks like this:

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 19 Jun 2024 09:44:09 GMT
Content-Type: application/octet-stream
Content-Length: 90903911
Last-Modified: Fri, 01 Dec 2023 06:03:52 GMT
Connection: keep-alive
Timing-Allow-Origin: *
Cache-Control: no-store
Pragma: no-cache
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-TCP-Info
X-TCP-Info: addr=IP-VPN-VALID;port=48105;sc=
Accept-Ranges: bytes

The X-TCP-Info header shows that the client IP is valid (i.e., addr=IP-VPN-VALID) and the streaming connection can continue. In contrast, a response to an invalid request looks like this:

HTTP/1.1 420 
Server: nginx
Date: Wed, 19 Jun 2024 09:52:59 GMT
Content-Length: 0
Connection: keep-alive
X-Netflix-Geo-Check: failed
Timing-Allow-Origin: *
Cache-Control: no-store
Pragma: no-cache
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-TCP-Info
X-TCP-Info: addr=IP-NO-VALID;port=50912;sc=

The X-TCP-Info header now shows that the client IP is invalid (i.e., addr=IP-NO-VALID) and the streaming connection cannot continue. Note also that we now have another header, X-Netflix-Geo-Check, reporting that the geolocation check performed by Netflix appears to have failed.

X Region Authorization Mechanism

X performs a region check on every GET request made to obtain the .m4s fragments (recall that X uses the HLS protocol). If this request is made from an allowed region, X returns a response code 200, transmitting part of the content. Additionally, one of the headers in this response (specifically, X-Allow-Country) indicates the regions where playback of the content is allowed. For instance:

X-Allow-Country: us,um,id,ph,vn,th,mm,co,ar,pe,my,ve,au,tw,cl,ec,gt,ht,bo,do,hn,hk,py,la,sv,ni,sg,cr,nz,pa,uy,pr,mo,bn,gp,mq,gf,mf,bl

As shown, the content we use here as a case study can be broadcast in many countries. However, if the request is made from a restricted location, you will get a 403 response code. This response code indicates that the content is not available at that specific location. The X-Allow-Country is also contained in the response. In particular, an example of the response obtained is the following:

HTTP/2 403 Forbidden
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Length
Age: 430505
Cache-Control: max-age=604800, must-revalidate
Content-Type: text/html
Date: Wed, 19 Jun 2024 10:03:32 GMT
Last-Modified: Sat, 06 Apr 2024 19:49:31 GMT
Perf: 7402827104
Server: ECAcc (mdr/67D3)
Server-Timing: x-cache;desc= ,x-tw-cdn;desc=VZ
Surrogate-Key: amplify_video amplify_video/bucket/0 amplify_video/1776699274350206976
Timing-Allow-Origin: https://twitter.com, https://mobile.twitter.com
X-Allow-Country: us,um,id,ph,vn,th,mm,co,ar,pe,my,ve,au,tw,cl,ec,gt,ht,bo,do,hn,hk,py,la,sv,ni,sg,cr,nz,pa,uy,pr,mo,bn,gp,mq,gf,mf,bl
X-Cache: MISS
X-Connection-Hash: d6a042657d63b53180289774a208a3fbb63176c9672b244744d0d4d4f4fb34e2
X-Content-Type-Options: nosniff
X-Response-Time: 13
X-Transaction-Id: 807a16693aec5940
X-Tw-Cdn: VZ
X-Tw-Cdn: VZ
Content-Length: 345

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
        <title>403 - Forbidden</title>
    </head>
    <body>
        <h1>403 - Forbidden</h1>
    </body>
</html>

YouTube Region Authorization Mechanism

In the case of YouTube, the client makes a POST request when accessing the video content. The response includes an object called playabilitystatus, which indicates whether the content is allowed at the client’s location. If it is allowed, the state attribute of this object will be OK. On the contrary, if the content is restricted in that region, the status attribute will be UNPLAYABLE. Regardless of whether the content is allowed or not, the HTTP response code is always 200. Therefore, the blocking status is determined on the client side by examining the content of the response rather than indicating it directly by its response code.

France TV Region Authorization Mechanism

Geolocation authorization on France TV occurs continuously during GET requests made by clients to access .dash files. When these files are requested from a restricted location, the server responds with an HTTP error code 403. Additionally, the X-Errortype header included in this response indicates the reason for the error. In this case, it is specifically tagged as geo. For instance, the response received from a restricted location looks like this:

HTTP/2 403 Forbidden
Server: AkamaiGHost
Mime-Version: 1.0
Content-Type: text/html
Content-Length: 752
Expires: Thu, 20 Jun 2024 07:49:10 GMT
Cache-Control: max-age=0, no-cache
Pragma: no-cache
Date: Thu, 20 Jun 2024 07:49:10 GMT
Akamai-Mon-Iucid-Del: 624506
Access-Control-Allow-Origin: https://www.france.tv
Access-Control-Expose-Headers: X-ErrorType,X-Reference-Error,Akamai-Mon-Iucid-Ing,Akamai-Mon-Iucid-Del,Akamai-Request-BC
Access-Control-Allow-Headers: Range,CMCD-Request,CMCD-Object,CMCD-Status,CMCD-Session
Access-Control-Allow-Methods: GET,OPTIONS
X-Errortype: geo

In this case, the method used to perform this control cannot be described in more detail, but it is evident that said control exists and that it is on the server side. This is evidenced by the fact that when the location changes to a restricted location, the streaming is interrupted.

RTVE Region Authorization Mechanism

And how does RTVE work to block content? When you start playing content on RTVE Play, the following sequence occurs:

Figure 4: Geoblocking API calls in the first RTVE requests.

As seen in Figure 4, several requests are made to the Geoblock API, which returns a JSON object indicating whether the content is available in the user’s region. For instance, a response from a valid location looks like this:

"page": {
  "items": [
   {
     "id":"16143443",
     "pubState": "ENPUB",
     "disponible": "Y",
     "desde": "01/01/1900 00:00",
     "hasta":"01/01/2901 00:01",
     "geolocalizadoCMS":true
   }

Note that the value of the disponible field (Spanish translation for available) is Y. In contrast, a response from an invalid location looks like this:

"page": {
  "items": [
   {
     "id":"16143443",
     "pubState": "ENPUB",
     "disponible": "N",
     "desde": "01/01/1900 00:00",
     "hasta":"01/01/2901 00:01",
     "geolocalizadoCMS":true
   }

After these Geoblocking API calls, as shown in Figure 4, there is a request for the .mpd file, which corresponds to the content you want to display. Region verification is also performed in this request. For instance, for the following request:

GET /43/34/16143443/16143443_drm.mpd?idasset=16143443 HTTP/2

We get a response similar to this (we left out some parts that are not interesting for our post). See the X-Country header:

X-Cache: MISS, HIT
X-Cache-Hits: 0, 3
X-Timer: S1718719439.709317,VSO, VEO
Vary: Accept-Encoding
X-Idasset: 16143443
X-Country: es
X-Original-Url: /43/34/16143443/16143443_drm.mpd?idasset=16143443
X-Vel: 85
X-Auth-Path: /api/geoblock/16143443/es.json

However, this check is only done when the .mpd file is requested. Subsequent content transmissions do not perform additional geolocation checks. As a result, if a user changes their location after the initial request for the MPD file, they can continue viewing the content without any further checks.

Quick Fix

To prevent unauthorized access, we propose modifying RTVE’s region authorization mechanism to ensure continuous location verification throughout subsequent content requests. A quick-and-dirty (but functional) solution would involve adding the header X-Auth-Path: /api/geoblock/XXX/es.json to each content request, where XXX represents the identifier of the updated geoblock API call. This would allow RTVE to detect changes in the client’s location and enforce geoblocking during content playback.

Responsable disclosure

Following the discovery of this vulnerability, we contacted the RTVE security team via email on July 5, 2024, providing technical details and reproduction steps. We allowed RTVE a three-month window to investigate and address the issue. Our goal was to ensure that RTVE could effectively rectify the vulnerability prior to the publication of this post, thereby safeguarding its content and maintaining compliance with regional access restrictions. After initial discussions where they acknowledged our disclosure, RTVE ceased further communication. As a result, we decided to proceed with the publication after waiting for the full three-month period.


And that’s all, guys & gals! In this post, we have analyzed the streaming protocols of several media companies using Burp Suite and identified issues with RTVEs implementation of geoblocking. We discovered that geoblocking checks occur only during the initial MPD request, enabling users to bypass restrictions by changing their location after this verification. To fix this, we proposed adding continuous location verification throughout subsequent requests.About the authors: this post was originally written by Mario Romeo and reviewed/edited by Ricardo J. Rodríguez.