{"id":2324,"date":"2020-06-21T18:01:31","date_gmt":"2020-06-21T18:01:31","guid":{"rendered":"http:\/\/blog.rastersoft.com\/?p=2324"},"modified":"2020-10-21T12:15:44","modified_gmt":"2020-10-21T12:15:44","slug":"a-ritmo-de-conga","status":"publish","type":"post","link":"https:\/\/blog.rastersoft.com\/?p=2324","title":{"rendered":"A ritmo de conga (1)"},"content":{"rendered":"\n<p><strong>Actualizado:<\/strong> varios comandos de servidor a aspiradora terminaban con un LF (o sea, <strong>\\n<\/strong>). A\u00f1adidos.<\/p>\n\n\n\n<p>Recientemente decid\u00ed comprarme un aspirador rob\u00f3tico, as\u00ed que empec\u00e9 a ver opciones. Es cierto que, siendo el primero, no quer\u00eda gastarme mucho por si no me convenc\u00eda, pero a la vez no quer\u00eda tampoco comprar algo cutre que luego no funcionase. As\u00ed que al final, despu\u00e9s de mucho pensar, decid\u00ed comprarme un Conga de Cecotec. Mi intenci\u00f3n era comprar el m\u00e1s bajo de gama, pero estaba agotado, as\u00ed que al final me pill\u00e9 el Conga 1490, que tiene como caracter\u00edstica diferenciadora que se puede controlar desde el m\u00f3vil.<\/p>\n\n\n\n<p>Y claro, me ponen un caramelito as\u00ed, delante, y lo primero que se me pas\u00f3 por la cabeza fue \u00abno estar\u00eda mal meter las narices a ver c\u00f3mo funciona\u00bb.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"186\" style=\"aspect-ratio: 186 \/ 186;\" width=\"186\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/oh_si.mp4\"><\/video><\/figure>\n\n\n\n<p>Sin embargo, cuando me le\u00ed las condiciones de uso de la <em>app<\/em> y descubr\u00ed que env\u00eda tu IP, tu correo-e y los mapas que hace la aspiradora no s\u00f3lo a Cecotec (que, a fin de cuentas, es una empresa espa\u00f1ola y est\u00e1 sujeta a las normas comunitarias de protecci\u00f3n de datos), sino directamente al verdadero fabricante, que es chino (y te dicen claramente que \u00e9l s\u00ed que no est\u00e1 sujeto a esas normas), la cosa empez\u00f3 a mosquearme, y mis ganas de tocar dentro aumentaron bastante.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"320\" style=\"aspect-ratio: 320 \/ 320;\" width=\"320\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/say-what.mp4\"><\/video><\/figure>\n\n\n\n<p>Pero no se vayan todav\u00eda, que a\u00fan hay m\u00e1s&#8230; resulta que se me ocurre ver qu\u00e9 permisos pide para funcionar, y me encuentro con que en el manifiesto pide, entre otras cosas:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>hacer llamadas<\/li><li>acceso total a Internet<\/li><li>acceso al micr\u00f3fono<\/li><li>acceso a la c\u00e1mara y al flash<\/li><li>acceso de lectura y escritura a todo el almacenamiento del dispositivo<\/li><li>obtener datos del propietario<\/li><li>acceso a los <em>logs<\/em> del sistema<\/li><li>acceso a la lista de aplicaciones<\/li><li>arrancar autom\u00e1ticamente en el inicio del sistema<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"134\" style=\"aspect-ratio: 200 \/ 134;\" width=\"200\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/say-what-gone-with-the-wind.mp4\"><\/video><\/figure>\n\n\n\n<p>Esto ya me parec\u00eda el colmo: una aplicaci\u00f3n china con acceso a TODO, y que encima se lanza autom\u00e1ticamente en el arranque&#8230; <strong>ni-de-co-\u00f1a<\/strong>.<\/p>\n\n\n\n<p>Y s\u00ed, se lo que dir\u00e1n algunos: la mitad de esos permisos (c\u00e1mara, micr\u00f3fono, llamadas y almacenamiento) no s\u00f3lo se pueden desactivar en las propiedades de la aplicaci\u00f3n, sino que, de intentar usarlos, el sistema operativo avisar\u00eda; y la otra mitad (acceso a datos del propietario y lista de aplicaciones) han sido eliminados en versiones recientes de Android. Pero pese a todo, es una cuesti\u00f3n de que no basta con ser bueno, tambi\u00e9n hay que <em>parecerlo<\/em>. Y esta <em>app<\/em>, por mucho de que en la pr\u00e1ctica no haga nada malo, que dejen todo eso as\u00ed queda, como m\u00ednimo, <em>feo<\/em>.<\/p>\n\n\n\n<p>Pero es que, adem\u00e1s, como veremos luego, la <em>app<\/em> y la aspiradora precisan de una conexi\u00f3n a internet para trabajar, lo que significa que si, por el motivo que sea, el fabricante decide que ya no le compensa tener encendido su servidor, MI aspiradora, por la que he pagado dinero, dejar\u00e1 de funcionar de la manera que me vendieron que funcionar\u00eda.<\/p>\n\n\n\n<p>As\u00ed que toca arremangarse y empezar a trabajar.<\/p>\n\n\n\n<p><strong>DISCLAIMER:<\/strong> no ser\u00e9 responsable si alguien decide seguir mis pasos y se carga su aspiradora. En principio todo lo que cuento deber\u00eda ser seguro, pero por motivos obvios no me puedo responsabilizar de lo que hagan otras personas, s\u00f3lo de lo que haga yo.<\/p>\n\n\n\n<p>Lo primero que hice fue echar un vistazo al manual, y como cab\u00eda suponer, la aspiradora tiene WiFi y hay que emparejarla primero con el router. Para ello hay dos maneras, la autom\u00e1tica y la manual. En ambos casos se comienza pulsando el bot\u00f3n de encendido de la aspiradora durante tres segundos, de manera que el piloto de la WiFi empieza a parpadear, y a continuaci\u00f3n se mete la clave de la WiFi en la <em>app<\/em> (el SSID ya aparece, poniendo por defecto el mismo que usa el m\u00f3vil).<\/p>\n\n\n\n<p>Ahora, en modo autom\u00e1tico, simplemente se deja que sea la propia <em>app<\/em> quien configure todo. Sin embargo, en modo manual hay que ir a <em>Ajustes -&gt; WiFi<\/em> en el m\u00f3vil y escoger una red con el identificador <em>CongaGyro_XXXXXX<\/em>, pulsar el bot\u00f3n de <em>configurar<\/em>, y volver a la WiFi normal. Efectivamente: al ponerse en <em>modo emparejamiento<\/em>, la aspiradora se convierte en un punto de acceso sin clave.<\/p>\n\n\n\n<p>El primer paso, por tanto, era obvio: poner la aspiradora en <em>modo emparejamiento<\/em>, conectarse a esa WiFi desde el port\u00e1til (en mi caso me dio la IP 192.168.4.2), y hacer un escaneo de puertos con <em>nmap<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">nmap -p 1-49151 192.168.4.1<\/pre>\n\n\n\n<p>Y tal y como cab\u00eda esperar, el puerto 80 est\u00e1 abierto, y al entrar desde un navegador aparece esta p\u00e1gina:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/Captura-de-pantalla-de-2020-06-20-00-28-02.png\" rel=\"lightbox-0\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/Captura-de-pantalla-de-2020-06-20-00-28-02-1024x576.png\" alt=\"\" class=\"wp-image-2337\" srcset=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/Captura-de-pantalla-de-2020-06-20-00-28-02-1024x576.png 1024w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/Captura-de-pantalla-de-2020-06-20-00-28-02-300x169.png 300w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/Captura-de-pantalla-de-2020-06-20-00-28-02-768x432.png 768w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/Captura-de-pantalla-de-2020-06-20-00-28-02-1536x864.png 1536w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/Captura-de-pantalla-de-2020-06-20-00-28-02.png 1920w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Tras escribir el SSID y la clave de mi WiFi, devuelve una p\u00e1gina con un OK y el punto de acceso desaparece. Una simple comprobaci\u00f3n con <em>nmap<\/em> nos devuelve la nueva IP de la aspiradora, ahora s\u00ed en la WiFi <em>de verdad<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">nmap -sP 192.168.18.0\/24<\/pre>\n\n\n\n<p>Por supuesto, cada uno tiene que cambiar la IP por el valor de las IPs internas de su red. Una vez encontrada la IP, un nuevo escaneo de puertos me dej\u00f3 descolocado: no hab\u00eda absolutamente ninguno, todos estaban cerrados a cal y canto.<\/p>\n\n\n\n<p>Decid\u00ed que poco m\u00e1s podr\u00eda hacer sin instalar la aplicaci\u00f3n y esnifar los datos que intercambiaba con el aspirador, pero no me hac\u00eda ninguna gracia meterla en mi m\u00f3vil, as\u00ed que cog\u00ed una vieja tablet que no usaba para nada, la formate\u00e9, la registr\u00e9 con una cuenta de correo creada <em>ex profeso<\/em>, y me fui a la <em>Play Store<\/em> a instalar la <em>app<\/em>&#8230;<\/p>\n\n\n\n<p>Y no estaba.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"240\" style=\"aspect-ratio: 320 \/ 240;\" width=\"320\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/oh-my.mp4\"><\/video><\/figure>\n\n\n\n<p>Prob\u00e9 con todo tipo de combinaciones, pero aunque estaban algunas otras <em>apps<\/em> de Cecotec, la que hab\u00eda visto para la Conga 1490 y 1590 no aparec\u00eda por ninguna parte. Curiosamente fue lo mismo que me ocurri\u00f3 cuando prob\u00e9 con un Android X86 corriendo en una m\u00e1quina virtual&#8230; Mi conclusi\u00f3n es que, dado que en el manifiesto de la <em>app<\/em> pide permitir hacer llamadas, la <em>Play Store<\/em> s\u00f3lo deja instalarla en dispositivos con tarjeta SIM.<\/p>\n\n\n\n<p>Sin embargo, si nos bajamos el APK desde otra fuente, lo copiamos a la tablet y lo instalamos (tras permitir la instalaci\u00f3n desde fuentes no confiables, claro) la aplicaci\u00f3n funciona perfectamente.<\/p>\n\n\n\n<p>Con ella ya instalada, llega la segunda parte: configurar un punto de acceso que nos permita esnifar todo el tr\u00e1fico. El problema surge cuando nos damos cuenta de que es muy dif\u00edcil hacer eso en WiFi, as\u00ed que mi soluci\u00f3n fue usar una Raspberry Pi configurada como punto de acceso, y correr en ella <em>tcpdump<\/em> para capturar todo el tr\u00e1fico que pasase.<\/p>\n\n\n\n<p>Para configurar una Raspberry Pi como punto de acceso basta con seguir estas instrucciones:<\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/www.raspberrypi.org\/documentation\/configuration\/wireless\/access-point-routed.md\" target=\"_blank\">https:\/\/www.raspberrypi.org\/documentation\/configuration\/wireless\/access-point-routed.md<\/a><\/p>\n\n\n\n<p>Yo utilic\u00e9 la res 192.168.18.X para la WiFi, y as\u00ed asegurarme de que no haya interferencias con nada m\u00e1s. Luego, para capturar todo el tr\u00e1fico, uso el comando:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">sudo nohup tcpdump -ni wlan0 '(not dst 192.168.18.4) and (not src 192.168.18.4)' -s0 -w datos.pcap<\/pre>\n\n\n\n<p>Siendo 192.168.18.4 la direcci\u00f3n IP de mi ordenador de sobremesa, para que no capture los paquetes que se intercambian cuando entro por SSH, y as\u00ed tener una captura limpia. El par\u00e1metro <em>w <\/em>almacena los paquetes <em>en bruto<\/em> en el fichero <em>datos.pcap<\/em>, lo que nos permite luego abrirlo en, por ejemplo, <em>WireShark<\/em>, para analizarlos con m\u00e1s detenimiento.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"216\" style=\"aspect-ratio: 320 \/ 216;\" width=\"320\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/perfect.mp4\"><\/video><\/figure>\n\n\n\n<p>Y con esto est\u00e1 todo listo para empezar, as\u00ed que puse en marcha la captura de paquetes, y en la tablet lanc\u00e9 la aplicaci\u00f3n, rellen\u00e9 los campos con una direcci\u00f3n de correo nueva, creada para la ocasi\u00f3n, emparej\u00e9 la aspiradora, y lanc\u00e9 un escaneo de puertos&#8230; \u00a1y ahora la aspiradora ten\u00eda uno abierto, el 8888!<\/p>\n\n\n\n<p>Buena cosa, pues, pero ahora tocaba parar la captura y empezar a analizar qu\u00e9 hab\u00edan hecho la aspiradora y la <em>app<\/em>.<\/p>\n\n\n\n<p>Una vez copiado el fichero con el volcado, proced\u00ed a abrirlo con el <em>Wireshark<\/em>. Lo primero que hace la aspiradora, como cabe esperar, es obtener una IP, pero luego resulta que lo siguiente que hace es conectarse a <em>Ibl-app-eu.robotbona.com<\/em>, y enviar una petici\u00f3n POST a <em>baole-web\/common\/sumbitClearTime.do<\/em> con un formulario con el siguiente contenido (en realidad va en formato <em><a href=\"https:\/\/en.wikipedia.org\/wiki\/Percent-encoding\">URLEncode<\/a><\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">appKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>deviceId=yyyyyyyyyyyyyyy<br>deviceType=1<br>clearTime=0<\/pre>\n\n\n\n<p>Donde <em>xxxxxxx<\/em> e <em>yyyyyyy<\/em> son unas ristras de n\u00fameros hexadecimales que, probablemente, identifiquen a mi aspiradora. La respuesta es un OK con el siguiente texto:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">2b<br>{\"msg\":\"ok\",\"result\":\"0\",\"version\":\"1.0.0\"}<br>0<\/pre>\n\n\n\n<p>Que resulta ser un bloque en formato <em><a href=\"https:\/\/en.wikipedia.org\/wiki\/Chunked_transfer_encoding\">chunked<\/a><\/em> con un resultado en formato <a href=\"https:\/\/en.wikipedia.org\/wiki\/JSON\">JSON<\/a>. A continuaci\u00f3n otra conexi\u00f3n al mismo servidor, pero esta vez pidiendo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">appKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<br>authCode=zzzzz<br>deviceId=yyyyyyyyyyyyyy<br>deviceType=1<br>funDefine=11101<br>nonce_str=AAAAA<br>version={\"wifi\":\"1.0.48\",\"mcu\":\"3.9.1714(513)\"}<br>sign=SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS<\/pre>\n\n\n\n<p>Una vez m\u00e1s lo he anonimizado <em>just in case<\/em>. La respuesta es la misma que antes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">2b<br>{\"msg\":\"ok\",\"result\":\"0\",\"version\":\"1.0.0\"}<br>0<\/pre>\n\n\n\n<p>Hasta aqu\u00ed la aspiradora se ha conectado al puerto 80 del destino, lo que es consistente con el uso de REST. Sin embargo, ahora la aspiradora se conecta al puerto 20008 del destino, y comienza un intercambio de mensajes diferente. La siguiente petici\u00f3n desde la aspiradora es un bloque que comienza con una secuencia de 20 bytes binarios, seguidos por 349 bytes en ASCII en formato JSON (el JSON, en realidad, se transmite en una \u00fanica l\u00ednea y sin formato, pero lo he embellecido para mejorar la lectura. Si en alg\u00fan punto incluyese un LF, incluir\u00eda el s\u00edmbolo <strong>\\n<\/strong>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">71 01 00 00 | 10 00 00 00 | 01 00 00 00 | 02 00 00 00 | 00 00 00 00\n{\n  \"version\":\"1.0\",\n  \"control\":{\n    \"targetId\":\"0\",\n    \"targetType\":\"6\",\n    \"broadcast\":\"0\"\n  },\n  \"value\":{\n    \"token\":\"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n    \"deviceId\":\"yyyyyyyyyyyyyy\",\n    \"appKey\":\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n    \"deviceType\":\"1\",\n    \"authCode\":\"zzzzz\",\n    \"deviceIp\":\"192.168.18.3\",\n    \"devicePort\":\"8888\",\n    \"firmwareVer\":\"{\\\"wifi\\\":\\\"1.0.48\\\",\\\"mcu\\\":\\\"3.9.1714(513)\\\"}\"\n  }\n}<\/pre>\n\n\n\n<p>Aqu\u00ed ya empieza a haber cosas interesantes: la aspiradora comunica al servidor cual es la IP interna y el puerto que ha abierto para comunicarse. Estos datos son importantes para la <em>app<\/em>. Se repiten los campos <em>deviceId<\/em>, <em>appKey<\/em> y <em>authCode<\/em> de mensajes anteriores, pero ahora se a\u00f1ade un <em>token<\/em>.<\/p>\n\n\n\n<p>La respuesta tambi\u00e9n es complicada. En este caso es de 99 bytes, y comienza tambi\u00e9n con una ristra de 20 valores binarios, seguido de 79 bytes con un JSON normal:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">63 00 00 00 | 11 00 c8 00 | 01 00 00 00 | 02 00 00 00 | 00 00 00 00\n{\n   \"msg\":\"login succeed\",\n   \"result\":0,\n   \"version\":\"1.0\",\n   \"time\":\"2020-06-21-04-59-39\"\n}<\/pre>\n\n\n\n<p>En el primer mensaje, los dos primeros bytes en formato<a href=\"https:\/\/en.wikipedia.org\/wiki\/Endianness\"> little endian<\/a> forman el n\u00famero 369, que coincide con la suma de los 20 bytes binarios y los 349 bytes de JSON. En el segundo mensaje, los dos primeros bytes coincide con 99 en decimal, por lo que parece que, como m\u00ednimo, los dos primeros bytes indican el tama\u00f1o de la respuesta, probablemente para poder reservar la cantidad de memoria que necesite en el momento, y no tener que reservar de m\u00e1s, o ampliando bloques. \u00bfQu\u00e9 significan el resto de bytes? De momento no tenemos informaci\u00f3n suficiente para saberlo.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"114\" style=\"aspect-ratio: 200 \/ 114;\" width=\"200\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/dunno.mp4\"><\/video><\/figure>\n\n\n\n<p>Siguiente env\u00edo desde la aspiradora 444 bytes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">bc 01 00 00 | 18 00 00 00 | 01 00 00 00 | 03 00 00 00 | 00 00 00 00\n{\n  \"version\":\"1.0\",\n  \"control\": {\n    \"targetId\":\"0\",\n    \"targetType\":\"6\",\n    \"broadcast\":\"0\"\n  },\n  \"value\": {\n    \"noteCmd\":\"102\",\n    \"workState\":\"6\",\n    \"workMode\":\"0\",\n    \"fan\":\"1\",\n    \"direction\":\"0\",\n    \"brush\":\"2\",\n    \"battery\":\"100\",\n    \"voice\":\"2\",\n    \"error\":\"0\",\n    \"standbyMode\":\"1\",\n    \"waterTank\":\"40\",\n    \"clearComponent\":\"0\",\n    \"waterMark\":\"0\",\n    \"version\":\"3.9.1714(513)\",\n    \"attract\":\"0\",\n    \"deviceIp\":\"192.168.18.14\",\n    \"devicePort\":\"8888\",\n    \"cleanGoon\":\"2\",\n    \"extParam\":\"{\\\"cleanModule\\\":\\\"3\\\"}\"\n  }\n}<\/pre>\n\n\n\n<p>Y otra vez tenemos una mezcla binaria y ASCII, en este caso de 60 bytes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">3c 00 00 00 | 19 00 c8 00 | 01 00 00 00 | 03 00 00 00 | 01 00 00 00\n{\n  \"msg\":\"OK\",\n  \"result\":0,\n  \"version\":\"1.0\"\n}\\n<\/pre>\n\n\n\n<p>Esto nos confirma que, efectivamente, lo primero que recibimos es el tama\u00f1o de la respuesta completa.<\/p>\n\n\n\n<p><strong>Editado:<\/strong> faltaba un <strong>\\n<\/strong> al final del JSON.<\/p>\n\n\n\n<p>Ahora la aspiradora env\u00eda s\u00f3lo 20 bytes, lo que es s\u00f3lo la cabecera:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">14 00 00 00 | 00 01 c8 00 | 01 00 00 00 | 04 00 00 00 | e7 03 00 00<\/pre>\n\n\n\n<p>Y la respuesta del servidor es<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">14 00 00 00 | 11 01 c8 00 | 01 00 08 01 | 04 00 00 00 | e7 03 00 00<\/pre>\n\n\n\n<p>En este punto, la <em>app<\/em> se conecta a la aspiradora y empieza a intercambiar datos con este mismo formato, pero de momento vamos a dejar esa parte de lado, pues esta conexi\u00f3n con el servidor remoto sigue estando activa. De hecho, 30 segundos despu\u00e9s del env\u00edo anterior, la aspiradora env\u00eda de nuevo otra secuencia, en concreto:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">14 00 00 00 | 00 01 c8 00 | 01 00 00 00 | 05 00 00 00 | e7 03 00 00<\/pre>\n\n\n\n<p>Y la respuesta del servidor es<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">14 00 00 00 | 11 01 c8 00 | 01 00 08 01 | 05 00 00 00 | e7 03 00 00<\/pre>\n\n\n\n<p>Otra vez inactividad hasta que 30 segundos despu\u00e9s volvemos a tener otro paquete desde la aspiradora:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">14 00 00 00 | 00 01 c8 00 | 01 00 00 00 | 06 00 00 00 | e7 03 00 00<\/pre>\n\n\n\n<p>Y la respuesta del servidor es<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">14 00 00 00 | 11 01 c8 00 | 01 00 08 01 | 06 00 00 00 | e7 03 00 00<\/pre>\n\n\n\n<p>Lo interesante es que empieza a haber un patr\u00f3n aqu\u00ed. Si asumimos que son cinco n\u00fameros de cuatro bytes cada uno, el cuarto n\u00famero es un n\u00famero de secuencia: en efecto, comienza en 2 en la primera petici\u00f3n, y su respuesta tiene el 2 tambi\u00e9n. La siguiente petici\u00f3n tiene el valor 3, y su respuesta tambi\u00e9n. Luego viene el 4, y otra vez la respuesta, el 5 y otra vez la respuesta, el 6 y su respuesta&#8230; Adem\u00e1s, el resto de los n\u00fameros de las peticiones y respuestas 4, 5 y 6 son iguales, lo que hace suponer que se utilizan para mantener la conexi\u00f3n activa. Por otro lado, en las peticiones, el quinto byte tiene el bit 0 a cero, y en las respuestas est\u00e1n a uno. En el sexto byte, adem\u00e1s, el bit 0 est\u00e1 a cero en peticiones con datos, y a 1 en las que son s\u00f3lo para mantener la conexi\u00f3n.<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter meme\"><video height=\"182\" style=\"aspect-ratio: 250 \/ 182;\" width=\"250\" controls src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2020\/06\/austin-powers-yeah-baby.mp4\"><\/video><\/figure>\n\n\n\n<p>Veamos ahora qu\u00e9 pasa con la <em>app<\/em> en s\u00ed. Como ya dije, se conecta al puerto 8888, pero lo raro es que establece <em>dos<\/em> conexiones en vez de una. \u00bfPor qu\u00e9? Ni idea. Pero veamos con calma qu\u00e9 hace.<\/p>\n\n\n\n<p>En la primera conexi\u00f3n tenemos este intercambio, antes de que la aspiradora la cierre (<em>t<\/em> es tablet, <em>a<\/em> es aspiradora):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">t-&gt;a: 14 00 00 00 | 00 01 c8 00 | 00 00 01 00 | 1f 27 00 00 | 00 00 00 00\na-&gt;t: 14 00 00 00 | 11 01 c8 00 | 01 00 00 00 | 1f 27 00 00 | e7 03 00 00\nt-&gt;a: 14 00 00 00 | 00 01 c8 00 | 00 00 01 00 | 1f 27 00 00 | 00 00 00 00<\/pre>\n\n\n\n<p>En la segunda conexi\u00f3n se intercambian estos datos:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">t-&gt;a: 14 00 00 00 | 00 01 c8 00 | 00 00 01 00 | 1f 27 00 00 | 00 00 00 00\na-&gt;t: 14 00 00 00 | 11 01 c8 00 | 01 00 00 00 | 1f 27 00 00 | e7 03 00 00\nt-&gt;a: 14 00 00 00 | 00 01 c8 00 | 00 00 01 00 | 1f 27 00 00 | 00 00 00 00\na-&gt;t: 14 00 00 00 | 11 01 c8 00 | 01 00 00 00 | 1f 27 00 00 | e7 03 00 00\nt-&gt;a: 14 00 00 00 | 00 01 c8 00 | 00 00 01 00 | 1f 27 00 00 | 00 00 00 00\na-&gt;t: 14 00 00 00 | 11 01 c8 00 | 01 00 00 00 | 1f 27 00 00 | e7 03 00 00\nt-&gt;a: 14 00 00 00 | 00 01 c8 00 | 00 00 01 00 | 1f 27 00 00 | 00 00 00 00\na-&gt;t: 14 00 00 00 | 11 01 c8 00 | 01 00 00 00 | 1f 27 00 00 | e7 03 00 00\nt-&gt;a: 14 00 00 00 | 00 01 c8 00 | 00 00 01 00 | 1f 27 00 00 | 00 00 00 00<\/pre>\n\n\n\n<p>O sea, m\u00e1s o menos lo mismo. De aqu\u00ed no puedo sacar mucha informaci\u00f3n.<\/p>\n\n\n\n<p>Hasta aqu\u00ed la primera parte. Ahora toca empezar a hacer pruebas para intentar descubrir c\u00f3mo dar \u00f3rdenes a la aspiradora.<\/p>\n\n\n\n<p><a href=\"https:\/\/blog.rastersoft.com\/?p=2404\">Parte 2<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Actualizado: varios comandos de servidor a aspiradora terminaban con un LF (o sea, \\n). A\u00f1adidos. Recientemente decid\u00ed comprarme un aspirador rob\u00f3tico, as\u00ed que empec\u00e9 a ver opciones. Es cierto que, siendo el primero, no quer\u00eda gastarme mucho por si no me convenc\u00eda, pero a la vez no quer\u00eda tampoco comprar algo cutre que luego no &hellip; <a href=\"https:\/\/blog.rastersoft.com\/?p=2324\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">A ritmo de conga (1)<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,16,7],"tags":[],"class_list":["post-2324","post","type-post","status-publish","format-standard","hentry","category-cacharreo","category-opendonita","category-tutoriales"],"_links":{"self":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2324"}],"version-history":[{"count":61,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2324\/revisions"}],"predecessor-version":[{"id":2609,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2324\/revisions\/2609"}],"wp:attachment":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}