跳转至

獲取地址

在漏洞利用的過程中,我們常常需要獲取一些變量,函數的地址,以便於能夠進行進一步的利用。這裏我將獲取地址的方法分爲如下幾類

  • 直接尋找地址,即我們可以通過反編譯等手段直接看到對應符號的地址。
  • 泄漏地址,即需要我們通過控制程序的執行流來泄漏程序中的某些符號指針的內容,來獲取對應的地址。
  • 推測地址,這裏我們一般常用的就是根據某個段內的符號之間的偏移是固定的,從而來推斷一些新的符號的地址。
  • 猜測地址,一般主要指的是,我們需要自己去猜測對應符號的地址,這裏伴隨的往往就是暴力枚舉了。

上述幾種方法,是一種遞進地考慮方式,我們在獲取相關符號的地址時,應保持這樣的思考方式。

在上面的幾種方式中,我認爲主要有兩點核心思想

  • 充分利用代碼本身的性質,比如程序某些代碼的位置就是固定的,如不開啓 PIE 時,代碼段的位置;再比如,glibc 的後三位是固定的。
  • 充分利用相對偏移的性質,這是由於目前程序加載時往往加載的內存都是一段一段的,所以相對偏移往往是固定的。

更加具體的,我們可以看如下的介紹。

直接尋找地址

程序中已經給出了相關變量或者函數的地址了。這時候,我們就可以直接進行利用了。

這種情形往往適用於程序沒有開啓 PIE 的情況。

泄漏地址

在泄漏地址的過程中,我們往往需要找到一些敏感的指針,這些指針裏存儲着要麼就是我們想要的符號的地址,要麼就是與我們想要的符號的地址相關。

下面給出幾個例子。

泄漏變量指針

比如

  1. 泄漏 main arena 中各種 bin 的頭表指針,可能就可以獲取堆中或者 glibc 中某個變量的地址。

泄漏 got 表

有時候我們並不一定非得直接知道某個函數的地址,可以利用 GOT 表跳轉到對應函數的地址。當然,如果我們非得知道這個函數的地址,我們可以利用 write,puts 等輸出函數將 GOT 表中地址處對應的內容輸出出來(前提是這個函數已經被解析一次了)。

ret2dl-resolve

當 ELF 文件採用動態鏈接時,got 表會採用延遲綁定技術。當第一次調用某個 libc 函數時,程序會調用_dl_runtime_resolve 函數對其地址解析。因此,我們可以利用棧溢出構造 ROP 鏈,僞造對其他函數(如:system)的解析。這也是我們在高級 rop 中介紹的技巧。

/proc/self/maps

我們可以考慮通過讀取程序的 /proc/self/maps來獲取與程序相關的基地址。

推測地址

在大多數情況下,我們都不能直接獲取想要的函數的地址,往往需要進行一些地址的推測,正如上面所說,這裏就重點依賴於符號間的偏移是固定的這一思想。

關於棧上的地址,其實我們大多時候並不需要具體的棧地址,但是我們可以根據棧的尋址方式,推測出棧上某個變量相對於 EBP 的位置。

這裏主要考慮的是如何找到 Glibc 中相關的函數。

有 libc

這時候我們就需要考慮利用 libc 中函數的基地址一樣這個特性來尋找了。比如我們可以通過 __libc_start_main 的地址來泄漏 libc 在內存中的基地址。

注意:不要選擇有 wapper的函數,這樣會使得函數的基地址計算不正確。

常見的有wapper 的函數有?(待補充)。

無 libc

其實,這種情況的解決策略分爲兩種

  • 想辦法獲取 libc
  • 想辦法直接獲取對應的地址。

而對於想要泄露的地址,我們只是單純地需要其對應的內容,所以 puts , write,printf 均可以。

  • puts,printf 會有 \x00 截斷的問題
  • write 可以指定長度輸出的內容。

下面是一些相應的方法

pwnlib.dynelf

前提是我們可以泄露任意地址的內容。

  • 如果要使用 write 函數泄露的話,一次最好多輸出一些地址的內容,因爲我們一般是隻是不斷地向高地址讀內容,很有可能導致高地址的環境變量被覆蓋,就會導致 shell 不能啓動。
libc 數據庫
# 更新數據庫
./get
# 將已有libc添加到數據庫中
./add libc.so 
# Find all the libc's in the database that have the given names at the given addresses. 
./find function1 addr function2 addr
# Dump some useful offsets, given a libc ID. You can also provide your own names to dump.
./dump __libc_start_main_ret system dup2

去 libc 的數據庫中找到對應的和已經出現的地址一樣的 libc,這時候很有可能是一樣的。

也可以使用如下的在線網站:

當然,還有上面提到的 https://github.com/lieanu/LibcSearcher

關於堆的一些地址的推測,這就需要我們比較詳細地知道堆裏分配了多少內存,目前泄漏出的內存地址是哪一塊,進而獲取堆的基地址,以及堆中相關的內存地址。

猜測地址

在一些比較奇怪的情況下,我們可能可以使用如下的方式

  • 使用一些暴力的方法來獲取地址,比如 32 位時,地址隨機化的空間比較小。
  • 當程序被特殊部署時,其不同的庫被加載的位置可能會比較特殊。我們可以在本地嘗試,然後猜測遠程的情況。