iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 11
0
Software Development

從 Rust 往程式底層前進系列 第 11

Stack Overflow 3 - ASLR

  • 分享至 

  • xImage
  •  

這篇要來講上一篇沒講完的部份,不知道你有沒有實際去試試看,如果不用 gdb 的話那個測試 RCE 的實驗還跑不跑的起來呢?如果你有試過就會知道答案是跑不起來,所以這又是發生了什麼事,上次談到堆疊的程式碼預設是禁止執行的,這只是其中一個保護機制而已,今天要來談談另一個保護機制 - ASLR

ASLR 的全名是 Address Space Layout Randomization ,它讓每次程式以及動態函式庫的載入位置都不相同,以防止你能填入固定的位置到堆疊中的返回位置中,這使得 buffer overflow 造成的 RCE 在現今的作業系統中變得幾乎不可能做到,你可以試著準備個簡單的程式,反覆執行,並在執行中看看 maps 中的位置是不是每次都不同,像這就是我隨意的兩次的執行 cat 的結果

55d02d7b9000-55d02d7c1000 r-xp 00000000 08:04 1706314                    /bin/cat
55d02d9c0000-55d02d9c1000 r--p 00007000 08:04 1706314                    /bin/cat
55d02d9c1000-55d02d9c2000 rw-p 00008000 08:04 1706314                    /bin/cat
55d02ec91000-55d02ecb2000 rw-p 00000000 00:00 0                          [heap]
...
55d2e94a1000-55d2e94a9000 r-xp 00000000 08:04 1706314                    /bin/cat
55d2e96a8000-55d2e96a9000 r--p 00007000 08:04 1706314                    /bin/cat
55d2e96a9000-55d2e96aa000 rw-p 00008000 08:04 1706314                    /bin/cat
55d2e9b7e000-55d2e9b9f000 rw-p 00000000 00:00 0                          [heap]
...

那為什麼 gdb 又可以執行出預期的結果呢?其實答案也很明顯, gdb 把 ASLR 關掉了,不然的話每次除錯時,上次記下來的記憶體位置就會失效,下中斷點或是要看變數的值就很麻煩啊,在 gdb 中你可以用這個指令來看有沒有關閉 ASLR :

>>> show disable-randomization
Disabling randomization of debuggee's virtual address space is on.

也可以去設定它的開關

>>> set disable-randomization off

那如果要在不用 gdb 的情況下成功跑這個實驗的話,除了關掉整個系統的 ASLR 外還有個是用 setarch 的做法,我比較偏好這個:

$ setarch $(uname -m) -R <執行檔位置> < input
Hello from shellcode

shellcode

另外講一下,前一篇的範例中把要執行的程式碼稱為 shellcode , shellcode 是指那些利用漏洞而得以執行的程式碼,會叫做 shellcode 是因為通常它會開一個 shell 出來,畢竟對攻擊者而言,取得控制權才是最重要的事

以前對於 shellcode 方面其實有不少的研究,比如製作出不含 \0 的 shellcode ,甚至是完全以英數字編碼的 shellcode 也有,但在 buffer overflow 變得難以成功後這方面的東西似乎也比較沒有看到了,現在比較多的是反序列化造成的漏洞,比如像 python 的 pickle

import pickle

class Demo:
    def __reduce__(self):
      return (print, ("Hello world",))

pickle.loads(pickle.dumps(Demo()))

上面這段程式我用 python3.6 測試過,請注意字串後的 , 是必要的,沒意外的話應該會印出 Hello world,序列化是指把程式裡的物件轉成特定的表示型式,以便於交換資料,而反序列化則是把資料還原回物件,像 json 也算是其中一種格式,只是有些語言內建的序列化與反序列化太強大了,還可以從資料還原回任意的自訂的資料型態之類的,這就很容易遭到利用,在 pickle 中是因為它可以自訂這個型態要用什麼方式還原,於是這邊就設定讓它用一段字串當參數去呼叫 print

關於 stack overflow 的文章就到這邊結束了,下一篇要來看看我們的 main 真的是程式開始執行的點嗎?


上一篇
Stack Overflow 2 - RCE 與 DoS
下一篇
在 main 函式之前
系列文
從 Rust 往程式底層前進26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言