RootMyTV.github.io/README.md

217 wiersze
12 KiB
Markdown

![RootMyTV header image](./img/header_logo.png)
RootMyTV is a user-friendly exploit for rooting/jailbreaking LG webOS smart TVs.
It bootstraps the installation of the [webOS Homebrew Channel](https://github.com/webosbrew/webos-homebrew-channel),
and allows it to run with elevated privileges. The Homebrew Channel is a
community-developed open source app, that makes it easier to develop and install
3rd party software. [Find out more about it here.](https://github.com/webosbrew/webos-homebrew-channel)
If you want the full details of how the exploit works, [skip ahead to our writeup.](#research-summary-and-timeline)
<!-- TODO: say which webOS versions etc. are currently supported -->
At the time of writing (2021-05-15), all webOS versions between 3.5 and 5.5 we
tested (TVs released between mid-2017 and 2020) are supported by this exploit
chain.
# Usage Instructions
**Step Zero (disclaimer):** Be aware of the risks. Rooting your TV is (unfortunately) not supported by
LG, and although we've done our best to minimise the risk of damage,
we cannot make any guarantees. This may void your warranty.
1. Make sure the "LG Connect Apps" feature is enabled. It seems to be enabled by default on
webOS 4.0+. For older models, follow [LG's instructions.](https://www.lg.com/in/support/help-library/lg-webos-tv-how-to-use-lg-connect-apps-CT20150005-1437127057046)
2. Open the TV's web browser app and navigate to [https://rootmy.tv](https://rootmy.tv)
3. "Slide to root" using a Magic Remote or press button "5" on your remote.
4. Accept the security prompt.
5. The exploit will proceed automatically. The TV will reboot itself once
during this process, and optionally a second time to finalize the installation
of the Homebrew Channel. On-screen notifications will indicate the exploit's
progress.
6. Your TV should now have Homebrew Channel app installed, and an
unauthenticated root telnet service exposed. It is **highly recommended** to disable
Telnet and enable SSH Server with public key authentication
(Homebrew Channel → Settings → SSH Server). You will need to manually copy
your SSH Public Key over to `/home/root/.ssh/authorized_keys` on the TV.
GitHub user registered keys can be installed using the following snippet:
```sh
mkdir -p ~/.ssh && curl https://github.com/USERNAME.keys > ~/.ssh/authorized_keys
```
For exploiting broken TVs, check out the information [here.](./docs/HEADLESS.md)
## Troubleshooting
In case of any problems [join the OpenLGTV Discord server](https://discord.gg/xWqRVEm)
and ask for help on `#rootmytv` channel, or file a GitHub issue.
Before asking for support, please consult our [Troubleshooting guide.](./docs/TROUBLESHOOTING.md)
# Research Summary and Timeline
RootMyTV is a chain of exploits. The discovery and development of these
exploits has been a collaborative effort, with direct and indirect contributions
from multiple researchers.
On October 05, 2020, Andreas Lindh reported a root file overwrite vulnerability
to LG. On February 03, 2021, Andreas [published his findings](https://blog.recurity-labs.com/2021-02-03/webOS_Pt1.html),
demonstrating a local root exploit against the webOS Emulator (a part
of LG's development SDK). LG had boldly claimed that this issue did not affect their devices,
and that they were going to patch their emulator.
On February 15th, 2021, David Buchanan reported a vulnerability in LG's
"ThinQ login" app, which allowed the app to be hijacked via a specific sequence
of user inputs, allowing an attacker to call privileged APIs.
On March 23rd 2021, David [published a proof-of-concept exploit](https://forum.xda-developers.com/t/rootmy-tv-coming-soon-developer-pre-release-available-now.4232223/),
which enabled users to gain root privileges on their LG smart TVs. This was made
possible by combining it with the local root vulnerability previously
reported by Andreas (Yes, the same one that LG said did not affect their devices!).
Around March 28th 2021, Piotr Dobrowolski discovered a similar vulnerability in the
"Social login" app, which is present across a wider range of webOS versions.
More importantly, this exploit could be easily triggered over the local network,
using SSAP (details below), making it much more reliable and user-friendly.
At time of writing, the code in this repo is the combined work of David
Buchanan (Web design, initial PoC exploit) and Piotr Dobrowolski (Improved "v2" exploit
implementation, and writeup).
We would like to thank:
- Andreas Lindh for publishing his webOS research.
- The wider webOS community, particularly the XDA forums and the OpenLGTV discord (TODO: links)
- All the contributors (present and future) to the Homebrew Channel, and development of other homebrew apps and software.
- LG, for patching symptoms of bugs rather than underlying causes...
# The Technical Details
### Background
webOS, as the name suggests, is a Smart TV operating system mostly based on web
technologies. Applications, both system and external are either run in a
stripped down Chromium-based web browser ("WebAppMgr") or in Qt QML runtime. Almost all system
and external applications run in chroot-based jails as an additional security
layer.
"Web apps", outside of standard web technologies, also get access to an API for
communicating with "Luna Service Bus". This is a bus, similar to D-Bus, used to
exchange messages and provide various services across different security
domains. Bus clients can expose some RPC methods to other applications
(identified by URIs `luna://service-name/prefix-maybe/method-name`) which accept
JSON object message as their call parameters, and then can return one or many
messages. (depending on the call being "subscribable" or not)
While Luna bus seems to have extensive ACL handling, considering the [history of webOS IP transfers](https://en.wikipedia.org/wiki/WebOS#History), seems like not many engineers fully understand its
capabilities. Part of the bus is marked as "private", which is only accessible
by certain system applications, while most of the other calls are "public" and
can be accessed by all apps.
Unexpectedly, one of the "public" services exposed on a bus is "LunaDownloadMgr"
which provides a convenient API for file download, progress tracking, etc...
Said service has been researched in the past and an identity confusion bug
leading to an arbitrary unjailed root file write vulnerability has been
[publicly documented](https://blog.recurity-labs.com/2021-02-03/webOS_Pt1.html).
This in of itself was not very helpful in production hardware, thus we needed to
find a way of calling an arbitrary Luna service from an application with
`com.webos.` / `com.palm.` / `com.lge.` application ID.
### Step #0 - Getting in (stage1.html)
In order to gain initial programmatic control of the TV user interface an
interface of "LG Connect Apps" can be used. Its protocol called "SSAP" is a
simple websocket-based RPC mechanism that can be used to indirectly interact
with Luna Service bus and has been extensively documented in various
home-automation related contexts. We use that to launch a vulnerable system
application which is not easily accessible with plain user interaction.
#### Step #0.1 - Escaping the origins
SSAP API is meant to be used from an external mobile app. For the sake of
simplicity, though, we wanted to serve our exploit as a web page. This lead us
to notice, that, understandably, SSAP server explicitly rejects any connections
from HTTP origins. However, there was an additional exception from that rule,
and seemingly authors wanted to allow file:// origins, which present themselves
to the server as `null`. Turns out there's one other origin that can be used
that is also reprted as `null` and that is `data:` URIs.
In order to exploit this, we've created a minimal WebSocket API proxy
implementation that opens a hidden iframe with a javascript payload (which is
now running in a `data:`/`null` origin) and exchanges the messages with the main
browser frame. This has been released as [a separate
library](https://github.com/Informatic/webos-ssap-web).
#### Step #0.2 - General Data Protocol Redirection
There's a minor problem with establishing the connection with SSAP websocket
server. While we all believe in utter chaos, we don't feel very comfortable with
serving our exploit over plain HTTP, which would be the only way of avoiding
Mixed Content prevention policies. (by default https origins are not allowed to
communicate with plain http endpoints)
While [some newer Chromium versions](https://chromium.googlesource.com/chromium/src.git/+/130ee686fa00b617bfc001ceb3bb49782da2cb4e)
do allow Mixed Content communication with `localhost`, that was not the case
when Chromium 38 was released (used in webOS 3.x). Thankfully, it seems like the
system browser on webOS 3.x is also vulnerable to something that has been
considered a security issue in most browsers for a while now - navigation to
`data:` URIs. Thus, when applicable, our exploits attempts to open itself as a
`data:` base64-encoded URI. This makes our browser no longer consider the origin
being secure, and we can again access the plain-http WebSocket server.
#### Mitigation note
An observant reader may have noticed that the service we use is meant to be used
remotely. While the connection itself needs a confirmation using a remote **we
highly recommend to disable LG Connect Apps functionality** in order to prevent
remote exploitation, or at least to keep the TV on a separate network.
### Step #1 - Social login escape (stage1.html)
Having some initial programmatic control of the TV via SSAP we can execute any
application present on the TV. All cross-application launches can contain an
extra JSON object called `launchParams`. This is used to eg. open a system
browser with specific link open, or launch a predetermined YouTube video. Turns
out this functionality is also used to select which social website to use in
`com.webos.app.facebooklogin`, which is the older sibling of
`com.webos.app.iot-thirdparty-login` used in initial exploit, present on all
webOS versions up until (at least) 3.x.
When launching social login via LG Account Management this application accepts
an argument called `server`. This turns out to be a part of URL that "web app"
browser is navigated to. Thus, using properly prepared `launchParams` we are
able to open an arbitrary web page (with the only requirement being it served
over `https`) running as a system app that is considered by `LunaDownloadMgr`
a "system" app.
### Step #2 - Download All The Things (stage2.html)
Since we are already running as a system application, we can download files
(securely over https!) into arbitrary unjailed filesystem locations as root.
We use that to download following files:
* `stage3.sh`
`/media/cryptofs/apps/usr/palm/services/com.palmdts.devmode.service/start-devmode.sh` -
this is the script executed at startup by `/etc/init/devmode.conf` as root,
in order to run developer mode jailed SSH daemon.
* `hbchannel.ipk``/media/internal/downloads/hbchannel.ipk` - since our end
goal is intalling the Homebrew Channel app, we can also just download it
during the earlier stages of an exploit and confirm it's actually downloaded.
* `devmode_enabled``/var/luna/preferences/devmode_enabled` - this is the flag
checked before running `start-devmode.sh` script, and is just a dummy file.
### Step #3 - Homebrew Channel Deployment (stage3.sh)
`stage3.sh` script is a minimal tool that, after opening an emergency telnet
shell and removing itself (in case something goes wrong and the user needs to
reboot a TV - script keeps running but will no longer be executed on next
startup), installs the homebrew channel app via standard devmode service calls
and elevates its service to run unjailed as root as well.