こんにちは。去る11月8日に、BadUSB体験会という社内勉強会を開催しましたのでその内容を簡単に紹介します。
(KLab Advent Calendar 2016 の2日目の記事になります)
概要
BadUSBとはUSBメモリのファームウェアを書き換えてHIDデバイスとして動作させ、任意のキー入力を行う攻撃手法の事なのですが、今回はその攻撃手法の 「任意のキー入力を行うHIDデバイス」
という部分を自作してみる事で、この攻撃について学んでみます。
デバイスの入手
任意のキー入力を行うHIDデバイスの作り方には様々な方法があり、PS/2キーボードの通信プロトコルを実装してUSB -> PS/2変換アダプタを通す などの手法がありますが、現状もっとも手軽な方法としては、 キーボード操作を行えるArduinoを利用する方法があります。
Arduino には標準で、キーボードとマウスを操作するライブラリが用意されており、 ATmega32U4 というチップがのっている Arduino であれば、2,3行のコードを書き込むだけでキー入力を行うことができます。1
今回は、Arduino互換機である CJMCU beetle を利用しました。完成品の状態で到着し、はんだ付けや、部品の用意をしなくてもすぐに利用できる上に、デバイス本体が非常に小さいため、USBメモリの殻をかぶせるなどの加工がしやすく、実際の攻撃をイメージしやすいからです。
Arduino IDE を利用して デバイス(Arduino) にコードをアップロードする
デバイスにコードを書き込むには、Arduino IDE を使います。 Arduino IDE は 公式サイト からダウンロードできます。 Windowsユーザーの方は 最近 Windows Storeから落とせるようになったのでそっちを使うとお手軽でよいです2
ダウンロードが完了したらWindowsならzip展開してarduino.exeを、MacならArduino.appを起動してください。
プログラムを書き込むためには、書き込み対象の Arduino のボード指定と、デバイスがつながっているシリアルポートの指定が必要です。
ボードの指定
今回利用している CJMCU beetle は Arduino Leonardo の互換機なので、ボードは Arduino Leonardo を設定します。
シリアルポートの指定
シリアルポートのCOM番号は、各々の環境によって異なるので、一覧の中から Arduino Leonardo と書かれているものを選択してください。
コードのアップロード
ボードとシリアルポートの設定ができたら、コードを書いてアップロードします。
動作テストとして、以下のコードをコピペし、[スケッチ]から[マイコンボードに書き込む]を選択して書き込んでください。3
コードの書き込みに成功すると、カーソルがわずかに震えます。MacとWindowsでカーソルの移動量が微妙に違うみたいなので、動かない場合は2や-2を4や-4などの大きい数字に変更してみてください(あまり大きい値にすると、プログラムの上書きができなくなるので注意してください)
#include <Mouse.h>
void setup() {
Mouse.begin();
}
void loop() {
Mouse.move(2, 2);
delay(25);
Mouse.move(0, 0);
delay(25);
Mouse.move(-2, -2);
delay(25);
Mouse.move(0,0);
delay(25);
}
Arduino でコードを書く時の基本(setup()とloop()関数)
Arduinoでコードを書く時はsetup()とloop()を作り、その中に処理を描いていきます。
setup()関数は、Arduinoが起動したときに一度だけ呼ばれる関数で、loop()関数はsetup()関数が実装されたあとに文字通りループでずっとよばれる関数です。
以下のプログラムは、Arduinoに同梱されているLEDの点滅を行うプログラムですが、setup()の中で、LEDのピン出力を有効にし、その後実行されるloop()中で1秒ごとにLEDへの出力をON/OFFしています。
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
キーボードの基本操作
Arduino を HIDデバイスとして認識させ、キー入力を行うには まず keyboard.h を読み込んだあと、 Keyboard.begin() を呼び出して初期化を行い、Keyboard.print() などのメソッドを利用してキー入力を行うという手順になります。
以下のメソッドがわかっていればだいたいのキー入力は可能になると思います。
- Keyboard.print(キー) // 引数にいれた文字列を入力する
- Keyboard.println(キー) // printと同じで最後に改行する(returnを押す)
- Keyboard.press(キーコード) // 指定キーコードのキーを押し込む。モディファイアキーを入力する時に使う。
- Keyboard.releaseAll() // 押し込んだすべてのキーを離す。
体験会のなかでうまれたコードの紹介
以下のコードは、体験会の参加者の方が実際に作ったものなのですが、Macに刺すとPCがシャットダウンします。便利ですね。
#include "Keyboard.h"
void setup() {
Keyboard.begin();
delay(500);
Keyboard.press(KEY_LEFT_CTRL);
delay(200);
Keyboard.press(KEY_F2);
Keyboard.releaseAll();
delay(200);
for (int i=0; i <= 8; i++) {
Keyboard.press(KEY_DOWN_ARROW);
Keyboard.releaseAll();
delay(200);
}
Keyboard.press(KEY_RETURN);
Keyboard.releaseAll();
}
void loop() {
}
体験会では、「すべてのコードをsetup()に書いて、loop()には書かないように」というルールにしました。setup()内であれば、差し込んでから一度しか呼ばれないのでどんなコードを書いても一度実行したあとは動かなくなるので、動かなくなったあとにプログラム書き換えをすればよいですが、loop()内に書いてしまうと、ずっと動き続けるので、プログラムを書き換える事自体難しくなってしまいます。
まとめ
- 「任意のキー入力を行うHIDデバイス」を作るのはとても簡単
- 自分のものではないUSBデバイスを安易に差し込むのはやめよう
32U4がのっているArduinoさえあれば誰でも簡単に試せるので興味のある方は是非チャレンジしてみてください。
-
すべてのArduinoがこのライブラリを利用できるわけではない事に注意してください。例えば一番メジャーな Arduino Uno は 328P というチップなのでこのライブラリを利用する事はできません ↩
-
バージョン更新がちょっと遅いみたいですが… ↩
-
今回は CJMCU beetle を10個購入したのですが、そのうちの3つがbootloaderの書き込みに失敗しており、シリアルポートが見つからなかったり書き込みが100%失敗する状態になっていました。AVRISP mk2でbootloaderを書き込んだら問題なく動いたのですが、そのようなトラブルに対処できないのであればArduino Leonardoで試してみるといいかもしれません ↩