以下の内容はhttps://daisuke20240310.hatenablog.com/entry/glibcより取得しました。


システムにインストールされたものと異なるバージョンのglibcを使う方法

現在、「詳解セキュリティコンテスト: CTFで学ぶ脆弱性攻略の技術 Compass Booksシリーズ」の 34章の「ヒープベースエクスプロイト」を読み進めています。34章では、glibc-2.31 を使うことを前提に解説がされています。出来れば、書籍と同じ環境を準備したいところです。

しかし、glibc-2.31 は Ubuntu 20.04 のシステムで使われていた?そうなのですが、現在は、少し古いバージョンの glibc です。現在、Parrot OS 6.1 を使ってますが、glibc のバージョンは、2.36 でした。

そこで、この記事では、システムの glibc とは異なるバージョンの glibc を使う方法を調べたので、それについて書いていきたいと思います。

それでは、やっていきます。

参考文献

今回、題材にさせて頂いた「詳解セキュリティコンテスト」です。

はじめに

「セキュリティ」の記事一覧です。良かったら参考にしてください。

セキュリティの記事一覧
・第1回:Ghidraで始めるリバースエンジニアリング(環境構築編)
・第2回:Ghidraで始めるリバースエンジニアリング(使い方編)
・第3回:VirtualBoxにParrotOS(OVA)をインストールする
・第4回:tcpdumpを理解して出力を正しく見れるようにする
・第5回:nginx(エンジンエックス)を理解する
・第6回:Python+Flask(WSGI+Werkzeug+Jinja2)を動かしてみる
・第7回:Python+FlaskのファイルをCython化してみる
・第8回:shadowファイルを理解してパスワードを解読してみる
・第9回:安全なWebアプリケーションの作り方(徳丸本)の環境構築
・第10回:Vue.jsの2.xと3.xをVue CLIを使って動かしてみる(ビルドも行う)
・第11回:Vue.jsのソースコードを確認する(ビルド後のソースも見てみる)
・第12回:徳丸本:OWASP ZAPの自動脆弱性スキャンをやってみる
・第13回:徳丸本:セッション管理を理解してセッションID漏洩で成りすましを試す
・第14回:OWASP ZAPの自動スキャン結果の分析と対策:パストラバーサル
・第15回:OWASP ZAPの自動スキャン結果の分析と対策:クロスサイトスクリプティング(XSS)
・第16回:OWASP ZAPの自動スキャン結果の分析と対策:SQLインジェクション
・第17回:OWASP ZAPの自動スキャン結果の分析と対策:オープンリダイレクト
・第18回:OWASP ZAPの自動スキャン結果の分析と対策:リスク中すべて
・第19回:CTF初心者向けのCpawCTFをやってみた
・第20回:hashcatの使い方(GPU実行時間の見積りとパスワード付きZIPファイル)
・第21回:Scapyの環境構築とネットワークプログラミング
・第22回:CpawCTF2にチャレンジします(クリア状況は随時更新します)
・第23回:K&Rのmalloc関数とfree関数を理解する
・第24回:C言語、アセンブラでシェルを起動するプログラムを作る(ARM64)
・第25回:機械語でシェルを起動するプログラムを作る(ARM64)
・第26回:入門セキュリhttps://github.com/SECCON/SECCON2017_online_CTF.gitティコンテスト(CTFを解きながら学ぶ実践技術)を読んだ
・第27回:x86-64 ELF(Linux)のアセンブラをGDBでデバッグしながら理解する(GDBコマンド、関連ツールもまとめておく)
・第28回:入門セキュリティコンテスト(CTFを解きながら学ぶ実践技術)のPwnable問題をやってみる
・第29回:実行ファイルのセキュリティ機構を調べるツール「checksec」のまとめ
・第30回:setodaNote CTF Exhibitionにチャレンジします(クリア状況は随時更新します)
・第31回:常設CTFのksnctfにチャレンジします(クリア状況は随時更新します)
・第32回:セキュリティコンテストチャレンジブックの「Part2 pwn」を読んだ
・第33回:セキュリティコンテストチャレンジブックの「付録」を読んでx86とx64のシェルコードを作った
・第34回:TryHackMeを始めてみたけどハードルが高かった話
・第35回:picoCTFを始めてみた(Beginner picoMini 2022:全13問完了)
・第36回:picoCTF 2024:Binary Exploitationの全10問をやってみた(Hardの1問は後日やります)
・第37回:picoCTF 2024:Reverse Engineeringの全7問をやってみた(Windowsプログラムの3問は後日やります)
・第38回:picoCTF 2024:General Skillsの全10問をやってみた
・第39回:picoCTF 2024:Web Exploitationの全6問をやってみた(最後の2問は解けず)
・第40回:picoCTF 2024:Forensicsの全8問をやってみた(最後の2問は解けず)
・第41回:picoCTF 2024:Cryptographyの全5問をやってみた(最後の2問は手つかず)
・第42回:picoCTF 2023:General Skillsの全6問をやってみた
・第43回:picoCTF 2023:Reverse Engineeringの全9問をやってみた
・第44回:picoCTF 2023:Binary Exploitationの全7問をやってみた(最後の1問は後日やります)
・第45回:書籍「セキュリティコンテストのためのCTF問題集」を読んだ
・第46回:書籍「詳解セキュリティコンテスト」のReversingを読んだ
・第47回:書籍「詳解セキュリティコンテスト」のPwnableのシェルコードを読んだ
・第48回:書籍「バイナリファイル解析 実践ガイド」を読んだ
・第49回:書籍「詳解セキュリティコンテスト」Pwnableのスタックベースエクスプロイトを読んだ
・第50回:書籍「詳解セキュリティコンテスト」Pwnableの共有ライブラリと関数呼び出しを読んだ
・第51回:picoCTF 2025:General Skillsの全5問をやってみた
・第52回:picoCTF 2025:Reverse Engineeringの全7問をやってみた
・第53回:picoCTF 2025:Binary Exploitationの全6問をやってみた
・第54回:書籍「詳解セキュリティコンテスト」Pwnableの仕様に起因する脆弱性を読んだ
・第55回:システムにインストールされたものと異なるバージョンのglibcを使う方法 ← 今回

