Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Binary Exploitation - File Structure
Search
LJP-TW
June 02, 2021
Technology
1
250
Binary Exploitation - File Structure
2021/06/02 台科資安社 社課
直播記錄檔:
https://www.youtube.com/watch?v=ItpJY9Lpw-o
LJP-TW
June 02, 2021
Tweet
Share
More Decks by LJP-TW
See All by LJP-TW
Reverse Engineering - 1
ljptw
0
1.2k
Reverse Engineering - 2
ljptw
0
540
Reverse Engineering - 3
ljptw
0
450
Re:0 從零開始的逆向工程
ljptw
1
750
Linux 極入門篇
ljptw
1
270
Fuzzing 101
ljptw
1
150
Binary Exploitation - Basic 補充篇
ljptw
1
39
Binary Exploitation - Heap
ljptw
1
120
Binary Exploitation - Basic
ljptw
1
94
Other Decks in Technology
See All in Technology
SREが投資するAIOps ~ペアーズにおけるLLM for Developerへの取り組み~
takumiogawa
1
440
CysharpのOSS群から見るModern C#の現在地
neuecc
2
3.5k
心が動くエンジニアリング ── 私が夢中になる理由
16bitidol
0
100
インフラとバックエンドとフロントエンドをくまなく調べて遅いアプリを早くした件
tubone24
1
430
日経電子版のStoreKit2フルリニューアル
shimastripe
1
140
飲食店データの分析事例とそれを支えるデータ基盤
kimujun
0
170
Lambdaと地方とコミュニティ
miu_crescent
2
370
テストコード品質を高めるためにMutation Testingライブラリ・Strykerを実戦導入してみた話
ysknsid25
7
2.7k
強いチームと開発生産性
onk
PRO
35
11k
DynamoDB でスロットリングが発生したとき/when_throttling_occurs_in_dynamodb_short
emiki
0
260
これまでの計測・開発・デプロイ方法全部見せます! / Findy ISUCON 2024-11-14
tohutohu
3
370
Amazon CloudWatch Network Monitor のススメ
yuki_ink
1
210
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
The Art of Programming - Codeland 2020
erikaheidi
52
13k
[RailsConf 2023] Rails as a piece of cake
palkan
52
4.9k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.5k
A Tale of Four Properties
chriscoyier
156
23k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
0
110
Gamification - CAS2011
davidbonilla
80
5k
YesSQL, Process and Tooling at Scale
rocio
169
14k
Into the Great Unknown - MozCon
thekraken
32
1.5k
Agile that works and the tools we love
rasmusluckow
327
21k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
232
17k
Transcript
2021/6/2 NTUSTISC Binary Exploitation aka Pwn File Structure
# whoami - LJP / LJP-TW - Pwn / Rev
- NTUST / NCTU / NYCU - 10sec CTF Team 1
Outline - What is File Structure - Arbitrary Read -
With puts - With fwrite - Arbitrary Write - With scanf - With fread - With puts 2 - _IO_FILE_plus exploitation - FSOP
File Structure 3
File Structure - 你有想過你用的 stdin stdout stderr 是什麼嗎? - 在打
GOT 的時候應該會看到的東東 4
File Structure - Glibc 預設 IO 會有 buffer, 減少 syscall
的數量 - 許多 PWN 題一開始會先設定 IO 不要有 buffer, 讓 IO 單純一點 - setvbuf(stdout, 0, _IONBF, 0); - 跟 IO 相關的函數, 會使用到 stdin stdout stderr 這些變數 - 那他們的結構是什麼呢? 5
File Structure 資料結構 6
File Structure - Stdin stdout stderr 指向的是 _IO_FILE_plus 結構 -
_IO_FILE_plus 內含 _IO_FILE 結構和一個 vtable 指標 7 Ref: https://elixir.bootlin.com/glibc/glibc-2.31/source/libio/libio.h#L149
File Structure - 各種 Flags 8
File Structure - 各種 buffer - 指向 buffer 的開始、 結尾,
和現在用到的位置 - Read buffer - Write buffer - Reserve buffer 9
File Structure - _chain 將各個 _IO_FILE 串成鏈 10
File Structure - Stdin 0 - Stdout 1 - Stderr
2 11
File Structure - Vtable 存放各種函數的指標 12
File Structure Variable Definition 13
File Structure - 講完結構, 現在來看實際變數怎麼創的 - 可以看到 fileno 跟 Flag
在這邊設定 - 這邊更關心的是 vtables 被初始化為 &_IO_file_jumps 14
File Structure - _IO_file_jumps - 明確給定每個 vtable 中 的函數指標是什麼 15
File Structure puts 流程 16
File Structure - 來看看 puts 是怎麼運作的 - 幫助理解 IO 函數是怎麼使用
stdin / stdout / stderr 17 Ref: https://elixir.bootlin.com/glibc/glibc-2.31/source/libio/ioputs.c#L32
File Structure - puts 實際上就是 _IO_puts 18
File Structure - 跳過一些 code, 來看 _IO_sputn 是什麼, 是一個 macro
19
File Structure - 跳過一些 code, 來看 _IO_sputn 是什麼, 是一個 macro
- _IO_sputn(stdout, str, len) - stdout->vtable->__xsputn(stdout, str, len) 20
File Structure - 跳過一些 code, 來看 _IO_sputn 是什麼, 是一個 macro
- _IO_sputn(stdout, str, len) - stdout->vtable->__xsputn(stdout, str, len) - _IO_new_file_xsputn(stdout, str, len) 21
File Structure - _IO_new_file_xsputn(stdout, str, len) - 實際把文字輸出出來的 function 22
Arbitrary Read 23
Arbitrary Read with puts 24
Arbitrary Read - 假設能任意修改 stdout 的內部, 那麼就可以構造任意讀 - 接下來解釋原因 25
Arbitrary Read - 從 _IO_new_file_xsputn 開始追 - _flags 有啟用 _IO_LINE_BUF
和 _IO_CURRENTLY_PUTTING - count 計算 _IO_buf_end 和 _IO_write_ptr 的距離 - 後續的程式碼有用到 count, 讓 count 等於 0 省事很多 - 所以利用時, 直接讓 _IO_buf_end 等於 _IO_write_ptr 26
Arbitrary Read - 從 _IO_new_file_xsputn 開始追 - to_do 的值一開始就大於零, 若
count 為 0, 則一定能執行到 _IO_OVERFLOW(f, EOF) - _IO_OVERFLOW 最後是呼叫到 _IO_new_file_overflow 27
Arbitrary Read - _IO_new_file_overflow - 首先檢查 _flags 沒有設定 _IO_NO_WRITES -
Stdout 本來就沒此 flag, 所以不用刻意繞 28
Arbitrary Read - _IO_new_file_overflow - 檢查 _flags 是否沒設定 _IO_NO_WRITES 或
_IO_write_base 為 NULL - 是的話會進入一段妨礙利用的 code - _IO_CURRENTLY_PUTTING 本來也就有設定, 不用刻意繞 - _IO_write_base 也不會是空的, 不用刻意繞 29
Arbitrary Read - _IO_new_file_overflow - 呼叫 _IO_do_write - 從 _IO_write_base
輸出 _IO_write_ptr - _IO_write_base 個字 - _IO_do_write 最後是呼叫到 _IO_new_do_write - _IO_new_do_write 最後是呼叫到 new_do_write 30
Arbitrary Read - new_do_write - 檢查 _flags 是否設定 _IO_IS_APPENDING -
IO_IS_APPENDING 本就沒設定, 不用刻意繞 31
Arbitrary Read - new_do_write - 檢查 _IO_read_end 是否不等於 _IO_write_base -
不要走到裡面就可以直接跑到 _IO_SYSWRITE(fp, data, to_do) - _IO_SYSWRITE(fp, data, to_do) 往編號 fp->_fileno 的 fd 寫入, 從 data 寫 to_do 個字 - 所以利用時, 直接讓 _IO_read_end 等於 _IO_write_base 32
Arbitrary Read - new_do_write - data 為 _IO_write_base - to_do
為 _IO_write_ptr - _IO_write_base 33
Arbitrary Read - 結論 - 讓 _IO_buf_end 等於 _IO_write_ptr -
讓 _IO_read_end 等於 _IO_write_base - 呼叫 puts 就會輸出 _IO_write_base 到 _IO_write_ptr 34
Arbitrary Read with fwrite 35
Arbitrary Read - 如果用 fwrite 呢? - 可以看到也是用 _IO_sputn -
多了設 flag 和改 fileno 後, 照打! 36
Arbitrary Read Demo 37
Arbitrary Write 38
Arbitrary Write with scanf 39
Arbitrary Write - 假設能任意修改 stdin 的內部, 那麼就可以構造任意寫 - 接下來解釋原因 40
Arbitrary Write - 從 scanf 開始追, 他其實是 __isoc99_scanf - 內部主要呼叫
__vfscanf_internal - 其內部又主要呼叫 inchar() 一次拿一個字來處理 - inchar() 呼叫 _IO_getc_unlocked() 41
Arbitrary Write - inchar() 呼叫 _IO_getc_unlocked() - 其實是 __getc_unlocked_body() -
若 _IO_read_ptr >= _IO_read_end, 就呼叫 __uflow() 42
Arbitrary Write - __uflow - 這邊所有的 if 都設定成不要進 - 但都不用刻意繞,
就不條列這邊的 條件了 - 最後進 _IO_UFLOW() - _IO_UFLOW 最後是呼叫到 _IO_file_underflow 43
Arbitrary Write - _IO_file_underflow 其實是 _IO_new_file_underflow - 檢查 flags 有無設定
_IO_EOF_SEEN、 _IO_NO_READS - 檢查是否 _IO_read_ptr < _IO_read_end 44
Arbitrary Write - _IO_new_file_underflow - 檢查 _IO_buf_base 是否為空 - 檢查
flags 是否啟用 _IO_LINE_BUF 或 _IO_UNBUFFERED - 都不用刻意繞 45
Arbitrary Write - _IO_new_file_underflow - 呼叫 _IO_SYSREAD, 從 fp->_fileno fd
讀取字元, 從 _IO_buf_base 寫到 _IO_buf_end 46
Arbitrary Write - 結論 - 不用刻意設定什麼 flags 之類的 - 呼叫
scanf 就能從 _IO_buf_base 寫到 _IO_buf_end 47
Arbitrary Write with fread 48
Arbitrary Write - 以下是 fread 時, 打 Arbitrary Write 的
PoC - 接下來解釋原因 49
Arbitrary Write - fread 使用到 _IO_sgetn, 他呼叫 _IO_XSGETN - 最終是呼叫到
_IO_file_xsgetn 50
Arbitrary Write - _IO_file_xsgetn - _IO_buf_base 不要為空 51
Arbitrary Write - _IO_file_xsgetn - 目標是走到 __underflow() - want 為
fread 要讀取幾個字 - fread(buf, 1, 0x20, fp) - want = 0x20 - have 為 _IO_read_end 和 _IO_read_ptr 的距離 - 讓 have 為 0 省事很多 52
Arbitrary Write - _IO_file_xsgetn - 目標是走到 __underflow() - _IO_in_backup 不用刻意繞
- _IO_buf_base 不要為空, 和 前面的條件一樣 - want < _IO_buf_end 和 _IO_buf_base 的距離 - 就能走到 __underflow 53
Arbitrary Write - __underflow - 和 __uflow 長很像 - 這邊所有的
if 都設定成不要進 - 但都不用刻意繞, 就不條列這邊的 條件了 - 最後進 _IO_UNDERFLOW() - _ IO_UNDERFLOW 最後是呼叫到 _IO_file_underflow - 前面已探討過 _IO_file_underflow 54
Arbitrary Write - 如果用 fread 的結論 - 讓 want <
_IO_buf_end 和 _IO_buf_base 的距離 - 呼叫 fread 就能從 _IO_buf_base 寫到 _IO_buf_end 55
Arbitrary Write with puts 56
Arbitrary Write - 以下是 puts 時, 打 Arbitrary Write 的
PoC - 接下來解釋原因 57
Arbitrary Write - _IO_new_file_xsputn - count 為 unsigned int -
這邊若 _IO_write_ptr 很大也 無妨 - e.g. 將 _IO_write_ptr 改成 stack address 58
Arbitrary Write - _IO_new_file_xsputn - count 為 0xf…… - s
為傳入 puts 的字串字串 - to_do 為 s 的長度 - count 比 to_do 大的話, 就改 成 to_do - 將 s 複製 count 個字到 _IO_write_ptr 59
Arbitrary Read Demo 60
_IO_FILE_plus exploitation 61
_IO_FILE_plus exploitation - _IO_FILE_plus 利用手段演變 - libc 2.24 前, 可以直接改
vtable 指針 62 _IO_FILE_plus vtable fake_vtable
_IO_FILE_plus exploitation - puts 使用到 vtable 的第 7 個 function
pointer - 直接把此 function pointer 改成想呼叫的位址 63 _IO_FILE_plus stdout vtable backdoor
_IO_FILE_plus exploitation - libc 2.24 之後, 多了 vtable check, 要求
vtable 要在一定的記憶 體區間 64 _IO_FILE_plus stdout vtable backdoor Glibc detected an invalid stdio handle
_IO_FILE_plus exploitation - 既然不能把 vtable 改成除了 __libc_IO_vtables section 以外的 地址,
那就在這個區域中找能利用的函數 - libio_vtable 規定變數存在於此 section 65
_IO_FILE_plus exploitation - 讓 stdout vtable[7] 為 _IO_str_jumps 中的 _IO_str_overflow
- puts 就會呼叫到 _IO_str_overflow 66 _IO_FILE_plus stdout vtable DUMMY1 DUMMY2 _IO_str_finish _IO_str_overflow _IO_str_underflow … __libc_IO_vtables
_IO_FILE_plus exploitation - libc 2.27 - _IO_str_overflow - 目標為框選處 -
將其配成 system(“/bin/sh”) 就能拿到 shell - 後面來看怎麼配 67
_IO_FILE_plus exploitation - _IO_str_overflow - Flag 不用刻意繞, 不會進 68
_IO_FILE_plus exploitation - _IO_str_overflow - pos 為 write ptr base
距離 - _IO_len 為 buf end base 距 離 - flush_only 為 c == EOF 69
_IO_FILE_plus exploitation - _IO_str_overflow - Flag 不用刻意繞, 不會進 70
_IO_FILE_plus exploitation - _IO_str_overflow - new_size = 2 * (_IO_buf_end
- _IO_buf_base) + 100 - old_blen 不為負數就不會進 if 71
_IO_FILE_plus exploitation - _IO_str_overflow - new_size = 2 * (_IO_buf_end
- _IO_buf_base) + 100 - 最終就能來到目標處 - new_size 要配置成 /bin/sh 字串位址 - 若設 _IO_buf_base 為 0 - 則 _IO_buf_end = (/bin/sh 字串位址 – 100) / 2 72
_IO_FILE_plus exploitation - _IO_str_overflow - fp->_s._allocate_buffer 配置成 system - _s
的 offset 為 0xe0 - _allocate_buffer 的 offset 為 0 - 設定 fp[0xe0] = system 73
_IO_FILE_plus exploitation - 利用 _IO_str_overflow PoC 如下 - libc 2.27
還有很多函數能利用 74
_IO_FILE_plus exploitation - 回來複習一下 75 _IO_FILE_plus stdout vtable DUMMY1 DUMMY2
_IO_str_finish _IO_str_overflow _IO_str_underflow … __libc_IO_vtables
_IO_FILE_plus exploitation - 為何不直接改 __libc_IO_vtables 中的 function pointer 呢 -
因為此 section 是 read only 76 _IO_FILE_plus stdout vtable DUMMY1 DUMMY2 _IO_str_finish One Gadget _IO_str_underflow … __libc_IO_vtables
_IO_FILE_plus exploitation - 但是在 libc 2.29, 此 section 是可寫的, 利用變得非常簡單
- PoC 如圖所示 77 _IO_FILE_plus stdout vtable DUMMY1 DUMMY2 _IO_str_finish Backdoor _IO_str_underflow … __libc_IO_vtables
_IO_FILE_plus exploitation Demo 78
FSOP 79
_IO_list_all FSOP - 前面有提到, _chain 會把各個 _IO_FILE_plus 串起來 - _IO_list_all
紀錄鏈表的第一個 _IO_FILE_plus 80 _IO_list_all _IO_list_all _chain _chain _IO_list_all NULL
FSOP - FSOP 偽造這個鏈表 - 並通過呼叫 _IO_flush_all_lockp() 觸發攻擊 - 以下三個時機會呼叫到此函數
- libc 檢查到記憶體錯誤時 - 執行 exit 時 - main return 時 81
FSOP - _IO_flush_all_lockp 82
FSOP - _IO_flush_all_lockp - 遍尋鏈表 83
FSOP - _IO_flush_all_lockp - 若 mode <= 0 且 write
ptr > write base 84
FSOP - _IO_flush_all_lockp - 若 mode <= 0 且 write
ptr > write base - 或 vtable offset == 0 且 mode > 0, 並且 wide data 的 write ptr > write base 85
FSOP - _IO_flush_all_lockp - 若 mode <= 0 且 write
ptr > write base - 或 vtable offset == 0 且 mode > 0, 並且 wide data 的 write ptr > write base - 則會再執行 _IO_OVERFLOW 86
FSOP - _IO_flush_all_lockp - 通過前面提到的 _IO_FILE_plus exploitation - 將 vtable
中_IO_OVERFLOW 改成可利用的函數 - 並配置好對應的參數 - 觸發攻擊拿 shell 87
FSOP - FSOP PoC 如圖 88
FSOP Demo 89
Q & A 90
Thanks 疫情期間少出門勤洗手 91