CTFするぞ

CTF以外のことも書くよ

Best Pwnable Challenges 2025

はじめに

今年参加したCTFの中から主観で面白かった問題を取り上げます。毎週参加してるわけではないので他にも面白い問題があったと思いますが、CTFtimeでtop 10に入るほどには参加していたらしいので今年は記事にしてみました。もっと面白い問題を知っているぞという方はぜひ教えてください。

受賞作品一覧

Stack Impromptu - 創造力賞

創造力賞(Creativity Award):解法がもっとも独創的だった・美しかった問題に与えられる賞

作問者

Dronexさん

解説と概要

はじめに紹介するのはBlackHat MEAの決勝で出題したStack Impromptuという問題です。「出題した」というように私が作問者になっているので紹介するか迷いましたが、90%くらいはDronexさんが作った問題なので対象にしました。

スレッド型サーバで次のような自明な脆弱性があるという問題です。

void fatal(const char *msg) {
  perror(msg);
  pthread_exit(NULL);
}

int server_read(int& fd) {
  size_t size;
  char buf[0x40];

  memset(buf, 0, sizeof(buf));
  if (read(fd, &size, sizeof(size)) != sizeof(size)
      || size > 0x100
      || read(fd, buf, size) < size)
    goto err;

  write(fd, buf, size);
  return 0;

err:
  close(fd);
  fatal("Could not receive data (read)");
  return 1;
}

void* server_main(void* arg) {
  int fd = (int)((intptr_t)arg);
  while (server_read(fd) == 0);
  return NULL;
}

セキュリティ機構がすべてかかっているため、stack canaryやlibcのアドレスをリークする必要があります。リークするためには write を適切なサイズで呼ぶ必要がありますが、そのためには read が失敗する(-1を返す)必要があります。

この問題ではバッファオーバーフローによってfdが書き換えられるため、 pthread_exit が死なないように工夫すると良い感じに任意のfdをcloseできるprimitiveが手に入ります。ここでさらに、 read で待機中のソケットにRSTパケットを送ると、こちらから接続を切ることなく相手の read を失敗させることができます。これらを組み合わせて、サーバ側のfdを差し替えることで別のソケットが未初期化バッファのリークを受け取ることができるという、ソケットの知識をフル活用したパズルになっています。

解法スクリプト

コメント

間違えて解けない状態の問題をDronexに渡したら、1日かけて解いてきたので驚きました。 fdが差し替わることで、新しく開いたソケットに突然プログラム上ありえない謎のデータが降ってくるリーク方法は過去に見たことがなく美しかったです。

decore - 脆弱性

脆弱性賞(Vulnerability Award):脆弱性がもっとも巧妙かつ自然に隠されていた問題に与えられる賞

作問者

不明

解説と概要

decoreはKalmarCTF 2025で出題された問題です。脆弱なプログラムが core_pattern に登録されているので、クラッシュすると「解析されると脆弱性を発火するコアダンプ」を生成するようなプログラムを作る必要があります。脆弱性はシンボル情報のパース時にELFのsymtab/strtabが不正だと範囲外参照を起こしてしまうというバグです。範囲外参照でフラグを表示するためにはフラグがメモリにマップされている必要があるので、そこをなんとかするという問題です。 この問題に関してはwriteupを公開しているので詳しくはそちらをご覧ください。

ptr-yudai.hatenablog.com

コメント

core_pattern に脆弱なプログラムが登録されていて権限昇格に使うという問題設定がそもそも斬新でした。プログラム側の脆弱性と、Linux側の回避しようのない問題を組み合わせて初めて解けるのも面白かったです。 脆弱性も実際にありそうな感じで良かったですが、欲を言えばソースコードも配布してほしかったです。

new_era - 教育賞

教育賞(Educational Award):もっとも教育的な問題に与えられる賞

作問者

r1ruさん

解説と概要

OSINTで有名なTsukuCTFですが、今年はr1ruさんがpwnを出題されていました。この問題は、Linux kernelのヒープでoff-by-nullが起きるというシンプルな脆弱性です。 こちらは作問者writeupが公開されているので、詳しくはそちらをご覧ください。

r1ru.github.io

コメント

ここ数年、Linux kernel exploitは半分以上がdata-oriented attackになっており、 pipe_buffer やページテーブルを使う問題を多く見るようになったため、その点でも教育的だと思いました。 同CTFのxcacheという問題も、Linux kernelの専用キャッシュでUAFが起こるという近年よく見るパターンを簡略化した問題設定のため、cross-cache attackの教材としておすすめです。

old school - 風水賞

風水賞(Feng Shui Award):もっとも面倒な*1glibcヒープ問題に与えられる賞

作問者

c0mm4nd_さん

解説と概要

最後に紹介するのはsnakeCTF 2025 Qualsのold schoolです。 この問題は、tcacheが無効化された環境で、freeとreallocでdouble freeが発生するという状況をなんとかするヒープ問です。fastbinのdouble freeといえば、2つのチャンクを交互にfreeして検知を回避するのが一般的ですが、この問題は2連続でfreeされることが確定しているため難しい問題です。topから取得できないがfastbinがあるときに malloc_consoliadte が走るという挙動を利用すると解けます。 公式writeupが公開されているので、詳しくはそちらをご覧ください。

snakectf.org

コメント

fastbinをunsortedbinに追い出したり、fastbinでFILE構造体を書き換えにいったり、いろいろ考えることがあって大変でした。ヒープで苦しみ楽しみたい方にはおすすめです。 いままでありがとう、fastbin。

その他の良問

惜しくも受賞を逃した問題たちです。

  • 創造力賞
    • Stack Rhapsody - BlackHat MEA CTF 2025 Finals(ソースコードがとてもシンプルで一見すると不可能ですが解ける面白い問題です。)
  • 脆弱性
    • piano - HKCERT CTF 2025 Quals(例外発生時のスタックの扱いでコーナーケースが発生し、結果としてUse-after-Freeにつながるという、一見パッチから何が起こるかわかりにくい問題でした。)
  • 教育賞
    • LPE - CODEGATE CTF 2025 Finals(Windows 11のセキュリティ機構入門として良いと思います。)
    • RandomJS - ASIS CTF 2025 Quals(JavaScriptのUse-after-Free入門として良いです。)
  • 風水賞
    • pryspace - TSG CTF 2025 Quals(厳しい制約で巨大なunsortedbinを作るというアイデアが斬新でした。)

*1:ヒープ問においては褒め言葉?