Lazy binding - ianchen0119/About-Security GitHub Wiki
當程式是利用 Dynamic linking 的方式做連結時,其函式位址會在執行週期才確定。這樣做的好處顯而易見: 程式引入的 library 的函式有千百個,但在執行周其中並不會都使用到,當函式被呼叫時再去載入它,就可以大幅提升執行效率。
判別是否為 Lazy-binding 的方法: 當我們利用逆向工具查看組合語言時,如果有發現 call function 的形式如
call puts@plt
,就代表該函式會在執行期間才做載入。
-
GOT: Global Offset Table
GOT 其實就是一個存放函式指標的陣列。
用來記錄在 ELF file 中用到的 Shared library 中符號的絕對地址, GOT 主要涵蓋以下內容:
-
.dynamic
-
.got 儲存全域變數的位址。
-
.got.plt
Name Description address of .dynamic 指向 GOT 的 .dynamic link_map 一個鍊結串列,用來紀錄用到的 Library dl_runtime_resolve 找出函式的位址 -
.data
-
-
PLT: Procedure Linkage Table
流程
- 程式碼中呼叫了
func
- 跑去 PLT 執行
func@plt
- PLT 中的
func@plt
會跳到 GOT 的.got.plt
尋找func
的位置 - 將
func
的 id 推入 Stack 中。 - 由於
func
是第一次呼叫,所以沒辦法順利在.got.plt
找到函式位址,這時系統就會把func
的位址寫進.got.plt
當中。 - 如此一來,等到
func
第二次被呼叫時,就可以直接找到其位址。
Lazy-loading 造成的安全性問題
Lazy-binding 雖能夠大幅度的提升程式的執行效率,但也因為該機制需要 GOT 能夠被寫入,所以如果有有心人士將 PLT 的對應位置改成 system call 的位置,那呼叫 plt function
時便會變呼叫 system call
,這點需要特別注意。
如何找到 libc_base
- 方法一
ldd ./yourelf
readelf -a ./libc.so.6 | grep puts
- 取得有用到的 libc 函式,如:
puts_got
puts_got
的 value 就會等於 libc_base 加上puts_lic
(有點像是相對位置)
取得 libc_base 後,我們就可以取得指定的 libc 函式,像是: system_got 的 value = libc_base + system_libc
- 方法二 使用 one_gadget :
- 可以一次取得 libc 中 get shell 的位址
- 必須符合條件 (constraints) 且知道 libc_base
one_gadget /lib/x86_64-linux-gnu/libc.so.6