Anti-ROP祭りだぜ!USENIX Security2014 ROP: Return of the %edi
この記事はシステム系論文紹介 Advent Calendar 2014 21日目として書かれました。ん、今日は大晦日?えっなんだって?
はじめに
こんばんは。
Dを単位取得退学(自称)して就職し、今は東京の片隅で毎日パワポを作っています、id:yuzuharaです。
そんなことはさておき、今年のUSENIX SecurityではなんとROPに関する研究が4つもacceptされており、ROP: Return of the %ediというスターウォーズのタイトルをもじったセッションがありました。
- ROP is Still Dangerous: Breaking Modern Defenses [N. Carlini et al.]
- Size Does Matter: Why Using Gadget-Chain Length to Prevent Code-Reuse Attacks is Hard [E. Goktas et al.]
- Oxymoron: Making Fine-Grained Memory Randomization Practical by Allowing Code Sharing [M. Backes et al.]
- Stitching the Gadgets: On the Ineffectiveness of Coarse-Grained Control-Flow Integrity Protection [L. Davi et al.]
せっかくなのでこのセッション全体をざっくり紹介し、今Anti-ROP界隈がアツいぜ!というのを共有できればいいなと思います。
不正実行とそれに対する防御の歴史
ROPの話をする前に、いわゆるソフトウェアセキュリティ一般の話をざっと概略してみます。とりあえず、今までにどのような不正実行のテクニックがあり、それを防御する仕組みが採用されてきたか、というのを簡単に時系列にしてみました。代表的なものだけリストアップしています。
- (攻)Stack overflow
- (防)Stack smashing Protection
- (攻)Heap overflow
- (防)Data Execution Prevention(DEP) [Microsoft 2004]
- (攻)Return to Libc
- (防) Address space layout Randomization (SLR) [2005?-]
- (攻)Return oriented programming [SHACHAM H, CCS’07]
- (防)Control-flow integrity [M Abadi, CCS’05]
- (攻)Jump Oriented programming
- (防)Branch History Inspection(kBouncer)[V.Pappas et.al., SEC’13]
- (攻)Sigreturn Oriented programming [E Bosmon, Oakland’14]
※攻撃(attack)の対義語は防御(defense)です。
なんというか、10年間で攻撃手法も保護も大きく変わりましたね・・・
ROP 防御の最新研究
kBouncer [V. Pappas et al., USENIX Security’13]
LBR(Last Branch Record)を使い、APIの呼び出し経路をチェックする方法が提案されています。この分岐ログを使った検知方法は、今回の4つの論文に大きな影響を与えています。ROPecker [Y. Cheng et.al., NDSS'14]
kBouncerのようなLBRを使ったROP検出と合わせて、メモリを4,8KBのセグメントに区切り、そのブロックを越えるindirect jumpのチェインが一定数以上だとROPと見なす手法を提案しています。要するに、jumpの ”距離”に注目したROP検出です。
ただし、この”距離”のしきい値が経験的な値であり、ぬけ穴であるという検証が、次に出てくる論文で行われています。しかし、サイクル早すぎだろオマエら。
イカしたAnti-ROP論文紹介するぜ!
ROP is Still Dangerous: Breaking Modern Defenses
この論文ではまず、既存のROP検出技術に対する3つの攻撃原理を定義しています。
- Call-Preceded ROP
普通のプログラムなら、retの戻りアドレスの一つ前の命令はcallのはず、というチェックをしているROP guardは多い。kBouncerがそれにあたる。70KB以上のUbuntuのシステムプログラムを解析したら、70KBより大きいプログラムは10個中10個そういうgadgetが見つかった。回避余裕でした。 - Evasion Attacks
実行中のコードはROP Gadgetなのか、正常なコードの断片なのか?の判定基準は難しい。実行している命令のセグメントが短く飛び飛びに実行していればROPと判断する方法があるが、ROP Gadgetのサイズが大きいものがあると意味が無い。 - History Flushing分岐命令の履歴を使ってindirect jump元がROPガジェットぽかったら検知というロジックもあるが、no-opな命令実行で埋め尽くせば、検知しづらくできる。
結論
この論文では、kBouncerとROPeckerそれぞれに対し、上記のprimitivesに対応するROP攻撃を行っています。そしてkBouncer、ROPecker共に突破できたと報告があります。そして次に、kBouncer、ROPeckerを改良して、突破されないようにできた、とありました。しかしそれでも、長いROPガジェットがある場合は、提案手法でも検知できないそうです。
Size Does Matter: Why Using Gadget-Chain Length to Prevent Code-Reuse Attacks is Hard
過去に提案されているROP defenses(kBouncer, ROPecker)では、ROP gadgetのサイズと、chain数のしきい値に経験的な値を使っています。この研究では、IE8でASLR, DEP, kBouncerを回避するROPを作れるか検証しています。どうも長いROP gadgetが普通にあったのでそれを使ったらしいです。長いROP gadgetを使うと、こういう経験的なしきい値に基づくROP検知は余裕で突破できてしまうようです。
この論文のコントリビューションは、新しい仕組みではなく、既存の手法と、リアルな環境とアプリケーションでの検証にある、というところっぽいです。しかし、USENIX Securityではなかなか珍しいタイプの論文ではないでしょうか?(IEEE S&Pとかだと絶対通らなさそう)
Oxymoron: Making Fine-Grained Memory Randomization Practical by Allowing Code Sharing
共有ライブラリのメモリランダマイズには限界があります。しかも、サイズが大きく、ROP gadgetを作るときによく使われてしまいます。この研究では、ASLRをより効果的に行うため、共有ライブラリを分割するバイナリ変換ツールを作成しています。
いくつかの関数ごとに分割し、読み込まれるアドレスを連続では無くすることで、関数のアドレスの予測可能性を下げています。関数呼び出し時は、間接呼び出しテーブルを使って、共有ライブラリ中の関数のアドレスを解決するようです。
Stitching the Gadgets: On the Ineffectiveness of Coarse-Grained Control-Flow Integrity Protection | USENIX
“Practical” control flow integrity(CFI)がホットトピックであると言っています(本当か?)kBouncerや、ROP Guard(MS EMET)などは、Practical CFIだそうです(本当かよ?)
この論文の貢献は、ROP検知の手法を整理し、その上でEMETのような粗いCFIを簡単に突破できてしまうことを実証したことにあるようです。その実証ということで、既存のPractical CFIで実行できる1MB以下のプログラム(共有ライブラリ)でTuring-completenessなROPを構築し、回避することができたとあります。
まとめ
- 今、Anti-ROPがアツい
- リアルアプリケーションでの検証が必須
- ホットトピックはサイクルが短い
(kBouncerがUSENIX SEC’13、ROPeckerに至ってはNDSS’14!)
あとがき
ということで、ざっとAnti-ROPセッションを紹介しました。セキュリティの研究者はここ10年で伸びており、USENIX Securityもコミュニティの広がりを考慮し、採択する論文を多くするという方針を採っているそうです。博士が取れないとかクサってる場合じゃねぇ!論文書いてトップカンファレンス通さなきゃ!
ということで、来年も研究頑張るぞい!