以下は「詳解セキュリティコンテスト: CTFで学ぶ脆弱性攻略の技術 Compass Booksシリーズ」のサポートサイトです。問題ファイルをダウンロードすることが出来ます。

book.mynavi.jp

今回対象とするプログラムは、files/pwnable/05_heap にあります。

概要

glibc について、少し調べたので、その内容を書いておきます。

glibc とは、「GNU C Library」の略で、C言語の標準ライブラリの実装です。たくさんの拡張がされており、Linux を使っていれば、一番お世話になってるライブラリだと思います。ファイルシステム上では、libc.so.6 という名前で配置されていて、glibc 以外のlibc の代替実装として、「musl libc」や「uClibc」などが存在します。

libc は、C言語の標準ライブラリの総称というイメージで、glibc は libc の具体的な実装の一つという感じです。

現在のシステムにインストールされている glibc のバージョンは以下で調べることが出来ます。

$ ldd --version
ldd (Debian GLIBC 2.36-9+deb12u8) 2.36
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
作者 Roland McGrath および Ulrich Drepper。

システムと異なるバージョンの glibc を使うことは、思ってたよりハードルが高いです。いろいろ調べた結果、システムにインストールされている glibc を差し替えることはやめておいた方がいいようです。

一番安全で確実な方法は、Docker を使って、別の環境を用意する方法のようです。ここでは、その選択はせず、いろいろとやってみたいと思います。

以下で、失敗も含めて、いろいろ書いてますが、結論としては、「GDBにデバッグシンボルを読み込ませる」に書いた内容になります。

Parrot OS 6.1にインストールされたglibcを使って確認する

まずは、システムにインストールされた glibc を使って調べていきます。使用するプログラムは、「詳解セキュリティコンテスト: CTFで学ぶ脆弱性攻略の技術 Compass Booksシリーズ」の 34章の「ヒープベースエクスプロイト」の attack_leak を使います。上のサポートサイトからダウンロードした ZIPファイルを解凍して、files/pwnable/05_heap/attack_leak にあります。ソースコードは同じディレクトリの attack_leak.c です。

以下のように、システムにインストールされた glibc が使われるようになっています。その glibc を調べてみると、先ほど、lddコマンドで見たように、バージョンは、2.36 のようです。この glibc は、strip されているので、シンボルを含んでいません。よって、GDB などで、変数の情報などが見れないものとなっています。

$ file attack_leak
attack_leak: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=11942832f0d694b495fc2a1a0f07058d4ef0227f, for GNU/Linux 3.2.0, with debug_info, not stripped

$ ldd attack_leak
        linux-vdso.so.1 (0x00007ffecdd42000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f38bb9a0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f38bbba1000)

$ file /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=30f067a5eccdb3bdce0b9ec7638ebd86992b9c8b, for GNU/Linux 3.2.0, stripped

$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Debian GLIBC 2.36-9+deb12u8) stable release version 2.36.
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 12.2.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
Minimum supported kernel: 3.2.0
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

$ nm /lib/x86_64-linux-gnu/libc.so.6
nm: /lib/x86_64-linux-gnu/libc.so.6: シンボルがありません

$ nm -D /lib/x86_64-linux-gnu/libc.so.6 | head -n 10
0000000000000000 A GLIBC_2.10
0000000000000000 A GLIBC_2.11
0000000000000000 A GLIBC_2.12
0000000000000000 A GLIBC_2.13
0000000000000000 A GLIBC_2.14
0000000000000000 A GLIBC_2.15
0000000000000000 A GLIBC_2.16
0000000000000000 A GLIBC_2.17
0000000000000000 A GLIBC_2.18
0000000000000000 A GLIBC_2.2.5

GDB で atack_leak を見てみます。関係ない表示は省略しています。GDB を起動しただけでは、プログラムはまだ動いていないため、変数の内容は見れませんが、プログラムを起動して、main関数までいくと変数の内容が見れるようになります。

$ gdb -q attack_leak
Reading symbols from attack_leak...

pwndbg> p main_arena
No symbol "main_arena" in current context.

pwndbg> start

pwndbg> p main_arena
$1 = {
  mutex = 0,
  flags = 0,
  have_fastchunks = 0,
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  top = 0x0,
  last_remainder = 0x0,
  bins = {0x0 <repeats 254 times>},
  binmap = {0, 0, 0, 0},
  next = 0x7ffff7f9bc60 <main_arena>,
  next_free = 0x0,
  attached_threads = 1,
  system_mem = 0,
  max_system_mem = 0
}

現在使用している glibc は stripされているはずなのに、変数の情報(シンボル)が見れています。これは、GDB がデバッグシンボルを自動的に読み込んでいるからだそうです。それを確認してみます。以下のコマンドで、自動的に読み込むデバッグシンボルの場所として、設定されたパスを表示しています。

pwndbg> show debug-file-directory
The directory where separate debug symbols are searched for is "/usr/lib/debug".

/usr/lib/debug に、何があるのか見てみます。長いので最初の方法だけ貼ってます。ここには、デバッグシンボルを格納したファイルがあります。.build-id というディレクトリに、2文字のディレクトリで整理されていて、その中には、xxx.debug というファイルが格納されています。これは、BuildID(sha1)の先頭2文字のディレクトリに残りの文字.debug という形で入っています。

