
Vulnerabilidades de inyección de teclado en presentadores inalámbricos
Tenía ganas de hacer un poco de ingeniería inversa de RF, así que pedí algunos clickers de presentación y me divertí un poco.
Esto es un fork de nrf-research-firmware (que escribí hace unos años en Bastille). He añadido soporte para algunos transceptores/protocolos nuevos, e incluido POCs de inyección de pulsaciones de teclado para 13 clickers de presentación comunes.
| Fabricante | Modelo | Protocolo | RFIC | Añadido |
|---|---|---|---|---|
| AmazonBasics | P-001 | AmazonBasics P-001 | nRF24 | 2019-04-20 |
| Canon | PR100-R | Canon PR100-R | PL1167 | 2019-04-20 |
| Funpick | Wireless Presenter | HS304 | HS304 | 2019-04-20 |
| AMERTEER | Wireless Presenter | HS304 | HS304 | 2019-04-20 |
| BEBONCOOL | D100 | HS304 | HS304 | 2019-04-20 |
| ESYWEN | Wireless Presenter | HS304 | HS304 | 2019-04-20 |
| Red Star Tech | PR-819 | HS304 | HS304 | 2019-04-20 |
| DinoFire | D06-DF-US | HS304 | HS304 | 2019-04-20 |
| TBBSC | DSIT-60 | TBBSC DSIT-60 | BK2451 | 2019-04-21 |
| Rii | Wireless Presenter | Rii Wireless Presenter | BK2451 | 2019-04-21 |
| Logitech | R400 | Logitech Unencrypted | nRF24 | 2019-04-21 |
| Logitech | R800 | Logitech Unencrypted | nRF24 | 2019-04-21 |
| Logitech | R500 | Logitech Encrypted | nRF24 | 2019-04-21 |
Este es el protocolo estándar de teclado Logitech cifrado, tal como lo usa el R500. Es, en cierto modo, vulnerable al ataque de “inyección de pulsaciones cifradas” que documenté con los teclados Logitech Unifying como parte del proyecto MouseJack.
Digo en cierto modo porque no todos los códigos de escaneo HID son aceptados. En concreto, 0x04-0x1D (A-Z) se reemplazan por 0x00 cuando el dongle envía la trama al ordenador anfitrión, lo que significa que podemos inyectar lo que queramos, siempre que no sea una letra. La otra excepción es que las combinaciones de teclas con ctrl sí están permitidas, incluso cuando incluyen letras.
Una inyección de pulsaciones eficaz a través del R500 requiere que seamos un poco creativos.
Supongamos que el objetivo está en una sesión de bash. En bash, podemos codificar nuestros caracteres en base-8, codificando los comandos que contienen letras y que queremos que el objetivo ejecute.
Por ejemplo, ping google.com se codifica como $'\160\151\156\147' $'\147\157\157\147\154\145\056\143\157\155'. Si enviamos esta cadena a una sesión de bash y después enviamos enter, el comando ping google.com se ejecutará en la máquina objetivo.
Puedes encontrar la dirección de tu Logitech R500 usando nrf24-scanner de la siguiente manera:
sudo ./tools/nrf24-scanner.py -c {2..74..3} -l
Los paquetes deberían verse así:
[2019-04-21 13:11:52.507] 62 5 85:D1:9D:FE:07 00:40:00:08:B8
[2019-04-21 13:11:52.515] 62 5 85:D1:9D:FE:07 00:40:00:08:B8
[2019-04-21 13:11:52.523] 62 22 85:D1:9D:FE:07 00:D3:4D:6F:B6:1B:E6:05:A2:B4:8B:98:F9:C2:00:00:00:00:00:00:00:81
La inyección es posible porque el dongle no aplica el incremento de los contadores AES, por lo que puedes reproducir paquetes. Un paquete enviado OTA se compone de una carga útil USB HID que ha sido cifrada en modo contador AES, seguida del contador. Cuando pulsas un botón en el clicker de presentación, este genera un paquete de tecla presionada y un paquete de tecla liberada. El paquete de tecla liberada son todo 0, lo que nos proporciona un material de clave limpio que podemos reutilizar, aplicar XOR con nuestra propia carga útil y enviarlo OTA.
No debería ser difícil automatizar el proceso de escuchar una pulsación de botón, extraer el segundo paquete (de tecla liberada) y usarlo automáticamente como referencia de material de clave. Pero soy perezoso, así que primero tendrás que capturar tú mismo una pulsación de botón, que se ve así:
[2019-04-21 16:02:56.451] 65 5 85:D1:9D:FE:07 00:40:00:08:B8
[2019-04-21 16:02:56.459] 65 5 85:D1:9D:FE:07 00:40:00:08:B8
[2019-04-21 16:02:56.468] 65 22 85:D1:9D:FE:07 00:D3:E6:7B:35:8C:BB:2C:7D:5B:8B:98:FA:76:00:00:00:00:00:00:00:B9
[2019-04-21 16:02:56.475] 65 5 85:D1:9D:FE:07 00:40:00:08:B8
[2019-04-21 16:02:56.507] 65 5 85:D1:9D:FE:07 00:40:00:08:B8
[2019-04-21 16:02:56.516] 65 22 85:D1:9D:FE:07 00:D3:99:D6:D3:8D:49:25:F5:4D:8B:98:FA:77:00:00:00:00:00:00:00:1A
[2019-04-21 16:02:56.524] 65 5 85:D1:9D:FE:07 00:40:00:08:B8
[2019-04-21 16:02:56.532] 65 5 85:D1:9D:FE:07 00:40:00:08:B8
El segundo paquete de 22 bytes es el paquete de tecla liberada.
Elimina el último byte de la carga útil y copia y pega la cadena en logitech.py, reemplazando KEYUP_REF.
(No debería funcionar sin actualizar KEYUP_REF, pero si funciona, ¡por favor házmelo saber!)
Inyecta la secuencia de pulsaciones codificada en base-8 del comando bash ping google.com en un dongle Logitech R500 concreto (dirección 85:D1:9D:FE:07):
sudo ./tools/r500-injector.py -l -a 85:D1:9D:FE:07
Este es el protocolo Logitech estándar sin cifrar, utilizado por el R400/R800.
Puedes encontrar la dirección de tu Logitech R400/R800 usando nrf24-scanner de la siguiente manera:
sudo ./tools/nrf24-scanner.py -c {2..74..3} -l
Los paquetes deberían verse así:
[2019-04-21 12:58:43.466] 32 0 9D:9E:95:52:07
[2019-04-21 12:58:43.620] 32 10 9D:9E:95:52:07 00:C1:00:00:00:00:00:00:00:3F
Inyecta la secuencia de pulsaciones de prueba en un dongle Logitech R400/R800 concreto (dirección 9D:9E:95:52:07):
sudo ./tools/preso-injector.py -l -f logitech -a 9D:9E:95:52:07
El Rii Wireless Presenter (bolígrafo redondeado) está basado en el BK2451 (que parece ser un clon del nRF24). Esto parece un protocolo genérico, dada la prevalencia de dispositivos hermanos, así que probablemente lo recategorice después de obtener más datos.
Es funcionalmente un teclado inalámbrico sin cifrar, vulnerable a la inyección de pulsaciones.