看了這篇文章後想自己嘗試看看,弄了好幾天總算搞出來了 owob
https://doar-e.github.io/blog/2019/01/28/introduction-to-turbofan/#setup
環境搭建
使用 Ubuntu 20.04
1 | git reset --hard e0a58f83255d1dae907e2ba4564ad8928a7dedf4 |
patch 分析
題目給了兩個 patch
nosandbox.patch
針對 chromium 的 patch,用來把 chrome 的 sandbox 拔掉,不過我這題的 chrome 一直 build 失敗就沒用這個了,只上 V8 的 patch 也不影響解題
addition-reducer.patch
針對 V8 的 patch,新增了一個 reducer
當節點是 kNumberAdd、左節點是 kNumberAdd、右節點是 kNumberConstant 時會嘗試合併節點
合併前的節點
合併後的節點
1 | diff --git a/BUILD.gn b/BUILD.gn |
看似沒問題,但在 V8 中浮點數是用 IEEE 754 表示的,大於 Number.MAX_SAFE_INTEGEER 在計算時可能會出現問題
來個例子
由於節點的資料範圍是在 typer phase 計算的,而 duplicate_addition_reducer 是在 typer phase 之後的 typed lowering phase 被執行的,且 duplicate_addition_reducer 不會更新節點的範圍,可以利用這個機制進行 oob 讀寫
typer phase
typed lowering phase
PoC
1 | function poc(a) { |
成功越界讀取
Exploit
addrOf primitive
利用乘法可以擴大讀取範圍
可以調一下 index 讓 double_arr 讀取到 obj_arr 的 elements,這樣就能 leak address%DebugPrint()
似乎會影響內存布局,這邊我用 –print-code 選項讓他印出編譯好的 assembly,找到 double_arr 載入 elements 的地方下斷點,這樣就能找到 elements 的位置,obj_arr 應該在 double_arr 下面一點的位置,慢慢 ni 然後看內存可以找到 element_arr 的 element,計算 offset 就可以找到正確的 index 了
1 | function f(trigger, idx, obj){ |
fakeObj primitive
接下來嘗試用 oob 讀取 double_arr 的 map,但失敗了
有讀到看起來很像的東西,但在後續構造 arbitrary read/write 的時候失敗了,我找不到原因所以換個方法
arbitrary read/write primitive
嘗試宣告一個 ArrayBuffer 並在函數內部宣告一個 Float64Array,嘗試找到 Float64Array 存資料的 pointer
跟前面一樣在 double_arr 載入 elements 的位置下斷點
在下面一點的地方應該有這樣的 code,這邊是宣告 Float64Array 的地方,把斷點下在 call r10
後面
1 | 0x2879719c5ce3 123 48b90122804a61180000 REX.W movq rcx,0x18614a802201 ;; object: 0x18614a802201 <ArrayBuffer map = 0x34559a284aa1> |
下 c
找到 double_arr 的 elements 之後下 c
,double_array 後面應該會有 Float64Array,找到指向 buffer 的 pointer
1 | gef➤ x/32gx 0x367469ba1c41-1 |
但 0x18614a802201 是個 object,真正存資料的地方是在 0x000055aeca03d1f0
這裡,這是一個 heap 上的位置
1 | gef➤ telescope 0x18614a802201-1 |
而這個東西也在 double_arr 的附近,可以用 oob 改成我們要操作的 address 並回傳一個新的 Float64Array,這樣就有任意位置讀寫了
1 | var rw_buffer = new ArrayBuffer(0x100); |
透過 wasm 寫入 shellcode
後續利用就很簡單了,透過任意寫竄改 wasm 的內容就可以了
成功彈出計算機
1 | var buffer = new ArrayBuffer(0x10); |