<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/11344

            Author:Proteas of 360 Nirvan Team

            0x00 簡介


            隨著 Xcode 7 的發布,蘋果為 Xcode增加了一個新的特性 Bitcode 【1】:

            p1

            新的特性往往意味著新的攻擊面。本文首先介紹什么是Bitcode及Bitcode相關的工作流程,在熟悉了 Bitcode的工作流程后,接下來是評估Bitcode相關的攻擊面,最后介紹針對各個攻擊面的測試方法及目前的測試結果。

            0x01 什么是Bitcode


            簡單來說,Bitcode是LLVM-IR在磁盤上的一種二進制表示形式。關于Bitcode詳細描述,請參考【2】,這里會用例子來讓大家對 Bitcode 有個感性認識。

            先寫一個簡單的 C程序,功能是計算兩個數的和,代碼如下:

            #!c
            intadd(int a, int b)
            {
                int c = a + b;
                return c;
            }
            

            將如上程序保存為 add.c,然后我們將源程序編譯成 Bitcode:

            #!bash
            clang -emit-llvm -c add.c-o add.bc
            

            執行如上命令會生成 add.bc,我們使用二進制編輯器打開生成的文件,查看文件內容:

            p2

            由于Bitcode是LLVM-IR的二進制表示形式,如上圖,在不了解編碼方式的前提下基本不可讀。下面我們把 Bitcode轉換成文本形式:

            #!bash
            llvm-dis add.bc -o add.ll
            

            用文本編輯器打開 add.ll,可以看到 add 函數的 LLVM-IR內容如下:

            #!c
            ; ModuleID = 'add.bc'
            target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
            target triple = "x86_64-apple-macosx10.11.0"
            ; Function Attrs: nounwindsspuwtable
            ; 如下是 add() 對應的 LLVM-IR
            ; 可以注意到這種表示形式會申請很多變量,
            ; 感興趣的同學可以了解下  Static Single Assignment (SSA) 
            define i32 @add(i32 %a, i32 %b) #0 {
              %1 = alloca i32, align 4          ; 變量 1,4 字節空間,后續用來存放參數 a
              %2 = alloca i32, align 4          ; 變量 2,4 字節空間,后續用來存放參數 b
              %c = alloca i32, align 4          ; 變量 c,4 字節空間,后續用來存放結果 c
            store i32 %a, i32* %1, align 4      ; 將 a 保存到變量 1 中
            store i32 %b, i32* %2, align 4      ; 將 b 保存到變量 2 中
              %3 = load i32, i32* %1, align 4   ; 將立即數 1 保存到變量 3 中
              %4 = load i32, i32* %2, align 4   ; 將立即數 2 保存到變量 4 中
              %5 = addnsw i32 %3, %4            ; 將變量 3 與變量 4 的和保存到變量 5 中
            store i32 %5, i32* %c, align 4      ; 將變量 5 保存到結果 c 中
              %6 = load i32, i32* %c, align 4   ; 將結果 c 保存到變量 6 中
            ret i32 %6                          ; 返回變量 6
            }
            

            對比源碼與已經注釋過的 add() 函數的 LLVM-IR 表示,大家應該對 LLVM-IR 有個感性認識了,下面我們一起看下Bitcode的工作流程。

            0x02 工作流程


            蘋果關于工作流程的描述:

            When you archive for submission to the App Store, Xcode compiles your app into an intermediate representation. The App Store then compiles the bitcode down into the 64- or 32-bit executables as necessary.

            如上的工作流程可以分為兩個階段:

            1. 在將應用上傳到 AppStore時,Xcode會將程序對應的 Bitcode一起上傳。
            2. AppStore會將 Bitcode重新編譯為可執行程序,供用戶下載。

            下面會將 Bitcode相關的完整的工作流程分解為如下幾個問題或子過程并分別做說明:

            1. WhereistheBitcode?
            2. 嵌入Bitcode 的方法
            3. 從 Bitcode生成可執行程序的方法

            WhereistheBitcode?

            參考蘋果的描述,只有在 Archive時才會生成 Bitcode,于是建立了一個測試工程:

            p3

            執行Archive,然后查看生成的包結構:

            p4

            經過分析在如上的目錄中并沒有直接找到 Bitcode,接下來檢查生成的 MachO。使用MachOView加載生成的 MachO,結果如下圖:

            p5

            從上圖可以看到最終的可執行程序中多了 LLVM 相關的 Segment 與 Section。繼續查看對應的Section的信息:

            p6

            如上圖,Section__bundle 中保存的是一個 xar文檔,提取出 xar文檔,然后使用如下命令解開文檔:

            #!bash
            解開:
            xar -x -f XXX.xar
            

            解開后,可以看到 Bitcode文件。

            總結:程序對應的 Bitcode被Xcode打包成 xar文檔,嵌入的 MachO中。

            下面我們看下在 MachO中嵌入 Bitcode的方法。

            嵌入Bitcode 的方法

            方法一

            通過對比 Archive與非Archive時的編譯參數,發現只要在如下圖所示的位置添加編譯參數:-fembed-bitcode,即可讓 Xcode普通編譯時也在 MachO中嵌入 Bitcode:

            p7

            方法二

            方法一雖然很方便,但是IDE做了太多工作,不便于理解具體過程,接下來我們自己編譯可執行文件。從源代碼生成可執行程序主要分為:編譯、鏈接兩個過程,為了控制這兩個過程,下面會講解Makefile的配置,及這兩個過程用到的參數。

            在使用Makefile編譯iOS程序時,有些通用的配置,如下的通用配置,供大家參考:

            #!bash
            SDK_iOS := $(shell xcodebuild -version -sdkiphoneos Path)
            CC_iOS := $(shell xcrun --sdkiphoneos --find clang)
            LD_iOS := $(CC_iOS)
            SYS_ROOT=-isysroot $(SDK_iOS)
            SDK_SETTINGS_iOS=$(SYS_ROOT) -I$(SDK_iOS)/usr/include -I$(SDK_iOS)/usr/local/include
            MIN_VER_iOS=-miphoneos-version-min=8.0
            ARCH_iOS=-arch arm64
            

            以main.m為例說明編譯需要的參數:

            #!bash
            CC_FLAGS_COMMON=-fblocks -std=gnu99 -fobjc-arc -g-fembed-bitcode
            CC_FLAGS=-x objective-c $(ARCH_iOS) $(CC_FLAGS_COMMON)
            COMPILE_iOS_OBJ=$(CC_iOS) $(MIN_VER_iOS) $(SDK_SETTINGS_iOS) $(CC_FLAGS)
            
            $(COMPILE_iOS_OBJ) -c main.m -o main.o
            

            將 main.o,AppDelegate.o,ViewController.o鏈接成可執行程序的參數:

            #!bash
            LDFLAGS=$(SYS_ROOT) \
                    -dead_strip \
                    -fembed-bitcode \
                    -fobjc-arc -fobjc-link-runtime
            LINK_iOS_BIN=$(LD_iOS) $(ARCH_iOS) $(MIN_VER_iOS) $(LDFLAGS)
            LDFLAGS_CUSTOM=-framework Foundation -framework UIKit
            $(LINK_iOS_BIN) $(LDFLAGS_CUSTOM) AppDelegate.oViewController.omain.o -oXBCTest
            

            大家把如上的 Makefile片段稍加修改,整理到一個 Makefile文件中,就可以通過 make命令嵌入Bitcode到可執行程序。

            方法三

            在這個方法中我們會將上面的步驟進一步分解,具體過程為:

            源碼-->Bitcode-->xar-->可執行程序

            如上我們介紹了在 MachO中嵌入 Bitcode的方法,對應的是第一個過程:“在將應用上傳到 AppStore時,Xcode會將程序對應的 Bitcode一起上傳”,下面我們說明第二個過程。

            從 Bitcode生成可執行程序的方法

            第二個過程為:“AppStore會將 Bitcode重新編譯為可執行程序,供用戶下載”。第二個過程是在蘋果的 Server上進行的,我們沒法直接獲得細節,但是應該都是基于相同的工具鏈,我們可以模擬這個過程。

            從 MachO中提取 Bitcode

            AppStore拿到我們上傳的 IPA后,首先需要從 IPA 內的 MachO文件中提取出包含Bitcode的xar文檔。在 Xcode的工具鏈中有個工具 segedit可以用來從 MachO提取Section,提取 xar的具體參數如下:

            #!bash
            segedit ./XBCTest -extract "__LLVM" "__bundle" Embedded-BC.xar
            

            提取到 xar后,解開xar:

            #!bash
            解開:
            xar -x -f Embedded-BC.xar
            

            得到如下幾個Bitcode文件:

            p11

            還可以使用 llvm-dis 工具將如上文件處理成可讀形式,從而了解每個文件的內容。

            生成可執行程序

            在有了 Bitcode后,接下來需要將 Bitcode編譯成可執行程序,分為兩個過程:將Bitcode編譯成 Object文件;鏈接Object文件到可執行程序。

            如上我們已經從Bitcode重新生成了可執行程序 XBCTest。

            0x03 攻擊面


            我們先回顧下 Bitcode 在本地的工作流程:Xcode將嵌入了 Bitcode的MachO上傳到 AppStore。通過分析可以發現這里存在兩個問題:

            1. MachO與其中嵌入的 Bitcode的一致性問題。即:能否把程序B的 Bitcode嵌入到程序A中。
            2. AppStore是否信任了 Xcode,而沒有檢查一致性問題,從而允許將MalformedMachO上傳到 AppStore。

            在分析了可能存在的問題后,我們認為如果Bitcode流程與功能存在缺陷,便可以對兩個目標形成威脅:普通用戶、蘋果。

            普通用戶

            由于 Bitcode對普通用戶是透明的,因此無法通過其弱點直接攻擊用戶。但是一致性問題是可能對普通用戶造成威脅的,試想:如果提交 AppStore審核的 程序A 中嵌入了含有惡意代碼的Bitcode,普通用戶就有可能從AppStore下載到含有惡意代碼的程序。

            對于這種攻擊方式我們將其叫做 Bitcode Injection,下文會詳細介紹這種攻擊的實施方法,及我們的測試結果。

            蘋果

            果MalformedMachO可以被上傳到蘋果的服務器,蘋果的服務器相較于之前,主要需要進行兩個額外的操作:解開xar;編譯Bitcode。如果這兩個過程出現問題,輕則可以在蘋果的服務器上造成 DoS,重則可以在蘋果的服務器上造成任意代碼執行。

            另外,Bitcode原本是LLVM-IR的一種序列化形式,而LLVM-IR是一種中間形式,之前沒有被直接暴露出來,現在完全開放了,而且又是二進制格式,這是很容易出問題的。從 Bitcode生成可執行文件的過程主要由如下幾個子過程組成:

            1. 基于平臺無關的 IR的代碼優化。
            2. IR的平臺相關化、合法化。
            3. 平臺相關的優化、代碼生成。

            這些原本是編譯器的內部過程,由于各種原因,傳統的對編譯器的測試主要集中在前端的 Parser 與Lexer,現在借由 Bitcode如上的一些中間或者后端過程也暴露了出來,如果如上的過程出現問題最糟糕的結果是可以控制編譯器的指令生成。

            以上是關于攻擊面的分析,后文會介紹測試xar及Bitcode的思路,以及發現的問題。

            0x04 BitcodeInjection


            上文在介紹 Bitcode工作流程時已經介紹了實施BitcodeInjection的方法,但是上面提到的方法不夠簡練,這里我們再介紹一種更簡單的方法,主要的思路就是最大限度的利用 Xcode,這個方法的具體實施步驟為:

            1. 用 Xcode建立工程XBCTest:

              p12

            2. 復制工程XBCTest,得到工程XBCTest2:

              p13

            3. 修改工程XBCTest2的源碼,嵌入惡意代碼:

              p14

            4. Archive 工程XBCTest2:

              p15

              p16

            5. 獲得MachO,利用segedit從MachO中提取出含有Bitcode的xar:

              p17

              #!bash
              提取xar:
              segedit ./XBCTest -extract "__LLVM" "__bundle" BC.xar
              
            6. 修改工程XBCTest的鏈接標記,將提取的xar:BC.xar嵌入到工程XBCTest的MachO文件中。

            7. 禁用工程XBCTest的 Bitcode特性,Archive并上傳 AppStore:

              p18

            我們在測試的過程中并沒有嵌入惡意代碼,而是從網上找個兩個完全不同的應用,將其中一個的 Bitcode嵌入到另一個的 MachO中,并提交到AppStore。

            在將應用提交到 AppStore的過程中主要會進行兩個方面的檢查:Xcode在本地進行靜態分析;提交后,蘋果的服務器還會進行檢查。但是使用 Bitcode Injection 構造的應用可以通過這兩項檢查:

            p18

            p19

            經過漫長的審核后,我們的應用被拒了,理由是:我們的應用與描述不符。在描述中我們的應用應該長成如下樣子:

            p20

            但是蘋果的審核人員安裝后,程序卻長成這個樣子:

            p21

            這至少可以說明三個問題:

            1. 我們使用的 BitcodeInjection方法沒有問題。
            2. 蘋果的審核人員審核的是從 Bitcode編譯出來的程序。
            3. 一致性是靠人肉區分的。如果嵌入對UI沒有影響的惡意代碼,還是有可能繞過審核的。

            0x05 測試xar


            思路

            對 xar進行模糊測試,生成數據的方法是基于標準的 xar文檔進行變異。

            測試結果

            目前主要 Fuzz出一些空指針解引用問題。

            0x06 測試clang


            思路

            對 clang中的Bitcode到Object 的功能進行模糊測試,也是采用變異的方法生成測試數據。

            測試結果

            通過對 clang的Fuzz我們發現了一些堆損壞相關的問題。

            0x07 總結


            1. The Xcode 7 bitcode feature has opened a huge attacking surface, Apple should do something to narrow it, for example: checking the bitcode is identical to the relatedMachO file.
            2. 在上文中我們詳細介紹了所考慮到的攻擊面,及針對每個攻擊面的測試思路,希望這些對大家研究 Bitcode相關的攻擊面及安全性有幫助。

            0x08 參考資料


            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线