【Houseシリーズ編】House of Force・Spiritでヒープを乗っ取る|CTF思考フレームワーク #64
こんにちは、アンペンです!
今回はHouseシリーズ──glibcヒープ攻撃の名門技集です。2007年Phrack 67号「Malloc Maleficarum」でPhantasmal Phantasmagoria氏が体系化したのが起源で、その後の研究者が新技を発見するたびに「House of ◯◯」と命名されてきた歴史があります。CTF Heap問題ではこれらの名前が共通語彙として飛び交うので、それぞれの『発想の核』を押さえておくと一気に読みやすくなります。
共通点は『malloc/freeのアルゴリズム仕様の隙を突いて、freeリストや内部メタデータを操る』こと。glibcバージョンごとに使える技が消滅したり新生したりするので、『どの技がどのバージョンで生きているか』のマッピングが実戦の鍵です。
『House of なんとか』がいくつも出てくると、それだけで身構えてしまいますよね。でも安心してください。これらは“流派の名前”のようなものです。剣術に流派があるように、ヒープ攻撃にも『この隙はこう突く』という名のついた型があるだけ。全部を暗記する必要はなく、『どの型が、ヒープのどの部分を狙うのか』という“地図”を持っておけば、CTFの解説を読むときに迷子になりません。

『House of 〇〇』って名前がいっぱいあるけど、関係あるの?

全部『malloc仕様の別々の隙』を突く独立した技。Force=top chunk弄り、Spirit=偽チャンク作成、Lore=small bin改竄、Orange=unsorted bin attack。条件と前提が違うから、問題に応じて使い分けになるよ。
Houseシリーズの代表4種:(1)House of Force(top chunkのsizeをBoFで巨大化→巨大malloc要求で任意アドレスを切り出す/glibc 2.29で殺された)、(2)House of Spirit(スタック等に偽チャンクヘッダを作りfreeしてtcache/fastbinに食わせる)、(3)House of Lore(small binの双方向リストを偽造して任意malloc)、(4)House of Orange(top chunkの整理に乗じてunsorted bin attack→任意書込)。現代の主流はIO_FILE系(_IO_2_1_stdout_のvtable改竄)とHouse of Rust。glibcバージョンと技の対応を常に確認。
この記事で分かること
- Houseシリーズの全体像と歴史的背景
- 主要4種(Force/Spirit/Lore/Orange)の発想の核
- glibcバージョン進化と各技の生死マップ
- 現代版(IO_FILE系/House of Rust)への入口
- 守る側の選択肢(新glibc+メモリ安全言語+Hardened allocator)
📖 はじめてのWebセキュリティ #64|Houseシリーズ編
House of Force・Spiritでヒープを乗っ取る。 シリーズ一覧を見る →
⚠️ 大事なお約束
本番システムへのexploitは違法。CTF・自作バイナリ・how2heap等の検証環境のみで確認してください。
主要House 4種の発想を比べる
それぞれが攻めるglibc構造
- House of Force:ヒープ末尾の
top chunkのsizeフィールドをBoFで0xFFFFFFFFFFFFFFFF等に書き換え→巨大mallocを要求すると『要求量だけtopから切り出して残りを新topにする』処理が攻撃者制御の場所に新topを置く。glibc 2.29で size validate が入り無効化 - House of Spirit:stack上やbss上に偽のチャンクヘッダを仕込み、そのアドレスを
free()するとtcache/fastbinが受け入れる。続くmallocが偽チャンク領域を返す。サイズ整合性の検証を回避できる時に有効 - House of Lore:small binの双方向リスト(bk/fd)を偽造。
victim->bk = fake_chunk_addrと書き込みmallocを誘導すると、fake_chunkが返却される。unlinkマクロのチェックを通る形に偽装する必要 - House of Orange:top chunkを使い切るような巨大mallocを誘発するとtopがunsorted binへ送られる。そこでunsorted bin attack(
victim->bk = target - 0x10)でtargetにmain_arenaのアドレスを書く。元はFile Stream(_IO_FILE)を狙うHouse of Orange exploitの構成要素 - House of Rust(現代): glibc 2.32+のSafe-Linking対応。tcache poisoningを暗号化されたfdに対応させた最新版。ヒープベースを別経路でリーク後にXOR解除して仕込む
4つを一言で覚えるなら、『どこを攻めるか』で区別するのがコツです。Forceはヒープの“末尾の空き地(top chunk)”、Spiritは“偽の表札(偽チャンク)”、Loreは“住人名簿(双方向リスト)”、Orangeは“大工事のドサクサ(unsorted bin)”。狙う場所がそれぞれ違うから、使える前提条件も違います。問題を見て『今いじれるのはどこか』を考えると、自然と使う型が絞れてきますよ。