$ tree -a --charset=C /usr/lib/debug
/usr/lib/debug
|-- .build-id
|   |-- 00
|   |   |-- 3f2a8d1826d842839d01cef170b3e091beb6ca.debug
|   |   `-- f7c56d6a3112b2f4c5f0604854d0dfe271174a.debug
|   |-- 01
|   |   `-- 73cb431894dbaef21ca18a765398b4917b7c19.debug
|   |-- 02
|   |   `-- 4aba767e722d671ad5a7662a96ebfc226bc711.debug
|   |-- 03
|   |   `-- d5d6ed8361b98625388531bcf4b4511eadaabe.debug

先ほど、確認した、システムにインストールされた glibc のデバッグシンボルを見てみます。BuildID の先頭2文字を除いた文字列で検索します。grepコマンドの -C 3 は、ヒットした文字列の前後の3行を表示するというオプションです。BuildID の先頭2文字(30)のディレクトリに、BuildID の残りの文字.debug というファイルが格納されていることが確認できました。デバッグシンボルのファイルの中身も見てみましたが、さすがによく分かりませんが、nmコマンドでシンボルの内容は確認できるようです。

$ file /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=30f067a5eccdb3bdce0b9ec7638ebd86992b9c8b, for GNU/Linux 3.2.0, stripped

$ tree -a --charset=C /usr/lib/debug | grep -C 3 f067a5eccdb3bdce0b9ec7638ebd86992b9c8b
|   |   |-- 4660658da89844c15813542353f281b7b60fc8.debug
|   |   `-- b0d5511b92953d06bd4efdb5089f32bce903bc.debug
|   |-- 30
|   |   `-- f067a5eccdb3bdce0b9ec7638ebd86992b9c8b.debug
|   |-- 31
|   |   |-- 9c1a4c4c0bae3ca9b80781cff1838a5e248cd0.debug
|   |   |-- c34b875ae6b5cb475fcd3da69b36e05af5d3e4.debug

$ hexdump -C  /usr/lib/debug/.build-id/30/f067a5eccdb3bdce0b9ec7638ebd86992b9c8b.debug | head -n 20
00000000  7f 45 4c 46 02 01 01 03  00 00 00 00 00 00 00 00  |.ELF............|
00000010  03 00 3e 00 01 00 00 00  10 74 02 00 00 00 00 00  |..>......t......|
00000020  40 00 00 00 00 00 00 00  b8 77 3f 00 00 00 00 00  |@........w?.....|
00000030  00 00 00 00 40 00 38 00  0e 00 40 00 4a 00 49 00  |....@.8...@.J.I.|
00000040  06 00 00 00 04 00 00 00  40 00 00 00 00 00 00 00  |........@.......|
00000050  40 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  |@.......@.......|
00000060  10 03 00 00 00 00 00 00  10 03 00 00 00 00 00 00  |................|
00000070  08 00 00 00 00 00 00 00  03 00 00 00 04 00 00 00  |................|
00000080  00 10 00 00 00 00 00 00  f0 0a 1a 00 00 00 00 00  |................|
00000090  f0 0a 1a 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000a0  1c 00 00 00 00 00 00 00  10 00 00 00 00 00 00 00  |................|
000000b0  01 00 00 00 04 00 00 00  00 00 00 00 00 00 00 00  |................|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000d0  b4 03 00 00 00 00 00 00  88 53 02 00 00 00 00 00  |.........S......|
000000e0  00 10 00 00 00 00 00 00  01 00 00 00 05 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00  00 60 02 00 00 00 00 00  |.........`......|
00000100  00 60 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |.`..............|
00000110  fc 4d 15 00 00 00 00 00  00 10 00 00 00 00 00 00  |.M..............|
00000120  01 00 00 00 04 00 00 00  00 00 00 00 00 00 00 00  |................|
00000130  00 b0 17 00 00 00 00 00  00 b0 17 00 00 00 00 00  |................|

$ nm /usr/lib/debug/.build-id/30/f067a5eccdb3bdce0b9ec7638ebd86992b9c8b.debug | head -n 10
0000000000193a80 b CSWTCH.1
00000000001d3860 b DW.ref.__gcc_personality_v0
0000000000000000 A GLIBC_2.10
0000000000000000 A GLIBC_2.11
0000000000000000 A GLIBC_2.12
0000000000000000 A GLIBC_2.13
0000000000000000 A GLIBC_2.14
0000000000000000 A GLIBC_2.15
0000000000000000 A GLIBC_2.16
0000000000000000 A GLIBC_2.17

$ nm /usr/lib/debug/.build-id/30/f067a5eccdb3bdce0b9ec7638ebd86992b9c8b.debug | grep main_arena
00000000001d2c60 b main_arena

ここまでの確認で、GDB で stripされたプログラムなのに、変数の情報が表示された理由が分かりました。ここからは、システムにインストールされたものとは異なる glibc を使って、GDB でデバッグシンボルを表示することを目指してやっていきたいと思います。

ダウンロードしたglibcを使って、実行、GDBでデバッグ、pwntoolsでデバッグしてみる

ダウンロードした glibc-2.31 のバイナリを使って、実行したり、GDB でデバッグしたり、pwntools で動かしたりしてみたいと思います。

以降で、ChatGPT に聞きながら、いろいろな方法を試してみましたが、結論として、以下の設定を使うだけでは、実行は出来ますが、GDB でデバッグは出来ませんでした。pwndbg が対応してる範囲の glibc なら動いたかもしれません。もしくは、pwndgb のバージョンを下げると出来るかもしれませんが、そこまでは試しませんでした。デバッグシンボルをロードする必要がありそうです。

以下に、設定でやろうとして、うまくいかなかった内容を、記録として残しておきます。

glibc-2.31 をビルドしようとしましたが、コンパイルエラーが出たので、以下の手順で、バイナリをダウンロードして使いました。Ubuntu の debパッケージから抽出して使う方法です(from ChatGPT)。ヒープ領域と libc のベースアドレスがページ単位になっているので、正しく実行できていると思います。ちなみに、LD_LIBRARY_PATH で、libc.so だけを使おうとすると、ローダーと libc のバージョンが一致しないためエラーになります。

