Skip to content

6cloudguy/tvstreamer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📺 TV Speaker: Unauthenticated Sony Bravia Audio Streamer

Medium Writeup License: MIT Python Linux Windows macOS

A cross-platform tool to stream live system audio from your Linux, Windows, or macOS machine directly to a Sony Bravia TV over the local network — by exploiting its unauthenticated UPnP/DLNA control interface.

This repository accompanies the technical write-up: How I Hacked my Living Room: Unauthenticated Control of a Sony Bravia TV via UPnP/DLNA.


🔍 Background & The Exploit

Many modern smart TVs (including Sony Bravia models) expose UPnP (Universal Plug and Play) and DLNA (Digital Living Network Alliance) endpoints on the local network. Because these protocols are designed for frictionless media sharing, they often do not implement any authentication or permission checks for devices on the same subnet.

By crafting raw SOAP XML requests, we can:

  1. Forcibly alter the TV volume (overriding manual controls).
  2. Set the media source (AVTransportURI) to an arbitrary HTTP stream URL.
  3. Trigger media playback (Play command).

All of this happens without any visual prompt, pairing PIN, or permission dialog appearing on the TV screen.


📁 Repository Structure

tvstreamer/
├── tv-speaker.py      ⭐ Cross-platform controller (Linux / Windows / macOS)
├── audio_server.py       DLNA-compatible streaming server (auto-detects OS audio backend)
├── tv-speaker.sh         Original bash controller (Linux legacy)
└── LICENSE

🛠️ System Architecture

flowchart LR
    subgraph sender ["Your Machine (Sender)"]
        A["System Audio\n(PulseAudio / WASAPI / AVFoundation)"] -->|"Loopback Capture"| B("FFmpeg Encoder")
        B -->|"MP3 Stream"| C["Flask Server (:8000)\naudio_server.py"]
        D["tv-speaker.py"] -.->|"1. Launch"| C
    end

    subgraph receiver ["Sony Bravia TV (Receiver)"]
        E["UPnP / DLNA Endpoint\n(:2870)"]
        F["Media Player"]
    end

    D -->|"2. SOAP: SetVolume"| E
    D -->|"3. SOAP: SetAVTransportURI"| E
    D -->|"4. SOAP: Play"| E
    E -.->|"Triggers Playback"| F
    F -->|"5. HTTP GET /stream.mp3"| C
Loading

A lightweight Flask HTTP server that:

  • Auto-detects the OS and selects the correct ffmpeg audio backend:
    Platform ffmpeg backend Audio Source
    Linux -f pulse PulseAudio / PipeWire monitor (auto-detected via pactl)
    Windows -f dshow Stereo Mix / virtual loopback device (auto-scanned)
    macOS -f avfoundation Virtual audio device e.g. BlackHole (index configurable)
  • Encodes captured loopback audio on-the-fly to MP3 (192kbps, 44.1kHz stereo).
  • Streams continuously at /stream.mp3 with proper DLNA compliance headers.

tv-speaker.py(recommended)

A fully dynamic cross-platform Python controller:

  • 🔍 SSDP auto-discovery — scans the LAN for Sony Bravia / UPnP MediaRenderers, no IP config needed.
  • 🌐 Auto-detects local machine IP for the stream URL.
  • 🖥️ Interactive picker when multiple devices are found on the network.
  • 🎨 Colourful ASCII banner and rich terminal output.
  • 🛑 Graceful Ctrl+C — sends a UPnP Stop to the TV before quitting.
  • Zero extra deps beyond Flask — all SOAP via stdlib urllib.

tv-speaker.sh (Linux legacy)

The original bash script. Requires curl and hardcoded IP variables. Kept for reference.


🚀 Getting Started

📋 Prerequisites

Dependency Linux Windows macOS
Python 3.8+
Flask
FFmpeg
PulseAudio / PipeWire
Stereo Mix (loopback)
BlackHole / Soundflower
pip install flask
🐧 Linux — FFmpeg install
sudo apt install ffmpeg    # Debian / Ubuntu
sudo pacman -S ffmpeg      # Arch Linux
sudo dnf install ffmpeg    # Fedora
🪟 Windows — FFmpeg + Stereo Mix setup
  1. Download FFmpeg from https://ffmpeg.org/download.html and add it to your PATH.
  2. Enable Stereo Mix (Windows system audio loopback):
    • Right-click the speaker icon → SoundsRecording tab
    • Right-click in empty space → Show Disabled Devices
    • Right-click Stereo MixEnable
  3. If your soundcard doesn't have Stereo Mix, install VB-Audio Virtual Cable as a loopback alternative.

