CVE-2016-10277在MOTO X手機上的漏洞利用實踐
CVE-2016-10277是存在於摩托羅拉系列手機的bootloader高危漏洞,可以通過核心命令注入劫持手機的啟動流程,載入攻擊者控制的initramfs,從而達到root提權的目的。我們手上正好有一個摩托羅拉的MOTO X手機,於是參照[1]的漏洞利用過程,將CVE-2016-10277的漏洞利用過程實踐了一把,復現過程還是十分曲折。
0x00 系統環境
1.手機: MOTO X(XT1581) 2.系統韌體版本: 3.Android版本:5.1.1
在漏洞利用過程中需要用到手機boot.img中的aboot、initramfs,手機沒有root的話是無法提取系統韌體的,幸好我們在網上找到了對應的系統韌體,可以直接提取使用。
0x01 漏洞原理
CVE-2016-10277的基本原理並不複雜,主要就是可以通過fastboot向bootloader注入核心命令引數。首先我們可以通過fastoot oem config 檢視配置引數:
這些引數都未受保護,即使bootloader已鎖,仍然可以通過fastboot oem config命令配置:
漏洞就在於bootloader未對配置的這些引數進行過濾,而這些引數會直接傳遞給核心的命令列。核心命令列引數的注入會影響bootloader的載入過程,攻擊者如果精心構造某些引數,將達到控制手機啟動,甚至root提權的目的。
0x02 漏洞驗證
首先我們要先確定MOTO X是否受CVE-2016-10277漏洞的影響。
1) 注入引數設定property
執行命令:
fastboot oem config fsg-id "a androidboot.bar=1"
該命令注入了androidboot.bar=1引數,該引數如果注入成功,將會設定系統的ro.boot.bar屬性為1。當然,這裡我們只是虛構了一個bar屬性。
2) 啟動系統檢視property
執行命令:
fastoot continue
adb shell getprop ro.boot.bar
可以看到成功設定系統屬性,說明核心命令列引數注入成功,確定MOTO X受CVE-2016-10277漏洞的影響。
0x03 漏洞利用
通過該漏洞的命令列注入,我們可以向核心命令列注入眾多引數,而這些引數又會在OS啟動階段多個地方被引用,因此該漏洞的攻擊面是很廣的,這裡我們主要嘗試能否通過該漏洞進行root提權。我們首先簡單介紹下手機的啟動過程,找到其中的利用點。
1) Android手機的Secure Boot過程
MOTO系列的手機大部分使用高通晶片,而高通晶片的手機大致啟動過程如下:
[Primary Bootloader (PBL)]
`-.
[Secondary Bootloader (SBL)]
`-.
[Applications Bootloader (ABOOT)]
`-.
[{boot,recovery}.img]
|-- Linux Kernel
`-- initramfs
`-.
[system.img]
手機開機後,首先啟動的是bootloader,而bootloader又大致分為3個階段,最先啟動的是PBL,然後是SBL、ABOOT,最後通過ABOOT從boot.img或recovery.img中載入linux kernel和initramfs,進入系統載入階段。initramfs是一個記憶體檔案系統,bootloader一般會從固定的記憶體地址中載入,系統啟動後會掛載到rootfs,即根目錄/。initramfs包含很多重要檔案,包括系統啟動後第一個使用者態程序init、服務啟動指令碼init.rc、selinux策略檔案sepolicy、adbd程式等。如果我們能夠讓系統啟動時載入我們構造的initramfs,那麼我們就可以在這裡面做很多劫持動作。而CVE-2016-10277的一個攻擊面就是通過注入核心命令引數控制手機啟動時的initramfs載入地址,載入我們指定的initramfs。
2) 通過引數注入劫持initramfs載入
通過CVE-2016-10277漏洞我們可以向核心注入initrd引數,該引數控制了initramfs的記憶體載入地址,引數形式如下:
initrd=<initramfs_address>,<initramfs_size>
首先我們測試是否可以劫持initramfs的載入地址,命令如下:
fastboot oem config fsg-id "a initrd=0x12341234,1024"
fastboot continue
執行命令後我們發現手機進入無限迴圈啟動,無法進入系統,手機已崩潰,說明initrd引數起到了作用。為了驗證能否順利劫持initramfs載入,我們還需要找到可用的initramfs,並且找到向記憶體注入可控initramfs的方法。
由於不同的手機系統韌體不一樣,initramfs也不通用,我們只有通過網上下載的對應系統韌體來提取initramfs。下載韌體後解壓縮找到boot.img,使用imgtool工具提取核心檔案:
這裡的ramdisk即是我們要找得initramfs。接下來我們想辦法向記憶體中注入我們的ramdisk,可通過如下命令:
fastboot flash thor ramdisk
我們向bootloader flash一個不存在image,雖然不能刷入,但是ramdisk肯定已經存在於手機記憶體中某個位置,接下來我們需要的就是找到這個位置。ABOOT二進位制檔案中有一個target_get_scratch_address函式,該函式返回的地址就是downloaded image存在的地址,所以我們通過IDA檢視ABOOT檔案就能夠找到該地址。
ABOOT檔案存在於bootloader中,提取韌體中的bootloader.img,使用imgtool提取卻出錯了:
用010editor檢視,看到了aboot的存在,但是bootloader.img應該是做了定製,不是普通的image檔案。
使用谷歌大法,找到了一個專門用於提取moto image檔案的python指令碼https://github.com/laginimaineb/unpack_motoboot:
成功提取aboot檔案後,放入IDA檢視,由於沒有刪掉符號資訊,可以快速定位到target_get_scratch_address函式:
我們從而得到flash image時image在記憶體中的地址為:0x11000000。綜上,我們終於可以嘗試劫持initramfs的載入:
不幸的是,手機依然無限迴圈重啟。問題出在什麼地方的?由於我們看不到任何啟動時列印的資訊,也不知從何入手。漏洞的發現者做出了一個猜測,有可能是flash image後,手機的啟動過程中汙染了我們傳送的initramfs,導致initramfs被破壞。因此,我們需要將控制的initramfs填充,將真正的initramfs放到高地址的記憶體中:
.--------------------------------.----------------------.
| Physical Address | Data |
|--------------------------------|----------------------|
| SCRATCH_ADDR | Corrupted PADDING |
| SCRATCH_ADDR + sizeof(PADDING) | Controlled initramfs |
`--------------------------------'----------------------'
我們選擇padding的資料長度為32MB,
這次終於成功啟動了系統,說明我們成功劫持了initramfs:
3) 構造initramfs獲取root許可權
成功劫持了initramfs後,我們需要想辦法替換或修改initramfs中的檔案來進行root提權。我們首先解壓縮initramfs,它是一個cpio打包、gzip壓縮的檔案:
我們在sbin目錄下看到了adbd二進位制檔案,它是我們我們執行adb shell時的服務程式。
我們想要root提權,一種方法就是patch adbd程式,讓adb shell直接以root許可權執行,而不是降權執行。在AOSP的adbd原始碼中我們看到,只要我們patch掉should_drop_privileges的執行,那麼就能讓adb shell以root許可權執行。
但是,我們將adbd放入IDA一看,發現strip掉了函式符號,IDA在ARM64下沒法F5,而且廠商在AOSP基礎上做了很多定製,導致使用strings找特徵都不好使。
如果要直接patch adbd程式估計得花很多時間逆向分析,這裡我們走一下捷徑,直接分析https://github.com/alephsecurity/initrootpatch後的adbd,然後對比原來的adbd程式,分析patch點,最後根據32位程式來推測64位arm程式可能的patch點。事實證明這是一條快速通道,我們很快就對比找到了patch點:
一共兩處patch點,根據patch點的結構,我們在64位adbd中找到相似的patch點:
於是我們patch掉這兩個地方,用patch後的adbd替換原來initramfs中的程式,重新打包執行,adb shell直接就是root許可權:
通過類似的方法,我們還可以patch init程式,關掉selinux。
0x04 總結
CVE-2016-10277是一個比較有意思的漏洞,原理不復雜,只是一個簡單的命令列引數注入,但是它的攻擊面卻很廣,危害也很大。我們在復現該漏洞的利用過程中,經歷了非常曲折的一個過程。本來漏洞發現者已經給出了MOTO G4、G5手機可用的exploit,但是我們的手機是MOTO X,原來的exp都沒法用,只有自己摸索漏洞利用過程。在研究過程學習了secure boot、aboot、selinux等知識,該漏洞的利用覆蓋了很廣的知識面,值得研究。