$ wget http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.31-0ubuntu9_amd64.deb

$ dpkg-deb -x ./libc6_2.31-0ubuntu9_amd64.deb /home/user/svn/oss/glibc231

$ file /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
/home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=634252e0c5f8b03957a2e529719d4101699a894a, for GNU/Linux 3.2.0, stripped

$ /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so --library-path /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu ./attack_leak
UAF
heap base : 0x555556743000
libc base : 0x7fe101798000

Uninitialized
heap base : 0x555556743000
libc base : 0x7fe101798000

以下は、ダウンロードした libc を使った GDB の起動方法です(from ChatGPT)。しかし、この方法は GDB環境すべてに影響を与えてしまうため、サポートしていないバージョンの libc だったため、うまくいきませんでした。

$ gdb -q ./attack_leak

pwndbg> set environment LD_LIBRARY_PATH /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu
pwndbg> set exec-wrapper /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so --library-path /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu
pwndbg> r
Starting program: /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak 
/bin/bash: /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /bin/bash)
/bin/bash: /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.36' not found (required by /bin/bash)
/bin/bash: /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by /bin/bash)
/bin/bash: /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /lib/x86_64-linux-gnu/libtinfo.so.6)
During startup program exited with code 1.

以下は、対象のプログラムの attack_leak にだけ、ダウンロードした libc を使う方法です。今度は、正しく実行できたようです。

$ gdb -q ./attack_leak

pwndbg> file /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
Reading symbols from /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so...
(No debugging symbols found in /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so)
pwndbg> set args --library-path /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu ./attack_leak
pwndbg> run
Starting program: /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so --library-path /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu ./attack_leak
UAF
heap base : 0x7ffff7fff000
libc base : 0x7ffff7dd0000

Uninitialized
heap base : 0x7ffff7fff000
libc base : 0x7ffff7dd0000

あと、pwntools で、GDB でデバッグするときに、ダウンロードした libc を使う方法です。以下のソースコードのようにすれば、対象のプログラムの attack_leak にだけ、ダウンロードした libc を使うことが出来ます。tmux を使ってるので、使わない場合は、context(terminal = ['tmux', 'splitw', '-h']) をコメントアウトする必要があります。

#!/usr/bin/env python3
from pwn import *

bin_file = './attack_leak'
context(os = 'linux', arch = 'amd64')
context(terminal = ['tmux', 'splitw', '-h'])

libc_path = '/home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so'
ld_path   = '/home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so'

binf = ELF( bin_file )

def main():
    proc = gdb.debug([ ld_path, '--library-path', os.path.dirname(libc_path), bin_file ])

if __name__ == '__main__':
    main()

patchelfを使って、対象プログラムが使用するローダ、libcを強制的に設定する方法

まず、patchelf をインストールします。

$ sudo apt install patchelf

次に、patchelf を使って、対象のプログラム(今回は、attack_leak をコピーした attack_leak_patch)が参照するローダと libc を強制的に設定します。--set-rpath で libc の場所を指定して、--set-interpreter で、使用するローダを指定して、最後に、パッチを適用する対象プログラムを指定します。

$ patchelf --set-rpath /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu --set-interpreter /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so ./attack_leak_patch

$ ldd attack_leak_patch
        linux-vdso.so.1 (0x00007ffccf297000)
        libc.so.6 => /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc.so.6 (0x00007feed587a000)
        /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so => /lib64/ld-linux-x86-64.so.2 (0x00007feed5a77000)

では、GDB で動かしてみます。正しく動いているようです。後で分かったのですが、この libc にはデバッグシンボルが付いていません。libc6-dbg を使って、デバッグシンボルを読み込ませようとしたのですが、うまくいきませんでした。

$ gdb -q attack_leak_patch
Poetry could not find a pyproject.toml file in /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap or its parents
pwndbg: loaded 169 pwndbg commands and 47 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $base, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break)
Reading symbols from attack_leak_patch...
------- tip of the day (disable with set show-tips off) -------
Use Pwndbg's config and theme commands to tune its configuration and theme colors!
pwndbg> start
Temporary breakpoint 1 at 0x11d5: file attack_leak.c, line 10.