Note: tv-speaker.py will auto-scan and prefer loopback devices (Stereo Mix, Wave Out Mix, etc.).
If it picks the wrong device, set AUDIO_DEVICE manually (see below).

🍎 macOS — Virtual audio device setup
  1. Install BlackHole:
    brew install blackhole-2ch
  2. Open Audio MIDI Setup → create a Multi-Output Device with both your speakers and BlackHole.
  3. Set system output to the Multi-Output Device.
  4. BlackHole becomes the loopback capture source for ffmpeg.

🏃 Usage

Python — all platforms (recommended)

# Auto-discover TV and start streaming
python tv-speaker.py

# Scan for TVs on your network, then exit
python tv-speaker.py --scan-only

# Skip SSDP discovery — specify everything manually
python tv-speaker.py --tv-ip 192.168.1.50 --host-ip 192.168.1.10 --volume 75

# All options
python tv-speaker.py --help

CLI flags:

Flag Description Default
--tv-ip <ip> TV IP — skips SSDP scan auto-discover
--host-ip <ip> Local machine IP for stream URL auto-detect
--port <port> Audio server port 8000
--volume <0-100> TV volume to set 80
--monitor <name> Linux: PulseAudio/PipeWire monitor sink to capture interactive picker
--scan-only Print found TVs and exit
--list-monitors Linux: print all available monitor sinks and exit

Override audio device if auto-detection picks the wrong source:

# Linux — list all available monitor sinks
python tv-speaker.py --list-monitors

# Linux — pin a specific monitor sink (skip the interactive picker)
python tv-speaker.py --monitor "alsa_output.pci-0000_00_1f.3.HiFi__Speaker__sink.monitor"

# macOS — set avfoundation device index
export AUDIO_DEVICE=1

# Windows (PowerShell) — set dshow device name
$env:AUDIO_DEVICE = "Stereo Mix (Realtek HD Audio)"

python tv-speaker.py

Find your Linux monitor sinks manually:

pactl list short sources | grep monitor

The interactive picker (shown when multiple exist) shows the friendly name alongside the sink name so you can easily identify Speakers, HDMI, USB audio, etc.

Bash — Linux legacy

# Edit TV_IP, LAP_IP, MONITOR inside the script first, then:
chmod +x tv-speaker.sh
./tv-speaker.sh

📡 SOAP Payloads Used

Both tv-speaker.py and tv-speaker.sh send raw SOAP XML over HTTP to the TV's UPnP endpoints at port 2870.

Volume Adjustment (RenderingControl#SetVolume)

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <u:SetVolume xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1">
      <InstanceID>0</InstanceID>
      <Channel>Master</Channel>
      <DesiredVolume>80</DesiredVolume>
    </u:SetVolume>
  </s:Body>
</s:Envelope>

Setting the Stream URI (AVTransport#SetAVTransportURI)

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
            s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
      <InstanceID>0</InstanceID>
      <CurrentURI>http://&lt;HOST_IP&gt;:8000/stream.mp3</CurrentURI>
      <CurrentURIMetaData></CurrentURIMetaData>
    </u:SetAVTransportURI>
  </s:Body>
</s:Envelope>

Triggering Playback (AVTransport#Play)

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
            s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
      <InstanceID>0</InstanceID>
      <Speed>1</Speed>
    </u:Play>
  </s:Body>
</s:Envelope>

🛡️ Security Countermeasures

If you own a Sony Bravia and want to prevent this kind of unauthenticated control:

  1. Enable IP Control authenticationSettings → Network → Home Network → IP Control
    • Set Authentication to Normal or Pre-Shared Key (not None).
    • Disable Simple IP Control if unused.
  2. Network segmentation — Put smart TVs and IoT devices on a dedicated VLAN or guest network, isolated from your primary LAN.
  3. Disable UPnP on your router — Prevents UPnP port mappings and reduces attack surface from devices on the LAN.

📄 License

This repository is licensed under the MIT License. Feel free to use, modify, and distribute.


👤 Author

Made by 6cloudguy — check out the full technical write-up on how the exploit was discovered:

How I Hacked my Living Room: Unauthenticated Control of a Sony Bravia TV via UPnP/DLNA

About

Scripts to stream media to Sony Bravia Tv by exploiting a UPnP bug/vulnerabilty that i found on my TV

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors