
CMPT733 サイバーセキュリティラボ II プロジェクト
.
├── README.md
├── heaplens.png
├── heaplens.py
├── logs
│ ├── sudoedit-#.txt
│ └── ...
└── tests
├── Makefile
├── env-in-heap
└── ...
README.md: このファイルです!heaplens.py: メインスクリプトlogs/: 開発・テスト中に取得したサンプルログが含まれていますtests/: テスト用のバイナリ(およびそのソースコード)が含まれていますエクスプロイトのテストに使用したもの(およびバージョン)の一覧です。これらは VM に既にインストールされているはずです。不足しているものがある場合は、以下の手順に従ってください。
python 3.8.10glibc 2.34gdb 9.2gef 2022.01
gef が有効になっていない場合は、/root/.gdbinit を確認してください~/.gdbinit にある内容をコピーしてくださいsudo の依存関係(sudo で heaplens を実行する場合)デバッグが有効な sudo のバイナリが必要です。デバッグシンボル付きのビルド済みバイナリが VM にインストールされています。
cyberlab@ubuntu:~$ which sudo
/usr/local/bin/sudo
cyberlab@ubuntu:~$ sudo --version
Sudo version 1.8.31
Sudoers policy plugin version 1.8.31
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.31
cyberlab@ubuntu:~$ sudoedit -s /
sudoedit: /: not a regular file # sudo は脆弱です
これは VM で既に実行済みです。設定に誤りがある場合は、以下の手順に従って Heaplens を読み込むことができます。
gef を起動して設定を編集します:
gef➤ gef config gef.extra_plugins_dir <パス>/heaplens
gef➤ gef save
gef➤ q
これにより、ファイル ~/.gef.rc または /root/.gef.rc(root の場合)が更新されます。
~/.gdbinit または /root/.gdbinit に次の行を追加します:
source <パス>/heaplens/heaplens.py
特権プログラムをデバッグする際は、root で gdb を実行することをお勧めします:
$ sudo su
# gdb
すべてのコマンドにヘルプメッセージが用意されています。GDB 内で <command> -h を使用してアクセスできます。
heaplensmalloc、realloc、calloc、free などのメモリ割り当て・解放関数からヒープ情報を収集します。
大まかな考え方としては、これらの関数をフックすることで、コールスタックとメモリ割り当ての戻りアドレスの確認・更新プロセスを自動化できます。トレースを検査することで、どのチャンクが特定の C ファイル内の foo() によって割り当てられたかを確認でき、さらに隣接するチャンクを調べるなどして、ヒープエクスプロイトに適したターゲットを見つけることができます。
また、ユーザーが中間のヒープレイアウトに関心がある場合、その間にカスタムブレークポイントを追加することもサポートしています。
このコマンド自体はあまり冗長ではなく、結果を表示するには heaplens-dump を使用する必要があります。
heaplens -h
usage: [-h] [-b BREAKPOINT] [-v]
Collect heap info from memory (de)allocation functions.
optional arguments:
-h, --help show this help message and exit
-b BREAKPOINT, --breakpoint BREAKPOINT
stop the executions here (execute br {breakpoint} in gdb) (default: None)
-v, --verbose increase output verbosity (default: False)
出力例:
gef➤ file sudoedit
gef➤ heaplens -b set_cmnd -- -s '\\' $(python3 -c 'print("A"*65535)')
----------------------------
Initializing Heaplens
----------------------------
Temporary breakpoint 1 at 0x5840: file ../../src/src/sudo.c, line 136.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
usage: sudoedit [-AknS] [-C num] [-g group] [-h host] [-p prompt] [-T timeout] [-u user] file ...
[Inferior 1 (process 82934) exited with code 01]
Setting breakpoint at set_cmnd...
Function "set_cmnd" not defined.
Breakpoint 2 (set_cmnd) pending.
Hooking free function...
Breakpoint 3 at 0x7f25cc163700: free. (2 locations)
Hooking malloc function...
Breakpoint 4 at 0x7f25cc163110: malloc. (2 locations)
Hooking realloc function...
Breakpoint 5 at 0x7f25cc163eb0: realloc. (2 locations)
Hooking calloc function...
Breakpoint 6 at 0x7f25cc164b40: calloc. (2 locations)
Running -s '\' $(python3 -c 'print("A"*65535)')...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 2, set_cmnd () at ../../../src/plugins/sudoers/sudoers.c:804
804 ../../../src/plugins/sudoers/sudoers.c: No such file or directory.
Removing breakpoints from mem_bkps...
heaplens-dumpHeaplens ログをダンプします。結果をファイルに書き込むオプション、JSON 形式での出力、チャンクのアドレスによる並べ替えを提供します。ダンプでは、各チャンクのアドレス、サイズ、バックトレース、関連するメモリ割り当て関数がより読みやすい形式で記録されます。
heaplens-dump -h
usage: [-h] [-o OUTPUT] [--json] [-s]
Dump Heaplens logs. Writes to stdout by default.
optional arguments:
-h, --help show this help message and exit
-o OUTPUT, --output OUTPUT
write to file at path {output} (default: None)
--json dump in json (default: False)
-s, --sort sort the chunks by their addresses (default: False)
出力例:
gef➤ heaplens-dump
----------------------------
Dumping...
----------------------------
...
[malloc] Chunk 3 @ 0x55f3908ed2a0 | size 0xc
Trace:
#0 __GI___strdup (s=0x7fff6fb3b8dc "en_US.UTF-8") at strdup.c:44
#1 0x00007f285df363c5 in _nl_load_locale_from_archive (category=category@entry=0xc, namep=namep@entry=0x7fff6fb29f50) at loadarchive.c:464
#2 0x00007f285df351fe in _nl_find_locale (locale_path=0x0, locale_path_len=0x0, category=category@entry=0xc, name=name@entry=0x7fff6fb29f50) at findlocale.c:152
#3 0x00007f285df34925 in __GI_setlocale (locale=<optimized out>, category=<optimized out>) at setlocale.c:337
#4 __GI_setlocale (category=<optimized out>, locale=<optimized out>) at setlocale.c:217
#5 0x000055f3901d5965 in main (argc=0x4, argv=0x7fff6fb2a298, envp=0x7fff6fb2a2c0) at ../../src/src/sudo.c:1430
...
Dump complete.
heaplens-chunksgef の heap chunks を少し変更したバージョンを出力します。
これは GEF の heap chunks(チャンクのアドレス、フラグ、サイズ、メタデータを表示)を拡張し、heap bins(glibc のビンから以前に割り当てられ解放されたチャンクを一覧表示)からの解放チャンクに関する情報を統合します。GEF は前述の 2 つのようなヒープ検査に役立つ機能を提供しますが、これらを組み合わせるのは面倒です。大まかに言うと、このコマンドは後者から解放チャンクのアドレスを収集し、前者の結果にラベルを付けます。
heaplens-chunks -h
usage: [-h] [--nocolor]
A modified `heap chunks` with info about free chunks.
optional arguments:
-h, --help show this help message and exit
--nocolor disable ANSI color codes
出力例:
gef➤ heaplens-chunks
Showing current heap info with freed chunks:
...
Chunk(addr=0x55dd7f91ddb0, size=0xed0, flags=PREV_INUSE) ← free chunk
[0x000055dd7f91ddb0 e0 fb ba e1 f8 7f 00 00 e0 fb ba e1 f8 7f 00 00 ...............]
Chunk(addr=0x55dd7f91ec80, size=0x50, flags=! PREV_INUSE)
[0x000055dd7f91ec80 2f 75 73 72 2f 6c 6f 63 61 6c 2f 73 62 69 6e 3a /usr/local/sbin]
Chunk(addr=0x55dd7f91ecd0, size=0x4010, flags=PREV_INUSE) ← free chunk
[0x000055dd7f91ecd0 f0 02 bb e1 f8 7f 00 00 f0 02 bb e1 f8 7f 00 00 ...............]
Chunk(addr=0x55dd7f922ce0, size=0x50, flags=! PREV_INUSE)
[0x000055dd7f922ce0 90 02 91 7f dd 55 00 00 00 00 00 00 00 00 00 00 .....U.........]
Chunk(addr=0x55dd7f922d30, size=0x2da0, flags=PREV_INUSE) ← free chunk
[0x000055dd7f922d30 d0 02 bb e1 f8 7f 00 00 d0 02 bb e1 f8 7f 00 00 ...............]
Chunk(addr=0x55dd7f925ad0, size=0x110, flags=! PREV_INUSE) ← free chunk
[0x000055dd7f925ad0 00 00 00 00 00 00 00 00 10 f0 90 7f dd 55 00 00 .............U.]
Chunk(addr=0x55dd7f925be0, size=0x30, flags=PREV_INUSE)
[0x000055dd7f925be0 00 00 00 00 00 00 00 00 d2 78 b7 7e dd 55 00 00 .........x.~.U.]
Chunk(addr=0x55dd7f925c10, size=0x20, flags=PREV_INUSE)
[0x000055dd7f925c10 65 6e 5f 55 53 2e 55 54 46 2d 38 00 00 00 00 00 en_US.UTF-8....]
Chunk(addr=0x55dd7f925c30, size=0xa3e0, flags=PREV_INUSE) ← top chunk
heaplens-clearheaplens によって収集・使用されたすべての内部ログ/データをクリアします。
heaplens-clear -h
usage: [-h] [-v]
Clear Heaplens logs.
optional arguments:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
heaplens-list-envヒープに保存・解放される環境変数を一覧表示します。これらの変数はヒープレイアウトに影響を与える可能性があるため、ヒープグルーミングを実行する際に特に役立ちます。
heaplens-list-env -h
usage: [-h] [-v] [--prefix PREFIX] [--suffix SUFFIX] [-b BREAKPOINT] [-s SKIP]
List environment variables that might affect the heap layout.
optional arguments:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
--prefix PREFIX environment variable value prefix
--suffix SUFFIX environment variable value suffix
-b BREAKPOINT, --breakpoint BREAKPOINT
stop the executions here (execute br {breakpoint} in gdb)
-s SKIP, --skip SKIP skip this environment variable
出力例:
gef➤ file sudoedit
Reading symbols from sudoedit...
gef➤ heaplens-list-env -s LC_ALL -b set_cmnd --prefix C.UTF-8@ -- -s \\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
...
1st execution. Found following environment variable:
['LOCPATH', 'LC_ALL', 'LC_IDENTIFICATION', 'LANG', 'LC_MEASUREMENT', 'LC_TELEPHONE', 'LC_ADDRESS', 'LC_NAME', 'LC_PAPER', 'LC_MESSAGES', 'LC_MONETARY', 'LC_COLLATE', 'LC_TIME', 'LC_NUMERIC', 'LC_CTYPE', 'TZ', 'SHELL', 'LANGUAGE']
...
2nd execution. Possible environment variables for heap grooming:
['LC_IDENTIFICATION', 'LC_COLLATE', 'TZ', 'LC_TIME', 'LANGUAGE', 'LC_NAME', 'LOCPATH', 'LC_MESSAGES', 'LC_NUMERIC', 'LC_ADDRESS', 'LC_TELEPHONE', 'LC_MONETARY', 'LC_MEASUREMENT', 'LC_CTYPE', 'LC_PAPER']
テストケーススクリプトをビルドするには(VM にビルド済み)
$ cd tests
$ make all
tests/heap-dump のヒープレイアウトをダンプgef➤ file tests/heap-dump
gef➤ heaplens -b breakme
gef➤ heaplens-dump
sudoedit のヒープレイアウトを output.txt にダンプgef➤ file sudoedit
gef➤ heaplens -b set_cmnd -- -s \\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
gef➤ heaplens-dump -o output.txt
tests/env-in-heap でヒープグルーミング用の環境変数を一覧表示gef➤ file tests/env-in-heap
gef➤ heaplens-list-env
...
----------------------------
2nd execution. Possible environment variables for heap grooming:
['ENV_IN_HEAP']
----------------------------
sudoedit でヒープグルーミング用の環境変数を一覧表示gef➤ file sudoedit
gef➤ heaplens-list-env -s LC_ALL -b set_cmnd --prefix C.UTF-8@ -- -s \\ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
...
----------------------------
1st execution. Found following environment variable:
['LOCPATH', 'LC_ALL', 'LC_IDENTIFICATION', 'LANG', 'LC_MEASUREMENT', 'LC_TELEPHONE', 'LC_ADDRESS', 'LC_NAME', 'LC_PAPER', 'LC_MESSAGES', 'LC_MONETARY', 'LC_COLLATE', 'LC_TIME', 'LC_NUMERIC', 'LC_CTYPE', 'TZ', 'SHELL', 'LANGUAGE']
----------------------------
...
----------------------------
2nd execution. Possible environment variables for heap grooming:
['LC_CTYPE', 'LC_PAPER', 'LC_MONETARY', 'TZ', 'LC_ADDRESS', 'LC_MEASUREMENT', 'LC_IDENTIFICATION', 'LC_COLLATE', 'LC_NUMERIC', 'LC_MESSAGES', 'LC_TIME', 'LANGUAGE', 'LC_NAME', 'LOCPATH', 'LC_TELEPHONE']
----------------------------
詳細については Issues ページを参照してください。