Temporary breakpoint 1, main () at attack_leak.c:10
10        setbuf(stdout, NULL);
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────────────────────────────────────────────────
 RAX  0x5555555551c9 (main) ◂— endbr64 
 RBX  0x555555555320 (__libc_csu_init) ◂— endbr64 
 RCX  0x555555555320 (__libc_csu_init) ◂— endbr64 
 RDX  0x7fffffffdef8 —▸ 0x7fffffffe264 ◂— 'SHELL=/bin/bash'
 RDI  1
 RSI  0x7fffffffdee8 —▸ 0x7fffffffe210 ◂— '/home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch'
 R8   0
 R9   0x7ffff7fe0d50 ◂— endbr64 
 R10  0
 R11  0
 R12  0x5555555550e0 (_start) ◂— endbr64 
 R13  0x7fffffffdee0 ◂— 1
 R14  0
 R15  0
 RBP  0x7fffffffddf0 ◂— 0
 RSP  0x7fffffffddc0 —▸ 0x7ffff7fc5fc8 ◂— 0
 RIP  0x5555555551d5 (main+12) ◂— mov rax, qword ptr [rip + 0x2e3c]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 ► 0x5555555551d5 <main+12>    mov    rax, qword ptr [rip + 0x2e3c]     RAX, [stdout@@GLIBC_2.2.5] => 0x7ffff7fc16a0 (_IO_2_1_stdout_) ◂— 0xfbad2084
   0x5555555551dc <main+19>    mov    esi, 0                            ESI => 0
   0x5555555551e1 <main+24>    mov    rdi, rax                          RDI => 0x7ffff7fc16a0 (_IO_2_1_stdout_) ◂— 0xfbad2084
   0x5555555551e4 <main+27>    call   setbuf@plt                  <setbuf@plt>
 
   0x5555555551e9 <main+32>    mov    edi, 0x418     EDI => 0x418
   0x5555555551ee <main+37>    call   malloc@plt                  <malloc@plt>
 
   0x5555555551f3 <main+42>    mov    qword ptr [rbp - 0x28], rax
   0x5555555551f7 <main+46>    mov    rax, qword ptr [rbp - 0x28]
   0x5555555551fb <main+50>    sub    rax, 0x10
   0x5555555551ff <main+54>    mov    qword ptr [rbp - 0x20], rax
   0x555555555203 <main+58>    mov    edi, 0                          EDI => 0
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
In file: /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak.c:10
    5 unsigned long ofs_libc_mainarena = 0x1ebb80;
    6 int main(void){
    7         void *ma, *mb;
    8         malloc_chunk *ca;
    9 
 ► 10         setbuf(stdout, NULL);
   11 
   12         ma = malloc(0x418);
   13         ca = mem2chunk(ma);
   14         malloc(0);
   15         mb = malloc(0x418);
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffddc0 —▸ 0x7ffff7fc5fc8 ◂— 0
01:0008│-028 0x7fffffffddc8 —▸ 0x555555555320 (__libc_csu_init) ◂— endbr64 
02:0010│-020 0x7fffffffddd0 ◂— 0
03:0018│-018 0x7fffffffddd8 —▸ 0x5555555550e0 (_start) ◂— endbr64 
04:0020│-010 0x7fffffffdde0 —▸ 0x7fffffffdee0 ◂— 1
05:0028│-008 0x7fffffffdde8 ◂— 0
06:0030│ rbp 0x7fffffffddf0 ◂— 0
07:0038│+008 0x7fffffffddf8 —▸ 0x7ffff7dfc0b3 (__libc_start_main+243) ◂— mov edi, eax
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 ► 0   0x5555555551d5 main+12
   1   0x7ffff7dfc0b3 __libc_start_main+243
   2   0x55555555510e _start+46
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> c
Continuing.
UAF
heap base : 0x55555555d000
libc base : 0x7ffff7dd5000

Uninitialized
heap base : 0x55555555d000
libc base : 0x7ffff7dd5000

[Inferior 1 (process 95461) exited normally]

では、puts("UAF"); でブレークポイントを設定して、その状態を確認します。

ヒープ領域のベースアドレスは、ca->bk と vmmap より、0x6b0 のオフセット位置にあることが分かります。よって、ca->bk - 0x6d0 で、ヒープ領域のベースアドレスが算出できることが分かります。

libc のベースアドレスは、下に書きます。

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File
    0x555555554000     0x555555555000 r--p     1000      0 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555555000     0x555555556000 r-xp     1000   1000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555556000     0x555555557000 r--p     1000   2000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555557000     0x555555558000 r--p     1000   2000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555558000     0x555555559000 rw-p     1000   3000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555559000     0x55555555d000 rw-p     4000   5000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x55555555d000     0x55555557e000 rw-p    21000      0 [heap]
    0x7ffff7dd5000     0x7ffff7dfa000 r--p    25000      0 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7dfa000     0x7ffff7f72000 r-xp   178000  25000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7f72000     0x7ffff7fbc000 r--p    4a000 19d000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fbc000     0x7ffff7fbd000 ---p     1000 1e7000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fbd000     0x7ffff7fc0000 r--p     3000 1e7000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fc0000     0x7ffff7fc3000 rw-p     3000 1ea000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fc3000     0x7ffff7fc9000 rw-p     6000      0 [anon_7ffff7fc3]
    0x7ffff7fc9000     0x7ffff7fcd000 r--p     4000      0 [vvar]
    0x7ffff7fcd000     0x7ffff7fcf000 r-xp     2000      0 [vdso]
    0x7ffff7fcf000     0x7ffff7fd0000 r--p     1000      0 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7fd0000     0x7ffff7ff3000 r-xp    23000   1000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ff3000     0x7ffff7ffb000 r--p     8000  24000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000  2c000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000  2d000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000      0 [anon_7ffff7ffe]
    0x7ffffffde000     0x7ffffffff000 rw-p    21000      0 [stack]
pwndbg> heap
pwndbg will try to resolve the heap symbols via heuristic now since we cannot resolve the heap via the debug symbols.
This might not work in all cases. Use `help set resolve-heap-via-heuristic` for more details.

Allocated chunk | PREV_INUSE
Addr: 0x55555555d000
Size: 0x290 (with flag bits: 0x291)

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555d290
Size: 0x420 (with flag bits: 0x421)
fd: 0x7ffff7fc0be0
bk: 0x55555555d6d0

Allocated chunk
Addr: 0x55555555d6b0
Size: 0x20 (with flag bits: 0x20)

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555d6d0
Size: 0x420 (with flag bits: 0x421)
fd: 0x55555555d290
bk: 0x7ffff7fc0be0

Allocated chunk
Addr: 0x55555555daf0
Size: 0x20 (with flag bits: 0x20)

Top chunk | PREV_INUSE
Addr: 0x55555555db10
Size: 0x204f0 (with flag bits: 0x204f1)

pwndbg> unsortedbin 
unsortedbin
all: 0x55555555d6d0 —▸ 0x55555555d290 —▸ 0x7ffff7fc0be0 ◂— 0x55555555d6d0

libc にデバッグシンボルが無いため、先ほどと同じようには分かりません。ca->fd0x7ffff7fc0be0 となっていることと、libc のベースアドレスは、0x7ffff7dd5000 であることは分かります。先ほど glibc-2.31 のバイナリをダウンロードしたサイトの同じディレクトリから、libc6-dbg もダウンロードします。nmコマンドで、main_arena のオフセットアドレスを確認すると、0x1ebb80 となっています。つまり、main_arena のアドレスは、0x7ffff7dd5000 + 0x1ebb80 = 0x7ffff7fc0b80 です。ca->fd のアドレスから main_arena のアドレスを引きます。0x7ffff7fc0be0 - 0x7ffff7fc0b80 = 0x60 となり、fdメンバは、main_arena のオフセットが 0x60 の位置にあることが分かります。これで、ようやく、ソースコードの ca->fd - 0x60 - ofs_libc_mainarena で、libc のベースアドレスが算出できることが分かります。

先ほどダウンロードした glibc-2.31 に対応する libc6_dbg をダウンロードします。

$ wget http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/libc6-dbg_2.31-0ubuntu9_amd64.deb

$ dpkg-deb -x ./libc6-dbg_2.31-0ubuntu9_amd64.deb ./glibc231-dbg

$ file glibc231-dbg/usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so
glibc231-dbg/usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter *empty*, BuildID[sha1]=634252e0c5f8b03957a2e529719d4101699a894a, for GNU/Linux 3.2.0, with debug_info, not stripped

$ nm glibc231-dbg/usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so | grep arena
000000000009d960 t __malloc_arena_thread_freeres
0000000000097fa0 t _dl_tunable_set_arena_max
0000000000097fb0 t _dl_tunable_set_arena_test
0000000000098c60 t arena_get2.part.0
0000000000099200 t arena_get_retry
0000000000098860 t detach_arena.part.0
00000000001eeb70 b dumped_main_arena_end
00000000001eeb78 b dumped_main_arena_start
00000000001ebb80 b main_arena
00000000001eb268 b narenas
00000000001eeb40 b narenas_limit.12523
0000000000000050 b thread_arena

$ tree glibc231-dbg | head -n 20
glibc231-dbg
`-- usr
    |-- lib
    |   `-- debug
    |       |-- .build-id
    |       |   `-- 77
    |       |       `-- 5cbbfff814456660786780b0b3b40096b4c05e.debug
    |       |-- lib
    |       |   `-- x86_64-linux-gnu
    |       |       |-- ld-2.31.so
    |       |       |-- ld-linux-x86-64.so.2 -> ld-2.31.so
    |       |       |-- libBrokenLocale-2.31.so
    |       |       |-- libSegFault.so
    |       |       |-- libanl-2.31.so
    |       |       |-- libc-2.31.so
    |       |       |-- libc.so.6 -> libc-2.31.so
    |       |       |-- libdl-2.31.so
    |       |       |-- libm-2.31.so
    |       |       |-- libmemusage.so
    |       |       |-- libmvec-2.31.so

pwntools を使った GDB のデバッグもやってみます。ソースは以下です。対象プログラム自体を書き換えているので、特別な指定があるわけではありません。

#!/usr/bin/env python3
from pwn import *

bin_file = './attack_leak'
context(os = 'linux', arch = 'amd64')
context(terminal = ['tmux', 'splitw', '-h'])

binf = ELF( bin_file )

libc = binf.libc

info( f"libc.functions['system'].address={libc.functions['system'].address:#x}" )

def attack( proc, **kwargs ):
    
    info( proc.recvall().decode() )

def main():
    
    adrs = "shape-facility.picoctf.net"
    port = 51556
    #adrs = "localhost"
    #port = 4000
    
    proc = gdb.debug( bin_file )
    #proc = process( bin_file )
    #proc = remote( adrs, port )
    
    attack( proc )
    #proc.interactive()

if __name__ == '__main__':
    main()

動かしてみたところ、こちらも、libc のデバッグシンボルは使えませんが、デバッグはできました。

GDBにデバッグシンボルを読み込ませる

いろいろやってみましたが、なかなか難しいです。上でダウンロードした libc6-dbg_2.31-0ubuntu9_amd64.deb のデバッグシンボルを格納したファイルが、想定したファイル名ではありませんでした。

libc6_2.31-0ubuntu9_amd64.deb に含まれていた libc-2.31.so の BuildID は、634252e0c5f8b03957a2e529719d4101699a894a で、libc6-dbg_2.31-0ubuntu9_amd64.deb に含まれていた libc-2.31.so の BuildID も 634252e0c5f8b03957a2e529719d4101699a894a で、一致しています。.build-id/63 というディレクトリに、4252e0c5f8b03957a2e529719d4101699a894a.debug というファイルがあることを想定していました。

この想定が異なることが、GDB で set debug-file-directory を実行してもデバッグシンボルが見えない理由だと思います。

http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/ には、libc6_2.31-0ubuntu9_amd64.deb の他に、libc6_2.31-0ubuntu9.17_amd64.deb というものがあります。こちらでやってみます。

対応する libc6-dbg もダウンロードします。こちらには、想定したファイル名のデバッグシンボルがありました。

$ wget http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.31-0ubuntu9.17_amd64.deb

$ dpkg-deb -x ./libc6_2.31-0ubuntu9.17_amd64.deb ./glibc231-17

$ file glibc231-17/lib/x86_64-linux-gnu/libc-2.31.so
glibc231-17/lib/x86_64-linux-gnu/libc-2.31.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0323ab4806bee6f846d9ad4bccfc29afdca49a58, for GNU/Linux 3.2.0, stripped

$ wget http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/libc6-dbg_2.31-0ubuntu9.17_amd64.deb

$ dpkg-deb -x ./libc6-dbg_2.31-0ubuntu9.17_amd64.deb ./glibc231-17-dbg

$ tree glibc231-17-dbg/usr/lib/debug/ | grep -C 3 23ab4806bee6f846d9ad4bccfc29afdca49a58
    |   |-- bbfc99785d85d52809274080447c60afb87a3d.debug
    |   `-- e7a2c78df9fd9167f8c32fbca41092a487adae.debug
    |-- 03
    |   |-- 23ab4806bee6f846d9ad4bccfc29afdca49a58.debug
    |   |-- 3fe837ef5dbf5a987ae78f121073481f2cacaa.debug
    |   `-- dba2ece6c3286b575a83251fc4a587d4440591.debug
    |-- 04

では、この glibc-2.31 を使っていきます。

$ cp attack_leak attack_leak_patch17

$ patchelf --set-rpath /home/user/svn/oss/glibc231-17/lib/x86_64-linux-gnu --set-interpreter /home/user/svn/oss/glibc231-17/lib/x86_64-linux-gnu/ld-2.31.so ./attack_leak_patch17

$ ldd attack_leak_patch17
        linux-vdso.so.1 (0x00007ffdabafb000)
        libc.so.6 => /home/user/svn/oss/glibc231-17/lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a42e40000)
        /home/user/svn/oss/glibc231-17/lib/x86_64-linux-gnu/ld-2.31.so => /lib64/ld-linux-x86-64.so.2 (0x00007f9a4303a000)

このプログラムバイナリを使って、GDB を動かしていきます。まず、実行するだけなら、ページ単位で表示されてるので、正しく glibc-2.31 が使われているようです。

次に、libc6-dbg を読み込ませます。main_arena の情報が参照できました!

しかし、heap や、unsortedbin はエラーで表示できませんでした。GDB に言われるままに、set resolve-heap-via-heuristic force を実行して、再度やってみると、heap、unsortedbin も正しく表示できました!

$ gdb -q attack_leak_patch17
Reading symbols from attack_leak_patch17...

pwndbg> r
Starting program: /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch17 
UAF
heap base : 0x55555555a000
libc base : 0x7ffff7dd6000

Uninitialized
heap base : 0x55555555a000
libc base : 0x7ffff7dd6000

[Inferior 1 (process 177490) exited normally]

pwndbg> start

pwndbg> p main_arena
No symbol "main_arena" in current context.

pwndbg> show debug-file-directory 
The directory where separate debug symbols are searched for is "/usr/lib/debug".

pwndbg> set debug-file-directory /home/user/svn/oss/glibc231-17-dbg/usr/lib/debug

pwndbg> file ./attack_leak_patch17
Reading symbols from ./attack_leak_patch17...

pwndbg> start

pwndbg> p main_arena
$1 = {
  mutex = 0,
  flags = 0,
  have_fastchunks = 0,
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  top = 0x0,
  last_remainder = 0x0,
  bins = {0x0 <repeats 254 times>},
  binmap = {0, 0, 0, 0},
  next = 0x7ffff7fc1b80 <main_arena>,
  next_free = 0x0,
  attached_threads = 1,
  system_mem = 0,
  max_system_mem = 0
}

pwndbg> b 21
Breakpoint 3 at 0x55555555523d: file attack_leak.c, line 21.

pwndbg> c
Continuing.

pwndbg> heap
malloc_chunk: An unknown error occurred when running this command.
You can try `set resolve-heap-via-heuristic force` and re-run this command.

For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
malloc_chunk: An unknown error occurred when running this command.
You can try `set resolve-heap-via-heuristic force` and re-run this command.

For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
malloc_chunk: An unknown error occurred when running this command.
You can try `set resolve-heap-via-heuristic force` and re-run this command.

For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
malloc_chunk: An unknown error occurred when running this command.
You can try `set resolve-heap-via-heuristic force` and re-run this command.

For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
malloc_chunk: An unknown error occurred when running this command.
You can try `set resolve-heap-via-heuristic force` and re-run this command.

For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Top chunk | PREV_INUSE
Addr: 0x55555555ab10
Size: 0x204f0 (with flag bits: 0x204f1)

pwndbg> unsortedbin 
unsortedbin: An unknown error occurred when running this command.
You can try `set resolve-heap-via-heuristic force` and re-run this command.

For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`

pwndbg> set resolve-heap-via-heuristic force

pwndbg> start

pwndbg> c

pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555a000
Size: 0x290 (with flag bits: 0x291)

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555a290
Size: 0x420 (with flag bits: 0x421)
fd: 0x7ffff7fc1be0
bk: 0x55555555a6d0

Allocated chunk
Addr: 0x55555555a6b0
Size: 0x20 (with flag bits: 0x20)

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555a6d0
Size: 0x420 (with flag bits: 0x421)
fd: 0x55555555a290
bk: 0x7ffff7fc1be0

Allocated chunk
Addr: 0x55555555aaf0
Size: 0x20 (with flag bits: 0x20)

Top chunk | PREV_INUSE
Addr: 0x55555555ab10
Size: 0x204f0 (with flag bits: 0x204f1)

pwndbg> unsortedbin 
unsortedbin
all: 0x55555555a6d0 —▸ 0x55555555a290 —▸ 0x7ffff7fc1be0 (main_arena+96) ◂— 0x55555555a6d0

一応、確認してみます。

ヒープ領域のベースアドレスについては、ca->bk0x55555555a6d0 なので、0x6d0 を引くと、0x55555555a000 になるので、合ってます。libc のベースアドレスは、ca->fd0x7ffff7fc1be0 なので、0x60 を引くと、0x7ffff7fc1b80 となり、さらに、0x1ebb80 を引くと、0x7ffff7dd6000 となります。。あれ、libc のベースアドレスは、0x7ffff7dd5000 ですね。おかしい。

合わないので、デバッグシンボルを確認します。あ、main_arena のオフセットが、0x1ebb80 ではなく、0x1ecb80 になってます。なるほど、書籍の環境は、libc6_2.31-0ubuntu9.17_amd64.deb ではなく、 libc6_2.31-0ubuntu9_amd64.deb だったということですね。しかし、libc6_2.31-0ubuntu9_amd64.deb の方は、想定したデバッグシンボルが含まれてなかったので、使うことが出来ません。libc6_2.31-0ubuntu9_amd64.deb の形式でもデバッグシンボルを使う方法を見つけるしかありません。

$ nm glibc231-17-dbg/usr/lib/debug/.build-id/03/23ab4806bee6f846d9ad4bccfc29afdca49a58.debug | grep main_arena
00000000001eee90 b dumped_main_arena_end
00000000001eee98 b dumped_main_arena_start
00000000001ecb80 b main_arena

libc6_2.31-0ubuntu9_amd64.deb の方は、libc-2.31.so が含まれていて、想定したデバッグシンボルのファイルがふくまれていません。しかし、libc-2.31.so にはデバッグシンボルが含まれています。これを分離すればいいのでは?

ということで調べてみると、分離する方法がありました。やってみます。

$ file libc-2.31.so
libc-2.31.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter *empty*, BuildID[sha1]=634252e0c5f8b03957a2e529719d4101699a894a, for GNU/Linux 3.2.0, with debug_info, not stripped

$ objcopy --only-keep-debug libc-2.31.so 4252e0c5f8b03957a2e529719d4101699a894a.debug

$ mkdir glibc231-dbg/usr/lib/debug/.build-id/63

$ mv 4252e0c5f8b03957a2e529719d4101699a894a.debug glibc231-dbg/usr/lib/debug/.build-id/63/

GDB で確認します。ヒープ領域のベースアドレスは合ってます。libc の方は、ca->fd0x7ffff7fc0be0 なので、0x60 を引くと、0x7ffff7fc0b80 で、さらに、0x1ebb80 を引くと、0x7ffff7dd5000 になり、vmmap の結果と一致してます!

$ gdb -q attack_leak_patch
Reading symbols from attack_leak_patch...

pwndbg> set debug-file-directory /home/user/svn/oss/glibc231-dbg/usr/lib/debug

pwndbg> set resolve-heap-via-heuristic force
You are going to resolve the heap via heuristic even though you have libc debug symbols. This is not recommended!
Set the strategy to resolve heap via heuristic to 'force'.

pwndbg> start

pwndbg> b 21
Note: breakpoint 2 also set at pc 0x55555555523d.
Breakpoint 4 at 0x55555555523d: file attack_leak.c, line 21.

pwndbg> c
Continuing.

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File
    0x555555554000     0x555555555000 r--p     1000      0 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555555000     0x555555556000 r-xp     1000   1000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555556000     0x555555557000 r--p     1000   2000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555557000     0x555555558000 r--p     1000   2000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555558000     0x555555559000 rw-p     1000   3000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x555555559000     0x55555555d000 rw-p     4000   5000 /home/user/svn/experiment/shokai_security_contest/files/pwnable/05_heap/attack_leak_patch
    0x55555555d000     0x55555557e000 rw-p    21000      0 [heap]
    0x7ffff7dd5000     0x7ffff7dfa000 r--p    25000      0 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7dfa000     0x7ffff7f72000 r-xp   178000  25000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7f72000     0x7ffff7fbc000 r--p    4a000 19d000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fbc000     0x7ffff7fbd000 ---p     1000 1e7000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fbd000     0x7ffff7fc0000 r--p     3000 1e7000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fc0000     0x7ffff7fc3000 rw-p     3000 1ea000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/libc-2.31.so
    0x7ffff7fc3000     0x7ffff7fc9000 rw-p     6000      0 [anon_7ffff7fc3]
    0x7ffff7fc9000     0x7ffff7fcd000 r--p     4000      0 [vvar]
    0x7ffff7fcd000     0x7ffff7fcf000 r-xp     2000      0 [vdso]
    0x7ffff7fcf000     0x7ffff7fd0000 r--p     1000      0 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7fd0000     0x7ffff7ff3000 r-xp    23000   1000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ff3000     0x7ffff7ffb000 r--p     8000  24000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000  2c000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000  2d000 /home/user/svn/oss/glibc231/lib/x86_64-linux-gnu/ld-2.31.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000      0 [anon_7ffff7ffe]
    0x7ffffffde000     0x7ffffffff000 rw-p    21000      0 [stack]

pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x55555555d000
Size: 0x290 (with flag bits: 0x291)

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555d290
Size: 0x420 (with flag bits: 0x421)
fd: 0x7ffff7fc0be0
bk: 0x55555555d6d0

Allocated chunk
Addr: 0x55555555d6b0
Size: 0x20 (with flag bits: 0x20)

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555d6d0
Size: 0x420 (with flag bits: 0x421)
fd: 0x55555555d290
bk: 0x7ffff7fc0be0

Allocated chunk
Addr: 0x55555555daf0
Size: 0x20 (with flag bits: 0x20)

Top chunk | PREV_INUSE
Addr: 0x55555555db10
Size: 0x204f0 (with flag bits: 0x204f1)

pwndbg> unsortedbin 
unsortedbin
all: 0x55555555d6d0 —▸ 0x55555555d290 —▸ 0x7ffff7fc0be0 (main_arena+96) ◂— 0x55555555d6d0

かなり時間がかかりましたが、やりたいことは出来ました。この内容が誰かの参考になれば幸いです。

おわりに

今回は、現在、「詳解セキュリティコンテスト: CTFで学ぶ脆弱性攻略の技術 Compass Booksシリーズ」の 34章の「ヒープベースエクスプロイト」を読み進めている途中で、システムにインストールされている glibc とは異なるバージョンの glibc を使うことに挑戦してみました。いろいろと分からないことだらけではありますが、やりたいところが出来て良かったです。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。




以上の内容はhttps://daisuke20240310.hatenablog.com/entry/glibcより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14