同じ通りに並ぶ4軒の家でも、それぞれ違う流儀で侵入されます。『House of Force』は屋根の高さ表示を書き換えて家を巨大化させ、別の敷地まで自分の家ということにする流儀。『House of Spirit』は偽の表札を立てて別の家のフリをして郵便を受け取る流儀。『House of Lore』は町内会の住人名簿(双方向リスト)を改竄して別人を住人として登録する流儀。『House of Orange』は大規模工事の段取りに乗じて公文書を書き換える流儀。家の構造(glibcの仕様)の細かい癖を、それぞれ別の角度から突く特殊技です。
ここで覚える用語:top chunk / unsorted bin attack
top chunkはヒープ末尾の『まだ誰にも割り当てられていない最大の空き領域』。新規mallocはまずtopから切り出されます。多くのHouse技がここを操作します。unsorted bin attackは『freeチャンクのbkを書き換えてmallocを呼ぶと、attacker指定のtargetアドレスにmain_arena内のあるアドレスが書き込まれる』性質を悪用するプリミティブ。任意リーク・任意書込の入口として、現代でも様々なexploitに組み込まれます。
glibc進化との追いかけっこ
House技はglibcバージョンに激しく依存します。攻撃者が新技を発見→glibcメンテナが検証チェックを追加→無効化→別の隙が見つかり新技誕生……という追いかけっこが20年続いています。下記が主要な節目。
この“追いかけっこ”、傍から見るとちょっとワクワクします。攻撃者が新しい隙を見つけるたび、glibcの開発者が見張りを足して塞ぎ、するとまた別の隙が見つかる——20年続く知恵比べです。だから実戦では『相手のglibcが何年世代か』を真っ先に確認するのが鉄則。同じ技でも、世代が1つ違うだけで通ったり弾かれたりします。“いつの時代の家か”を知ってから、侵入の流儀を選ぶわけです。
- glibc 2.26(2017): tcache導入。tcache poisoningの時代が始まる
- glibc 2.29(2019): tcache_entry.keyでdouble-free検出+top chunkのsize validate → House of Force殺し
- glibc 2.32(2020): Safe-Linking(fdをheap上位ビットでXOR保護) → tcache/fastbin poisoning難化
- glibc 2.34(2021):
__free_hook/__malloc_hook削除 → 旧攻撃経路封鎖 - 2022〜現代:
_IO_2_1_stdout_/_IO_FILEvtable直接書換、House of Rust等が主流


CTFでやってみよう:how2heapで実機検証
shellphish/how2heap で複数House技を動かす
目的は『各House技がglibcバージョンによって動く/動かない』を実機で確認することです。バージョン差を体感すると、CTF本番でldd --versionを最初に叩く癖が付きます。
git clone https://github.com/shellphish/how2heap.gitldd --versionで自分のglibcバージョンを確認(例:2.35)- 該当フォルダ(
glibc_2.35/)に移動→lsで動くサンプル一覧を確認 make house_of_einherjar等をビルド→実行→printf出力で『stack上の変数を返したぞ!』を見る- gdb+pwndbgで
heap chunks/bins/tcachebinsを実行、binの内部状態を観察 - 2.27/2.31の古いフォルダにあるサンプルを2.35環境で実行→失敗することを確認(検証強化が効いている証拠)
- 余裕があれば
house_of_kibana等の最新版に挑戦、IO_FILE系の世界へ
守る側:『新glibc+メモリ安全言語+確率的検出』
- glibcは常に最新(ディストリのstable+セキュリティパッチ即適用)。古いLTSを長く使う場合はCVE追跡を必須化
- C/C++を続けるならASan+UBSanを開発・CIで強制。本番では性能影響を考えてGWP-ASan(確率的)
- 新規プロダクトはRustで書く(所有権モデルがUAF/Double Freeを構文的に拒否、Houseシリーズ前提の脆弱性ごと排除)
- 本番ではHardened allocator(
Scudo(Android標準),jemallocセキュア設定,mimalloc-secure)を採用 - 監視で同一プロセスのheap関連クラッシュを異常検知としてフラグ化、自動exploitの早期発見
- カーネルならKASANを有効化し、ヒープバグを開発段階で潰す
- サプライチェーン(依存ライブラリ)も同じく最新化、CVE-2024-XXX等のヒープバグ修正を怠らない

House系は『glibcとの追いかけっこ』なんだね…バージョン確認が最初の一手か。

次回は保護機構と回避。Canary・PIE・ASLR・RELROの仕組みと、それぞれの突破口を整理するよ。
まとめ:『glibcバージョン×技のマッピング』が実戦の鍵
- Houseシリーズはmalloc/free仕様の隙を個別に突く独立技の集合
- 主要4種:Force / Spirit / Lore / Orange+現代版IO_FILE / Rust
- glibcバージョン依存→
ldd --version確認が初手 - 守りは最新glibc + メモリ安全言語 + Hardened allocator + ASan/Fuzz
今日の持ち帰りは『Houseシリーズは“暗記”ではなく“地図”で捉える』。それぞれが狙うヒープの部位と、効くglibc世代さえ押さえておけば、初見の型でも『ああ、あの場所を別角度から突いているのか』と読み解けます。攻防はバージョンとともに動き続ける——その前提を忘れないことが、いちばんの武器になります。
次回は保護機構と回避編。Canary・PIE・ASLR・RELROの内部と、それぞれの突破口・新世代CET等まで整理します。
