
Research toolkit that roots a Samsung Tizen 9 TV via a Chromium WasmGC RCE and V4L2 physmap arbitrary physical memory access, with persistent on-boot payload and root shell channel.
Unofficial security research on a 2024 Samsung Neo QLED running Tizen 9. No sdb, no developer mode, no firmware flashing: the TV is rooted from its own browser, and the root is made persistent through a stock on-boot service app.
| Test unit | 2024 Neo QLED, QNX1D series (QTV T09 platform) |
| Firmware | T-PTMxxxx (01400) |
| Kernel | Linux 5.4.249, ARM32 (VMSPLIT_3G + HIGHMEM, no LPAE), PAGE_OFFSET 0xC0000000, PHYS_OFFSET 0x20000000 |
| Browser | Chromium 120.0.6099.5 (SamsungBrowser/7.0) |
| Root | uid=0, CapEff=0x3fffffffff |
| Persistent payload | repo v41 (current md5/size in the AGENTS.md state row — regenerated from the artifact); the test unit runs the same build (deployed 2026-10-27, beacons carry tok=); payload_backup.dll keeps the previous build |
| Root channel | TCP 31337 on the TV, line protocol, replies end with __END__ |
pwsh -File .\root.ps1 -TvIp <tv-ip> # root the TV
pwsh -File .\uninstall.ps1 -TvIp <tv-ip> # restore stock
root.ps1 runs on the PC and drives everything: it starts the port-80 server,
roots the browser stub, installs the boot payload, and waits for the root channel
after the reboot. Two steps stay on the TV remote, and it prompts for both:
http://<pc-ip>/index.html and wait for RUNNING;Then:
python tools\root_shell.py "id" <tv-ip> # talk to the TV's root channel
Every option, the exact prompts, expected output, the host-IP caveat and the
manual fallback: docs/USAGE.md.
/dev/video40/30/60) accept an
attacker-chosen vm_pgoff in mmap() and pass it to remap_pfn_range()
unvalidated: arbitrary physical memory read/write from an unprivileged
process (uid 5001, group video).init_task in physical memory, locate our
own task through a forked child's real_parent, and zero the credentials.app_onboot service with
a .NET payload that repeats the physmap/cred patch at every boot, closes its
node and serves a root command channel on TCP 31337.No GPU CVE, no kernel exploit, no signed module. The physmap is the interesting
part; the stage-by-stage writeup with the measured constants is
docs/EXPLOIT.md.
| Document | Contents |
|---|---|
docs/USAGE.md | running it: options, prompts, expected output, uninstall detail, recovery |
docs/EXPLOIT.md | the chain stage by stage, with the firmware-specific constants |
docs/ROOT-METHODS.md | every root/persistence method evaluated and the one that won |
docs/FAILED.md | what did not work and why — reads like a list of dead ends, saves weeks |
docs/BOOT-REGRESSION-SMACK.md | the subtlest bug in the project: a wrong SMACK label made the app die before Main |
docs/PORTABILITY.md | another Tizen 9 TV: the four gates, what to re-measure, a step-by-step port |
docs/SERVER-HOSTING.md | the PC-side server: how it must run, the silent-death trap, firewall, logs |
docs/SCRIPT-REVIEW.md | production-readiness audit of the scripts |
docs/TESTING.md | the test layers, offline and on-TV, and what each catches |
docs/LOGGUIDE.md | every beacon and tool error decoded, with next steps |
docs/REFERENCE-MATERIALS.md | where to download firmware / GPL sources / sim tooling for your own model |
docs/REVIEW-HISTORY.md | closed review findings and their evidence (archive) |
docs/OPEN-ISSUES.md | current state, pending work, and the closed review/pass history |
AGENTS.md | hand-off: tools, procedure, verification, traps, recovery |
CHANGELOG.md | dated history of what changed and why |
SECURITY.md | the unauthenticated 31337 backdoor, scope, reporting, legal |
NOTICE.md | third-party attribution; which files are not relicensed |
LICENSE | MIT for the original work (third-party files excluded) |
root.ps1, uninstall.ps1 PC entry points (PowerShell)
payload/ boot payload source (.NET 6, Program.cs)
server/ port-80 server, exploit page, TV-side deploy scripts
tools/ physmap client, kernel helpers, build scripts
docs/ the documents above
AGENTS.md hand-off notes
LICENSE, NOTICE.md license + third-party attribution
SECURITY.md backdoor/scope/reporting
The whole toolkit is committed, so a clone runs without any other working tree.
server/payload.dll is included on purpose (byte-identical to the build output)
so the toolkit works without a .NET SDK. Runtime logs, build output and the
per-host generated deploy script are git-ignored and never served over HTTP.
docs/PORTABILITY.md before trying another model.server/deploy.sh is a
template whose H=/WANT=/SIZE_WANT=/TOKEN= markers server.py renders
per request
from the address the TV used and the payload actually served, the page rewrites
the shellcode's callback (IP and port), and the payload reads
share/rootchan.host. The compiled-in Host is a TEST-NET placeholder.docs/SERVER-HOSTING.md).payload/global.json pins
10.0.x (rollForward: latestPatch); the project targets net6.0, which the
pinned SDK still builds (an EOL warning is expected).