系統安全與漏洞利用

任意讀/寫原語(arbitrary read/write primitive)

一旦攻擊者藉某個記憶體漏洞取得立足點,他們就以「原語」來思考——一種可以隨意重複的基本能力,像是組裝利用程式的樂高積木。利用原語就是這樣一種能力;最受垂涎的是任意讀(能讀取攻擊者指名之「任何」位址的內容)與任意寫(能把選定的值寫到「任何」位址)。兩者合起來有時被稱為 read-what-where 與 write-what-where。

原始漏洞如何變成原語,過程如下。假設一次釋放後使用或溢位讓攻擊者能控制某物件內的一個指標欄位 p,外加一個長度。如果程式之後做了 read(p, len) 並把結果顯示出來,攻擊者就把 p 設為某個秘密位址並讀取它——那就是任意讀。如果程式做了 *p = value,而 p 與 value 都受攻擊者影響,那就是任意寫。利用程式把這些串起來:任意讀先「洩漏」一個真實的執行期位址(藉揭露程式碼或堆疊實際所在來擊敗 ASLR),接著任意寫把某個程式碼指標改向一個現已得知的目標,達成執行。第三種原語,任意執行,是最終目標——執行攻擊者選定的程式碼。一對乾淨的讀/寫如此強大,以致利用程式作者認為一旦擁有一對穩定的,這局基本上就贏了。

它之所以重要,是因為以原語思考正是真實利用實際進行的方式:不是某個神奇的單一步驟,而是把一個洩漏原語與一個寫入原語,組合著繞過每一道緩解措施。誠實的說法:單一漏洞很少直接給你完整的任意讀/寫——從「我能在這裡損毀八個位元組」走到「我能讀寫任何地方」,正是利用程式開發的主體,而像 ASLR 這樣的緩解措施存在的目的,就是要拒絕給攻擊者那些能讓寫入原語派上用場的位址。

// 攻擊者透過漏洞控制 obj->ptr 與 obj->len: show(obj->ptr, obj->len); // 把 ptr 設為秘密位址 -> 任意「讀」(洩漏) *(obj->ptr) = obj->val; // 把 ptr 設為程式碼指標 -> 任意「寫」(劫持)

同一個受控指標,依程式如何使用它,可成為讀原語或寫原語。

任意讀通常「先」出現:它洩漏一個位址以擊敗 ASLR,正是這一步才讓接著的任意寫落到一個已知、有用的目標上。

又称
arbitrary readarbitrary writeread/write/execute primitive任意讀寫讀寫原語