# HITCON CTF 2018 - Super Hexagon (Part 6/7) ###### tags: `trustzone` `ctf` `pwn` `ARM` `Aarch64`, `kernel` `hypervisor` # はじめに この記事は,[CTF Advent Calendar 2020](https://adventar.org/calendars/5338) の8日目の記事です. 7日目は私の「[HITCON CTF 2018 - Super Hexagon (Part 5/7)](https://hackmd.io/@bata24/By9QPlFMU)」でした. # リンク集 - Part1/7 (EL0) - https://hackmd.io/@bata24/HyMQI7PuB - Part2/7 (EL1) - https://hackmd.io/@bata24/HJMKyaDfI - Part3/7 (EL2) - https://hackmd.io/@bata24/S1bHxavMU - Part4/7 (S-EL0) - https://hackmd.io/@bata24/BJHBSc0g8 - Part5/7 (S-EL0別解) - https://hackmd.io/@bata24/By9QPlFMU - Part6/7 (S-EL1) - https://hackmd.io/@bata24/H1N-W6vf8 - Part7/7 (S-EL3) - https://hackmd.io/@bata24/HJhLZTvGI # S-EL1の攻略 ## S-EL1カーネルの解析 S-EL0の別解を解説する際に解析を終えているため,ここでは省略する. ### 脆弱性 #### 脆弱性1 ![](https://i.imgur.com/x96PoQS.png) ノーマルワールドから呼び出す割込経路①の,`sel1_mmap_world_shared_memory()`において,アドレス変換テーブルへマッピングを登録する処理があるが,ここに整数オーバーフローバグがある. ![](https://i.imgur.com/w2yKAXv.png) ![](https://i.imgur.com/txTXtid.png) `phys_addr`が`0x40000000`以下でないことのチェックは存在する.これはセキュアワールド用のメモリを,マッピング対象としないためのチェックである. ![](https://i.imgur.com/RJgFZP0.png) しかし`size`を加算したときに整数オーバーフローするケースが考慮されていない.つまり`sel1_mmap_world_shared_memory(0xFFFFF000, 0x2000)`を確保すると,物理メモリ`0x0~0x1000`がS-EL1のマッピングテーブルに登録されることになる. しかし実際にマッピングすると分かるが,S-EL3のメモリは`bios.bin`そのものであり,読み込み専用である.つまり仮にマッピングができても,実際に改変することはできない.またチーム`NASA Rejects`が検証しているが,この領域に書き込んでも特にSEGVなどのエラーは発生せずサイレントに実行が継続してしまうらしい. ```= gef> x/i $pc => 0x237d318: str r3, [r1] gef> x/xw $r1 0x237c80c: 0x91000042 gef> p $r3 $12 = 0x41414141 gef> stepi gef> x/xw $r1 0x237c80c: 0x91000042 ``` つまりこの脆弱性は,S-EL3のメモリをEL1から見えるようにマッピングするだけである.S-EL3に暗号鍵などが入っていれば嬉しいかもしれないが,今回の問題ではそういった機密情報はメモリ上になく,コードを改変できないと嬉しくないので,残念ながらこの脆弱性は使えない. #### 脆弱性2 割込経路②で設定されるSEGVのハンドラが,S-EL0とS-EL1を区別していない点が脆弱性である. 以下はSEGV発生時のハンドラだ.このハンドラはS-EL0のSEGVをハンドリングする目的で作られているが,実はS-EL1で発生したSEGVも同様にハンドリングする.なぜならS-EL0とS-EL1は割り込みベクタが同じだからだ. ![](https://i.imgur.com/tdyrrfG.png) ![](https://i.imgur.com/MaQQwXW.png) ![](https://i.imgur.com/JyvSy2T.png) ![](https://i.imgur.com/5Y25VIb.png) つまりS-EL0から`svc_sighandler()`を用いて`sel1_segv_restart_addr`にS-EL1シェルコードのアドレスを書き込んでおき,S-EL1でSEGVを発生させると,S-EL1はシェルコードのアドレスから再開するはずだ. #### 脆弱性3 割込経路①で呼び出される`sel1_load_trusted_app()`だが,`trustlet`のアドレスに対し,検証が不十分である. 具体的には,特定の範囲であることのチェックはされているが,確かに存在することの検証がされていない. ![](https://i.imgur.com/h8Yrac7.png) S-EL1では`0x2400000`から`0x2000000`へ向かって減算しながら仮想アドレスがマッピングされていくことを思い出そう. ![](https://i.imgur.com/0ZXxTsN.png) 従って`0x2000000`は基本的に最後まで使われない.つまりEL1からアドレス`0x2000000`を指定して`sel1_load_trusted_app()`を呼び出すと,まだその仮想アドレスには何もマッピングされていないので,SEGVが発生することになる. 本来はDoSにしかならずあまり使えない脆弱性ではあるが,脆弱性2と組み合わせることで効果を発揮する. ## 任意コード実行へ 今回はS-EL0の別解で利用した`exp_sel0-2.py`をベースにして攻略していく. S-EL0に偽造するチャンクは,下記のようにしておこう. ```= 0x237d000 +-----------------------------+ (used) | (prev_size) 0x00000000 | | size 0x00000021 | | (next) ... | | (prev) ... | 0x237d020 +-----------------------------+ (freed) | (prev_size) ... | | size 0x00000021 | | (next) 0x237d048+1 | | (prev) stack_addr | 0x237d040 +-----------------------------+ (don't care) | (prev_size) ... | | size 0x00000810 | 0x237d048 | (next) sel0_shellcode | ※shellcodeは0x400バイト固定とする | (prev) sel0_shellcode | | sel0_shellcode | | ... | 0x237d448 | sel1_shellcode | ※shellcodeは0x400バイト固定とする | sel1_shellcode | | sel1_shellcode | | ... | +-----------------------------+ ``` これでS-EL1から実行可能なメモリにシェルコードを用意できたことになる.後はSEGVを起こす方法だが,`sel1_load_trusted_app()`に`0x2000000`を渡して脆弱性3を発生させれば良い. :::spoiler Click {%gist bata24/59a33df9b8f3a3898127ce40647798f5 %} ::: ---- # 続く 明日は私の[HITCON CTF 2018 - Super Hexagon (Part 7/7)](https://hackmd.io/@bata24/HJhLZTvGI)です.(公開日になるまで閲覧できません)