作者:Peterpan0927@360 nirvan team
博客:https://peterpan980927.cn

use two vul and heap srpay twice

0x00.漏洞挖掘

這算是我的一個小練手吧,寫的不是很好,主要是思路分享

queryCompletion in AVEBridge

由于com.apple.AVEBridge這個模塊中的函數比較少,于是我就寫了一個比較小的C語言腳本來Fuzz一下,這個比較簡單,所以一下子就找到了:

mov rdi, [rdi+rsi*8+168]
...
call qword ptr [rax+0x1c8]

這里rsi是我們可控的一個參數,這里相當于我們可以劫持控制流做ROP進行提權,但還需要一個信息泄漏作為配合。

ReadRegister32

這是我在另一個模塊AppleIntelFramebufferAzul中找到的一個漏洞,因為我的目的很明確,就是需要信息泄漏,所以我就從有類似特征的函數進行入手了,如函數名位Readxxx,有memcpy類似的函數。

這個函數也十分簡單:

__int64 __fastcall AppleIntelAzulController::ReadRegister32(...){
    ...
    return *(a2 + a3);
}

通過逆向和調試我找到了這個函數的最上級調用是從IntelFBClientControl::actionWrapper函數開始的,通過調試我們發現傳到ReadRegister32的參數a3是用戶空間可控的,且沒有做任何邊界檢查,也就是說這個是一個越界讀,并且在它的上級函數中發現:

case 0x852:
    *(a5+2) = AppleIntelAzulController::ReadRegister32(*(this+2), *a3);

而這個a5正好是IOConnectCallMethod中要傳回用戶空間的那個outputStruct的地址,也就是說這是一個信息泄漏

getDisplayPipeCapability

這也是一個信息泄漏的問題,同樣在AppleIntelFramebufferAzul中,首先來看看一部分代碼:

//a1是this指針
v5 = *(a1+ 8 * *a2 + 0xf60);
if ( v5 ){
    if( *( v5 + 0x1dc ) && ( ! *(*(v5 + 0x3f70 ) + 0x100 ) ) ){
        memcpy(a3, (v5 + 0x2170), 0x1d8);
        *v3 = *v4
        result = 0;
    }
    else{
        ...
    }
}
else{
    ...
}
return result;

其中a2是我們可控數據且沒有做大小檢查,a3outputStruct地址,也就是說如果我們進入memcpy分支,同樣可以做到一個信息泄漏。

0x01.漏洞利用

這里我用來做提權的有兩個漏洞,queryCompletion我們可以通過參數來控制越界call,這個的利用就比較簡單,直接通過堆噴構造數據然后泄漏kslide做ROP即可,但是我們在10.13上需要尋找新的gadget,上一次還用的是project-zeropwn4fun上用的一個,一開始我的思路有問題,總想著有這樣一個pattern

...
push rax
...
...
;... is no pop
pop rsp
...
...
;... didn't change rsp
ret

但是這樣毫無疑問是自己把自己給框住了,事實上可以存在這樣的一種pattern

...
push rax
pop rsp
...
...
;... didn't change rsp
ret

而且我們的出發點可以放在二進制搜索上,直接從切入一段機器碼,不需要理會其上下文,比如我們可以在ida中搜索:

50 5c

然后通過ida的undefinecode來找到我們需要的gadget,這樣的話很快就能找到了,但是我因為思路問題卡了兩天。

接下來就是需要一個info leak來泄漏kslide了。

我一開始找到的一個infoleakReadRegister32,但是這個限制比較多,只能從一個很靠后的地址往后讀,后面基本沒有什么有效信息了,也不會有對象來給我們計算kslide。所以我在嘗試了一段時間后放棄了

后來我又找到了一個,這個的利用條件相對來說也比較苛刻(我們可以控制*a2):

//a1是this指針
v5 = *(a1+ 8 * *a2 + 0xf60);
if ( v5 ){
    if( *( v5 + 0x1dc ) && ( ! *(*(v5 + 0x3f70 ) + 0x100 ) ) ){
        memcpy(a3, (v5 + 0x2170), 0x1d8);
        *v3 = *v4
        result = 0;
    }
    else{
        ...
    }
}
else{
    ...
}
return result;

從上面可以看到我們需要滿足以下幾個條件才可以進入memcpy的分支:

  1. v5有效
  2. *(v5+0x1dc)不為0
  3. *(v5 + 0x3f70 )是一個有效內核地址
  4. *(*(v5 + 0x3f70 ) + 0x100 )為0

并且要想泄漏kslide還需要滿足一個條件,那就是從(v5 + 0x2170)(v5 + 0x2170 + 0x1d8)的地址上存在著有效數據供我們使用。

我剛一看,就有兩個想法:

就地解決

在這個對象內部來找,看看有沒有合適的,這是最簡單的一種做法,后來我在一次實驗中在偏移0x1398處找到了符合條件的,當時十分高興:

infoleak

后來想到一個問題,如果這個值超出了對象,那就是我們不可控的了,而且還有一個問題就是就算在對象內,有這么多次的解引用也不一定每次都能滿足,我重啟后果然失效了,我后來看了一下這個對象的大小就是0x1f60,果然不出所料

堆噴

另外一個就是做堆噴,來調偏移,這里我是通過mach_msg來實現的,泄漏分為兩步:

第一次先讀回來一個數據,里面泄漏了到底是哪一個消息 我們釋放這個消息,通過一個內核對象占住,第二次讀回來,泄漏對象虛表

target on MacOS 10.13 or 10.13.1

exp

poc

具體的還有一些細節問題在poc的注釋中做了一些解釋

代碼放在我的github上了

0x02.參考鏈接

labs_mwrinfosecurity

mac OS X internals 第九章


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/830/