
ZyxelルーターのファームウェアとMIPSアーキテクチャを掘り下げて楽しもう
チュートリアルは情報提供および教育目的のみです。私は、デジタル情報やコンピュータを利用するすべての人にとって、倫理的ハッキング、情報セキュリティ、サイバーセキュリティが身近なテーマであるべきだと考えています。ハッカーから身を守るには、ハッキングがどのように行われるかを知らなければ不可能だと考えています。
$ IDA Pro +7.0(IDAは非常に高価なので、Radar2を使用することもできます)
$ Rompager 4.07を実行しているルーター:TP-Link TD-W8951*、ZyXEL P-660R、Billion BiPAC 51**/52**など、膨大な数が存在します
$ UART to USB
ミスフォーチュンクッキーの脆弱性はしばらく前から存在していましたが、その技術的詳細を一般に示した分析はまだ不足しています。Check Pointによると、影響を受けるソフトウェアはAllegroSoftの組み込みWebサーバーRomPagerです。インターネット全体のスキャンによると、RomPagerは利用可能なエンドポイントの数に関して、世界で最も人気のあるWebサーバーソフトウェアである可能性があります。RomPagerは通常、デバイスに付属するファームウェアに組み込まれています。この特定の脆弱性は2002年にコードベースに導入されました。さらに、影響を受けるデバイスは、バージョン4.34より前(特に4.07)のRomPagerサービスを使用しているものです。
このチュートリアルでは、Rompager 4.07を使用するZXHN H108Lを使用します。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="ZXHN H108L"
Content-Type: text/html
Transfer-Encoding: chunked
Server: RomPager/4.07 UPnP/1.0
EXT:
それではシリアルポートを使用しましょう。まずボーレートを特定する必要があります。
$ sudo stty -F /dev/ttyUSB0
出力:
speed 115200 baud; line = 0;
-brkint -imaxbel
デバイス
私は minicom を使用しています。screen から HyperTerminal まで何でも使えますが、安定性の面でこれが好みです。
$ sudo minicom -s
+-----------------------------------------------------------------------+
| A - シリアルデバイス : /dev/modem |
| B - ロックファイルの場所 : /var/lock |
| C - 発呼プログラム : |
| D - 応答プログラム : |
| E - Bps/パリティ/ビット : 115200 8N1 |
| F - ハードウェアフロー制御 : いいえ |
| G - ソフトウェアフロー制御 : いいえ |
| |
| どの設定を変更しますか? |
+-----------------------------------------------------------------------+
| 画面とキーボード |
| 設定をdflとして保存 |
| 名前を付けて保存.. |
| 終了 |
| Minicomを終了 |
+--------------------------+
これで準備完了です:
$ sudo minicom -D /dev/ttyUSB0 -b 115200
Bootbase Version: VTC_SPI1.26 | 2012/12/26 16:00:00
RAM: Size = 8192 Kbytes
Found SPI Flash 2MiB GD25Q16 at 0xbfc00000
SPI Flash Quad Enable
Turn off Quad Mode
RAS Version: ZXHN H108LV4.0.0a_ZRQ_MA
System ID: $2.12.162.0(G94.BY.2)3.20.19.0| 2014/03/21 20140321_v006 | 2014
Press any key to enter debug mode within 3 seconds.
..........
使用可能なコマンドを表示するには:
$ ATHE
======= デバッグコマンド一覧 =======
AT 単にOKを返答
ATHE ヘルプを表示
ATBAx ボーレートを変更。1:38.4k, 2:19.2k, 3:9.6k 4:57.6k 5:115.2k
ATENx,(y) BootExtensionデバッグフラグを設定 (y=パスワード)
ATSE パスワードジェネレータのシードを表示
ATTI(h,m,s) システム時刻を時:分:秒に変更、または現在時刻を表示
ATDA(y,m,d) システム日付を年/月/日に変更、または現在日付を表示
ATDS RASスタックをダンプ
ATDT ブートモジュール共通領域をダンプ
ATDUx,y アドレスxから長さy分のメモリ内容をダンプ
ATRBx アドレスxの8ビット値を表示
ATRWx アドレスxの16ビット値を表示
ATRLx アドレスxの32ビット値を表示
ATGO(x) アドレスxでプログラムを実行、またはルーターを起動
ATGR ルーターを起動
ATGT ハードウェアテストプログラムを実行
ATRTw,x,y(,z) RAMテストレベルw、アドレスxからyまで(z回反復)
ATSH ROM内の製造元関連データをダンプ
ATDOx,y アドレスxから長さyまでをXMODEMでPCにダウンロード
ATTD ルーター設定をXMODEMでPCにダウンロード
ATUR ルーターファームウェアをフラッシュROMにアップロード
< 任意のキーを押して続行 >
このファームウェアには、動的分析に非常に役立つ隠しコマンドのセットがあります。問題はレジスタを表示したりブレークポイントを設定できないことですが、幸いにもこれらの隠しコマンドを使用すればその機能が得られます。それらを表示して使用するには、ATEN を使用する必要があります。ただし、このコマンドにはパスワードが必要です。ではどうすればよいでしょうか? ファームウェアをリバースエンジニアリングして、パスワードジェネレータのアルゴリズムを見つけましょう。
(静的解析) まずファームウェアファイルを見てみましょう:
$ binwalk ras
binwalk1
$ dd if=ras of=rom1.lzma bs=1 skip=85043 count=66696
$ dd if=ras of=rom2.lzma bs=1 skip=350259 count=3350556
$ lzma -d <rom1.lzma> rom1
$ lzma -d <rom2.lzma> rom2
抽出したファイルのシグネチャを見てみましょう:
$ binwalk -Y rom1
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 MIPS executable code, 32/64-bit, big endian, at least 1250 valid instructions
string はバイナリファイルが何であるか、または何を含んでいるかの概要を得るのに優れたツールです。パスワードアルゴリズムが見つかるかどうか見てみましょう:
$ strings rom1 | grep -i aten
$ strings rom2 | grep -i aten
どうやらファームウェアはまだ圧縮されているため見つかりません。つまり、デバッグモードを使用してルーターからダンプする必要があります:
$ ATDO bfc00000, 1f0000
xmodem
最初に思い浮かぶのは、ディスパッチテーブルを探し始めることです。なぜなら?単なる直感です。唯一の代替案は if-elif ですが、それらは長いセットになるでしょう。ユーザーが提供したパスワードの有効性を確認するために、以下の結果を得ました:
ROM:800158A0 CmdTable: .word unk_80015C20 # DATA XREF: sub_8000E3D8+4Co
ROM:800158A0 # sub_8000E3D8+90o ...
ROM:800158A4 .word sub_8000E6D0
ROM:800158A8 .byte 0
ROM:800158A9 .byte 0
ROM:800158AA .byte 0
ROM:800158AB .byte 0
ROM:800158AC .word aJustAnswerOk # " just answer OK"
ROM:800158B0 .word aAthe # "ATHE"
ROM:800158B4 .word CMD_SHOW_HELP_ATHE
ROM:800158B8 .byte 0
ROM:800158B9 .byte 0
ROM:800158BA .byte 0
ROM:800158BB .byte 0
ROM:800158BC .word aPrintHelp # " print help"
ROM:800158C0 .word aAtba # "ATBA"
ROM:800158C4 .word CMD_ATBA
...
ROM:800158D0 .word aAten # "ATEN"
ROM:800158D4 .word CMD_ATEN
MIPSのワードは4バイトであることに注意してください。では CMD_ATEN を見てみましょう:
ROM:8000FF84 lw $a0, 8($s0)
ROM:8000FF88 jal sub_80013654
ROM:8000FF8C li $a1, 0
ROM:8000FF90 jal passwd_generator
そして passwd_generator:
ROM:80010A2C passwd_generator: # CODE XREF: CMD_ATEN+50p
ROM:80010A2C lui $t9, 0xA11F
ROM:80010A30 lw $v1, ptrDO_GTABLE
ROM:80010A34 lw $t8, dword_80017050
ROM:80010A38 lw $v1, 0x18($v1) # シード部分を取得、ATSEコマンドで生成される
ROM:80010A3C lbu $t8, 0x6D($t8) # MACアドレスの最終バイトを取得
ROM:80010A40 sll $v1, 8 # $v1 = v1 << 8
ROM:80010A44 andi $t7, $t8, 7 # $t7 = t8 & 0x7
ROM:80010A48 li $t8, 0 # $t8 = 0
ROM:80010A4C srl $v1, 8 # $v1 = v1 >> 8
ROM:80010A50 li $t9, 0xA11F5AC6 # $t9 = MAGIC
ROM:80010A54 j loc_80010A68
ROM:80010A58 addu $t9, $v1, $t9 # $t9 = $v1 + $t9
ROM:80010A5C # ---------------------------------------------------------------------------
ROM:80010A5C
ROM:80010A5C loc_80010A5C: # CODE XREF: passwd_generator+40j
ROM:80010A5C sll $t9, 31 # $t9 = $t9 << 31
ROM:80010A60 or $t9, $t6, $t9 # $t9 = $t6 | $t9
ROM:80010A64 addiu $t8, 1 # $t8 = $t8 + 1
ROM:80010A68
ROM:80010A68 loc_80010A68: # CODE XREF: passwd_generator+28j
ROM:80010A68 sltu $t6, $t8, $t7 # $t6 = (t8 < t7? 1:0)
ROM:80010A6C bnez $t6, loc_80010A5C # $t6 != 0 ならジャンプ
ROM:80010A70 srl $t6, $t9, 1 # $t6 = $t9 >> 1
ROM:80010A74 jr $ra # 完了、終了
ROM:80010A78 xor $v0, $t9, $v1 # $v0 = $t9 ^ $v1
結論:
では、同じことを行うCプログラムを作成してコンパイルしましょう:
U32 passwd_generator(U32 seed, U8 last_mac_octet)
{
U32 b = seed & 0x00FFFFFF;
U32 r = ROR(b + 0xA11F5AC6, last_mac_octet & 7);
return r^b;
}
では ATSE を実行してシードを取得し、それを使用します (例: 088521A78838 を取得):
$ ./gen_pass 088521A78838
今度は、私たちがハックした魔法のコマンドを実行しましょう :p
$ ATEN1, A12F5AC6
ATEN1, A12F5AC6
OK
ATHE
======= デバッグコマンド一覧 =======
AT 単にOKを返答
ATHE ヘルプを表示
ATBAx ボーレートを変更。1:38.4k, 2:19.2k, 3:9.6k 4:57.6k 5:115.2k
ATENx,(y) BootExtensionデバッグフラグを設定 (y=パスワード)
ATSE パスワードジェネレータのシードを表示
ATTI(h,m,s) システム時刻を時:分:秒に変更、または現在時刻を表示
ATDA(y,m,d) システム日付を年/月/日に変更、または現在日付を表示
ATDS RASスタックをダンプ
ATDT ブートモジュール共通領域をダンプ
ATDUx,y アドレスxから長さy分のメモリ内容をダンプ
ATWBx,y アドレスxに8ビット値yを書き込み
ATWWx,y アドレスxに16ビット値yを書き込み
ATWLx,y アドレスxに32ビット値yを書き込み
ATRBx アドレスxの8ビット値を表示
ATRWx アドレスxの16ビット値を表示
ATRLx アドレスxの32ビット値を表示
ATGO(x) アドレスxでプログラムを実行、またはルーターを起動
ATGR ルーターを起動
ATGT ハードウェアテストプログラムを実行
AT%Tx 起動時にハードウェアテストプログラムを有効にする
ATBTx block0 write enable (1=有効, その他=無効)
< 任意のキーを押して続行 >
ATRTw,x,y(,z) RAMテストレベルw、アドレスxからyまで(z回反復)
ATWEa(,b,c,d) MACアドレス、国コード、EngDbgFlag、FeatureBitをフラッシュROMに書き込み
ATCUx 国コードをフラッシュROMに書き込み
ATCB フラッシュROMからワーキングバッファにコピー
ATCL ワーキングバッファをクリア
ATSB ワーキングバッファをフラッシュROMに保存
ATBU ワーキングバッファ内の製造元関連データをダンプ
ATSH ROM内の製造元関連データをダンプ
ATWMx ワーキングバッファ内のMACアドレス下位6桁を設定
ATMHx ワーキングバッファ内のMACアドレス上位6桁を設定
ATBS パスワードジェネレータのブートベースシードを表示
ATLBx xmodemでブートベースをアップロード、xはパスワード
ATSMx ワーキングバッファ内のMACアドレス6桁を設定
ATCOx ワーキングバッファ内の国コードを設定
ATFLx ワーキングバッファ内のEngDebugFlagを設定
ATSTx ワーキングバッファ内のROMRASアドレスを設定
ATSYx ワーキングバッファ内のシステムタイプを設定
ATVDx ワーキングバッファ内のベンダー名を設定
ATPNx ワーキングバッファ内の製品名を設定
ATFEx,y,... ワーキングバッファ内のフィーチャービットを設定
ATMP メモリマップテーブルの確認とダンプ
ATDOx,y アドレスxから長さyまでをXMODEMでPCにダウンロード
< 任意のキーを押して続行 >
ATTD ルーター設定をXMODEMでPCにダウンロード
ATUPx,y XMODEMでPCからRAMアドレスxに長さyのデータをアップロード
ATUR ルーターファームウェアをフラッシュROMにアップロード
ATDC ファームウェアアップロード中にハードウェアバージョンチェックを無効化
ATLC ルーター設定ファイルをフラッシュROMにアップロード
ATUXx(,y) フラッシュブロックxからyまでをXMODEMでアップロード
ATERx,y フラッシュROMのブロックxからyを消去
ATWFx,y,z アドレスxからデータをフラッシュアドレスyにコピー、長さz
ATXSx xmodem選択: x=0: CRCモード(デフォルト); x=1: チェックサムモード
ATLD 設定ファイルとデフォルトROMファイルをフラッシュにアップロード
ATBR デフォルトROMファイルにリセット
ATCD 実行中のROMファイルをフラッシュ内のデフォルトROMファイルに変換
OK
ついに、メモリをダンプできるまったく新しいコマンドセットを取得しました。
$ ATMP
ROMIO image start at bfc30000
code version:
code start: 80008000
code length: 1A5D4E
memMapTab: 18 entries, start = bfc44000, checksum = 9770
$RAM Section:
0: BootExt(RAMBOOT), start=80030000, len=18000
1: HTPCode(RAMCODE), start=80048000, len=E0000
2: RasCode(RAMCODE), start=80048000, len=420000
$ROM Section:
3: BootBas(ROMIMG), start=bfc28000, len=4000
4: DbgArea(ROMIMG), start=bfc2c000, len=2000
5: RomDir2(ROMDIR), start=bfc2e000, len=2000
6: BootExt(ROMIMG), start=bfc30030, len=13FD0
7: MemMapT(ROMMAP), start=bfc44000, len=C00
8: HTPCode(ROMBIN), start=bfc44c00, len=8000
(Compressed)
Version: HTP_TC V 0.05, start: bfc44c30
Length: 10488, Checksum: CB32
Compressed Length: 41CF, Checksum: D5A5
9: termcap(ROMIMG), start=bfc4cc00, len=400
10: RomDefa(ROMIMG), start=bfc4d000, len=2000
11: LedDefi(ROMIMG), start=bfc4f000, len=400
12: LogoImg(ROMIMG), start=bfc4f400, len=2000
13: LogoImg2(ROMIMG), start=bfc51400, len=2000
14: StrImag(ROMIMG), start=bfc53400, len=32000
15: StrImag2(ROMIMG), start=bfc85400, len=32000
16: Rt11nE2p(ROMIMG), start=bfcb7400, len=400
17: RasCode(ROMBIN), start=bfcb7800, len=246C00
(Compressed)
Version: ADSL ATU-R, start: bfcb7830
Length: 321D2C, Checksum: 582D
Compressed Length: 11E54B, Checksum: B30B
$USER Section:
Msecs 128
Heap0 16 300 16
Heap1 32 64 4
Heap2 64 64 4
Heap3 128 160 4
Heap4 192 256 4
Heap5 256 80 4
Heap6 320 20 4
Heap7 384 4 2
Heap8 448 20 2
Heap9 512 34 2
Heap10 1024 52 4
Heap11 2048 20 2
Heap12 3172 4 2
Heap13 4096 2 2
Heap14 0 0
...
ここで学んだことは、以前抽出したromファイルを分析するのに役立ちます。
code start: 80008000
code length: 1A5D4E
これで、新しいromファイルをダンプした後、ROM開始アドレス と ローディングアドレス を 0x80008000 に設定できます。以下のコマンドを使用します:
$ ATDO 80008000, 1A5D4E
ATGR がルーターを起動することがわかっているので、それを追跡して、実行をファームウェアの2番目の部分に渡す命令を見つけることができます。
atgr1
ROM:80011E8C loc_80011E8C: # CODE XREF: LoadAndRunImage+D8j
ROM:80011E8C jal sub_80009B24
ROM:80011E90 li $a0, 0x1F4
ROM:80011E94
ROM:80011E94 execute_image: # イメージを実行
ROM:80011E94 jalr $s0 # $s0のアドレスにジャンプしてリンク
ROM:80011E98 nop
では、$s0 に格納されているアドレスは何かと尋ねる必要があります。明らかに、ブレークポイントを設定することはできず、レジスタを表示することもできないため、何らかのトリックを使用してリークする必要があります。幸いなことに、メモリの読み取りと書き込みが可能です。次のコマンドを見てください:
ATWL 80011E94, ae30001c
ATGR
どうやら、このコマンドは命令 0x80011E94 を ae30001c (MIPS命令 sw $s0, 0x1C($s1) のバイト表現) でパッチします。元の jalr $s0 を sw $s0, 0x1C($s1) で上書きすることで、プログラムに $s0 レジスタの内容をメモリアドレス 0x8001FF1C に強制的に格納させました。これにより、ファームウェアの第2ステージは実行されず、代わりに "ERROR" メッセージが表示され、第1ステージコンソールへのアクセスは維持されます。やった! では、0x8001FF1C に何が格納されているか見てみましょう。
ATRL 8001FF1C
8001FF1C: 80020000
捕まえた! ... 0x80020000 を使用して、ファームウェアの第2部分をダンプし、適切に分析できます。
続く...