對于廣大的開發者而言,和URL 并不陌生。一直以來都是iOS的核心組件,而URL 是iOS APP重要的接口之一。
由于目前接口安全性研究較少,已有的研究也主要集中在系統,忽略了iOS 應用的安全性。下面就讓我們來回顧看雪2019安全開發者峰會上《是誰推開我的“窗”:iOS App接口安全分析》的精彩內容。
編輯按
:在廣闊的網絡世界,或許你在瀏覽器上的一次點擊都會觸發你手機上已安裝的應用的漏洞,進而導致賬號被盜、財產丟失、數據泄漏……
導致這個問題的原因是開發者沒有在外部可調用接口上部署權限檢查或過濾有害調用。所以,開發者應當時刻將安全放在首要的位置上!
嘉賓介紹
張一峰,北京長亭科技移動安全負責人,負責移動APP安全審計、源碼審計等漏洞挖掘工作。全球互聯網技術大會網絡安全專場演講嘉賓,2018華為終端安全獎勵計劃大會圓桌會議嘉賓,2018 Demo Labs 。
大會上講師首次披露了由于iOS APP URL 和接口導致的安全漏洞,完美的體現了“不知攻焉知防”。通過把過程接口調用可以利用的方式,在iOS平臺上實現可攻擊的效果和注入等方式,最后還幫我們做了防范和總結,希望大家注意iOS開發里的那幾點。
演講具體內容
以下為速記全文:
大家好!我是來自長亭科技的張一峰,我分享的題目是APP接口安全分析。
議題主要內容有這么五方面:第一,業務開發模式變遷,第二,混合開發模式,第三,漏洞成因和漏洞基礎,第四,實例展示,因為接口設計的缺陷導致的安全問題,第五,總結以及開發建議。
一
移動開發模式變遷
在開發模式變遷的時間軸,上面是一些時間節點,下面是相對應時間段在移動開發中和iOS使用的主流開發語言。
2007年和iOS問世,最初主要以java和oc作為編程語言,隨后谷歌增加了c和c++的支持。后面由于html5技術的發展,逐漸出現了純WEB的應用,不只是移動端,其它也會有,蘋果在這期間推出了它的新開發語言swift,同時,谷歌也官方支持了語言進行開發。
但是由于存在缺陷,后面人們更多使用混合開發模式,也就是當前比較多的開發模式。截止到現在,從最初的java、oc,到現在官方主流推薦使用和swift開發,所以經過10多年變遷,有很大變化。同時,因為有混合開發模式,還有著js和HTML。
二
混合開發模式
從時間線來說,從原生到WEB再到混合開發模式,但是從邏輯角度來說,混合開發模式放在中間是更合適的。原生開發模式很好理解,我們用官方提供的語言,調用的接口實現我們APP的功能。在里完全依賴于這個組件使用純前端技術,我們APP的功能和邏輯主要由js實現。
而混合開發模式是原生和web的混合,它相當于二者間的一個結合點。主流APP的調用還是依靠原生代碼進行調用,對于一些業務應用,比如更新比較頻繁的,或者可能每天都會變化的業務,我們會使用純web進行展示和渲染。
為了引出混合開發模式,就不得不提里面的優缺點,優點是跨平臺、開發成本比較低,但缺點也很多,其中比如主要的就是它對復雜算法、多編程等等支持不是很好。
同時,因為js能做的最多是壓縮和混淆,它對以前的代碼而言,與編譯之后的二進制相比,對源代碼保護還是有很多不足的。同時,有個最重要的缺點是與原生API交互是非常不方便的。
基于這個原因,人們開始逐漸使用混合開發模式,混合開發模式繼承了里的很多優點,通過手段避免了很多API調用的問題。是什么?它是js代碼到原生代碼的接口,大家把它形容為像一個橋一樣。
通過這個橋,我們的API還是由原生的代碼進行調用。其實的功能并不是在混合開發模式中從零做出來的,它類似的功能在系統API本來就已經提供了,只不過在混合開發模式中程序員對API進行了一定的封裝和擴展。
下面舉個能實現這樣功能的API,上面是,下面是,可以實現的功能,后面還有相應API的例子,這里面就不再詳細說了。
基于這個API有一個使用很多的框架,就是這個dage框架,它就是對API進行封裝,跟著框架所做的主要貢獻是增加了回調函數,也就是說它能獲取的返回值。
正常來說,我們通過這個API只能進行傳參、調用,但是如果獲取的返回值,所以在復雜業務里是有缺陷的,這個框架主要是增加,能通過獲取它的返回值。
另外一個是的和er,它也都分別有對應的API可以實現這樣的功能。后面有例子,這里就再不繼續展開。
說到這樣的功能的API就不得不提安卓平臺下這個接口,這個接口也是為了實現同樣的接口,但是在2012年被人們發現它可以實現一個遠程任意代碼執行,這個漏洞影響特別深遠,很多做開發的哪怕不懂安全,但在寫代碼時都會用一個API判斷是否大于17來避開這個漏洞,其實這個地方是容易發生安全問題的。
三
漏洞成因和漏洞接觸
首先介紹一下iOS 里的一種,就是,它是提供了應用間IPC的方式,也就是說通過可以調取另外一個應用再進行返回。怎么使用這個技術?其實非常簡單,只需要在xcode中進行注冊,然后實現回調就可以了。
這個大概長這個樣子,它是遵從這三個規范,通過API可以傳回里哪個字段的值,一個應用如果自定義了,其他第三方應用就可以對它進行調用,同時網頁也可以進行調用。這個也是我們后面例子中遠程進行攻擊的一個非常依賴的點。
其實也不是大家隨便可以調的,它是有一個權限限制的,就是需要用戶交互的,類似于讓用戶授權一樣,如果通過網頁進行調取的話,需要用戶點擊打開,如果是應用的話,在第一次是需要用戶進行授權的。
但那個授權其實相對來說是一個很寬泛的,它并不像強制訪問控制,它只是一個需要用戶點擊和確認就可以了,用戶很難去分辨。
說到,我們下相對應的代碼怎么去用它,前兩行代碼是里面,已知,去調取的話很簡單的兩行代碼就可以用這個open函數進行調用了,如果是js的話也非常簡單,一個鏈接就可以了,我們可以通過js里面這種自動點擊的方式進行自動調用也可以。
被動應用會進行回調函數,也就是最下面的函數,這個函數里它會獲取傳輸的參數,然后根據這個參數再執行相應的邏輯。
剛剛說有幾個API可以實現的功能,這里選了兩個API,選了兩個例子,讓大家對實現有個了解。上面是我們的前端鏈接,這里面是自定義的一種,并不是常見的。
當這個鏈接被請求的時候,系統的這個函數就會被毀掉,相當于對我們請求的鏈接進行攔截。如果我們這里面自定義了一個,這里就可以判斷這是不是我們自定義的,也就是說前后端對應好就可以實現通信,這里可以把傳輸參數取到,實現類似于偽協議的這樣一個通信。
通過這個可以實現從前端到后端的調用。另外一個是里的函數,它和上一個區別是你可以自定義這個函數的名字,前端你可以認為它是JS函數進行調用,但是它其實也會進入這個代碼,在這個代碼可以進行獲取參數。
有了上面那些基礎知識,就引出了接口漏洞的成因:首先,因為自定義的第三方,實際應用中你可以去市場中看,基本都有,基本是可以滿足的。
定義以后,其他的應用或者網頁可以對它進行調用,調用完程序可以執行和對應回調函數,這個回調本身可能就存在一些缺陷。
如果回調函數本身沒有什么特別的,我們需要關注它是不是有可能加載任意的URL,如果能加載任意的URL,也就是說我們可以執行我們任意的JS代碼,執行任意的JS代碼,如果恰好實現很多,我們就可以對接口進行調用,這種接口可能存在缺陷。兩種情況都不符合的話,有其他方式允許應用加載這一段。
為了更好理解下一部分實例里的代碼,這里簡單講一下OC運行時。OC是面向對象語言,它是一個大家接觸比較多的消息轉發機制,它在匯編層面發生函數對話時,它并不是直接把PC指針跳轉到目標函數的地址,它是有個的函數,把這個函數調用封裝,但這個函數調用其實還是通過這個跳轉過去,但是它相當于把這個消息進行轉發,其實是oc里多態的一種實現。
所以oc里面的多態相當于是在這運行池進行確定的。除此以外,運行池還提供的方式,可以理解為函數名字,但其實不是。如果把這個函數名傳里面去也可以實現函數調用,你不需要在程序里用形式把它包起來。
四
案例分析
案例1:遠程竊取的漏洞。
我們首先看它的info.的文件,因為最根本是在這個文件里。這里面我們發現它有一個自定義的,有了這個以后我們就要去看它的回調函數,它的回調函數邏輯很長,這里只是把相關的函數摘出來了,我們會發現它會進入這里,這里是做什么呢?它首先把我們傳輸的以字符段的形式取出,然后拿到問號之后的字符,然后以的形式進行解析。
因為是我們傳入的,所以這是一個可控變量。這段所要需要查詢的,就是在標準里query這個字段,它是格式的。進而判斷是否有Key為type的字段,這跟我們沒關系,就跳過了。
我們主要看它的eLse值,Else值里會判斷是不是有Key的URL,如果有的話它繼續判斷是不是這個開頭,如果兩個check都符合的話,它會把這個value傳給r。
下面是前端的代碼,相當于是把這個View壓到棧的最上面,把它渲染和展示。有了這個代碼我們就知道最終需要傳輸的就是這個樣子,我們的K是URL,然后對應的value,前面是字符串URL,后面是鏈接。這個程序把我們傳輸的鏈接會進行渲染出來,然后同時也沒有進行任何的校驗。
我們讓它打開我們的鏈接并不是真正的目的,所以我們還需要繼續往下分析,如果它打開我們的鏈接,因為這個服務器是我們自己的,我們可以在這里寫任意的js,任如果它定義了接口的話,我們就可以調用它的接口。
我們看一下這個,為了實現這個遠程攻擊,你可以把這個寫到一個網頁里。分析時發現它在初始階段進行初始化了,初始化最重要的是這個ler這個地方,它是前面說到那個框架里面的用法,在這里面相當于前面也注冊了名字就是函數的名字,然后第二個是函數名字所對應的操作。
所以最終發現在我們加載頁面里實現的效果,我們可以調用這個類下面的任意函數。
既然可以實現函數調用,我們就看看這個類下面有什么函數值得我們調,發現了有這個這個函數,根據函數名字感覺像獲取用戶信息,我們就需要去驗證一下是不是我們想要的樣子。所以嘗試一下,然后斷下來,發現它傳輸的有電話號碼、UID、和token。
最后就呼之欲出了,我們調用接口,達到最終的數組,這個數組不是最終目的,我們把它發給遠程服務器。這個頁面里通過這個方式,把拿到的token和發送給我們的服務器。
因為這個頁面本身就是www,所以它是符合策略的。這是我們實際在服務端收到一個請求,發現token和手機號都可以發送給我們。拿到token以后相當于對這個帳號實現了控制,而且在移動端里有個特點,就是token的有效期比較長。
案例2:任意文件上傳漏洞。
我們還是看info.plist,它有自定義的,這個案例本身可以完全不依賴于加載自己頁面本身,這可以完全挑過,因為這相當于實現問題比較多,從很多方面都可以去打。
同時為了實現遠程攻擊,你也可以把嵌到網頁里。說到嵌到網頁里剛剛忽略了一個點,它需要有授權,這里最方便的方式是可以以領紅包等等之類的方式,因為使用手機的都知道,基本所有都在用的應用,比如第三方支付、朋友圈分享等等底層都會用到這個機制,所以對普通用戶來說,很難分辨一個跳轉是惡意的還是真正的業務功能。
這個里面它使用的。這個處理,傳輸的最終會進入的URL里面,在這個里面它會首先判斷這個是不是等于空,如果等于的話它進一步查詢URL參數進入,進入下面的這個函數。
在這個函數里它獲取里面的和args,這時我們還不知道它是干什么用的,但是我們知道URL是我們傳入的,這個是個可控變量,也就是說它所查詢到的參數也是我們可控的。這里面它有一個權限驗證,就是它判斷你是不是有權限調用這個API,但是這個驗證是存在缺陷的。
然后就進入下一步,也就是說這兩個參數我們知道是可控的。這里面首先會調用權限調用這個函數,這個函數里面會把前面加一個,把構造好的傳給,這個我們在剛剛講oc運行池時提過這個函數,這個函數傳入的相當于是對這個的調用。
分析到這,我們就分析它其實可以實現的效果是對下面的以“jsapi-”為開頭,以為結尾的任意函數調用,我們就可以利用這個任意函數調用去做些有意思的事情。
所以我們要分析這類里面到底有什么函數值得我們調用。我們發現它有一個的函數,因為它符合這個命名,我們分析這個函數,發現它首先會拿到這個函數的URL字段,還有一個path字段,其實這個URL是它上傳圖片目標的服務器地址,path是你要上傳文件的路徑。有了上面一些已知信息,我們最終的就出來了。
開頭是jsapi,也就是我們過它第一個check,是你所要調用的函數名,我們這里面傳入剛剛看到的,在這里面要傳送兩個關鍵字,一個是URL,一個是pathjs跨頁面傳值敏感信息,URL是我們自己的服務器,也就是說把沙箱里的文件上傳到我們自己的服務輕易松手,path是沙箱里的一個文件。
所以在POC里上傳沙箱里的數據庫。這個例子里面為什么剛剛我說其實不需要加載任意URL那個地方?因為你完全可以把上面的load寫在最初的網頁里,只要跳轉這個目標應用,攻擊在一瞬間就完成了。
分析了很多ios平臺發現,發現回調函數里利用OC運行時進行函數動態調用的非常多,占比最大。這個例子可以看出你傳輸的字符是不是以某個數字開始,如果以某個數字開始就會調用某個函數js跨頁面傳值敏感信息,所以相當于傳輸一串數字就可以調用里面很多函數。實際分析下來,確實有很多這樣的案例存在,是一個非常危險的東西。
案例3:業務邏輯漏洞。
因為之前我們已經對怎么去確定是什么樣子的,所以在這里我們就把這兩個都跳過了,因為可是于這幾個實例是內容依次變少了,因為有很多東西思路是重復的,但代碼不一樣。
這個應用里,它為了實現增強網頁里面的功能,它不單是加入了很多內存這樣的函數,而且加入很多插件。可以通過插件ID調用這里面很多插件,我們從它可以調用的插件里發現了很引起我們興趣的東西就是這個,就是它本身自己帶了一個支付功能的應用。
所以我們把這個ID傳入,作為傳進去,它的參數里有一個很重要的,也就是說我們可以生成訂單,但是我們先不支付,然后我們作為發過去,可能導致支付風險,就是可能支付別人那去了。
當然,這個最終使用還需要依賴其他條件。但是這個例子充分說明了,對于支付類的SDK詳細顯示購買商品和金額是一個特別必要的事。之前交大他們做第三方支付研究時,也介紹過這一點。這個例子也是本地和遠程都可以打的。
這里我們做個階段性小結:之前我們演示的例子里主要是以文件讀作為我們利用的一個點,我們自然而然想到文件寫是不是也可以。同時,除了我們利用通過API這樣的方式、這樣的,還有沒有其他JS接口可以供我們調用?在攻擊方式上,我們剛才講了通過和的形式進行遠程攻擊,那還有沒有其他方式?
下面看下JS代碼執行情況,就是在ios9還是ios8,引入了一個更為安全、性能更高的。有一個新特性是支持JS注入。在下面的代碼里,可以把沙箱的這個JS插入到頁面中,以這個加載到前端頁面都會自動引入我們一個JS進去。
被插入的JS長什么樣子?大概這樣子,它也會定義很多函數。對JS程序而言,它可以當作自己實現的函數一樣進行調用。JS會駐留在所有網頁中,它會定義很多函數,效果類似于,如果存在剛才案例中的情況,我們依然可以通過調用這樣的函數進行滲透。
如果剛剛我們備注的JS存在沙箱或者遠程的話,結合文件寫等等,我們把本身給重寫了,就可以實現XSS。如果熱更新,當然,熱更新現在已經被蘋果禁止了,如果有熱更新的話也可以實現效果。
下面看一個代碼執行的例子,這個代碼執行的例子里,它首先是判斷這個是不是等于這個字符串,如果等于的話它會post這個,這個到底是什么?
它是ios里一個應用內部通信的機制。在之前都會調用這個的API,類似于把這個先注冊,注冊時會傳輸這個東西叫什么名字,它對應的是什么,也就是說它要執行的函數是什么。
所以在這個例子里,我們只要傳輸,它這個字符串進去,就會導致這個函數被執行。但這里其實并沒有實現任意代碼執行,但是如果被執行是一個非常敏感的函數或者結合其他漏洞的話,還是可以進行利用的。
剛剛我們說了遠程觸發,除此之外還有一個經常被別人忽略的二維碼掃描,這是普遍大家都在使用的一個方式,APP里面定義一個名以后,它可能在很多地都用同一個名進行加載,只不過這個URL傳輸的方式不一樣。
所以利用二維碼掃描也是可以做到的,在之前我們團隊有同事做過類似的活動,掃描二維碼就可以把你的照片發送給遠端服務器。
再一個是后臺觸發,但是這個利用難度就比較大了,因為后臺權限是很難拿到的。但是這個比較有意思的一點是什么?如果把攻擊向量放在后臺,它是可以打所有前端,也就是說你的服務器可以打這個業務里所有的客戶端,這是觸發方式里比較有意思的一點。
五
總結以及開發建議
說一下怎樣發現漏洞以及發現漏洞的思路是什么。首先,看看定義情況,如果有的話我們就看它的回調函數以及重點關注它有沒有加載URL這樣的操作。
另外,看看它有沒有通過二維碼或者其他方式加載任意URL。最后,對它我們可以調用的接口進行分析,看有沒有可利用的點。
在開發定義里面說幾點:iOS生態比安卓做得好多,也一定程度上保證了安全性,但是應用安全并不能完全依賴于系統安全。第二,對于使用建議保證最少原則,因為增加一個就相當于增加一個接口,增加一個接口就增加一個風險。
在混合開發模式中,這種核心敏感的操作建議使用原生代碼進行開發。外部可調用接口一定要嚴格過濾調用者,確??尚拧1热鐒倓偟睦?,如果我們在那個位置的check過不了的話,后面也就無從談起了。
最后,對本身是一個非常容易出現漏洞的組件之一,實際開發中又很難避開它去不用,所以在開發中要注意已知和未知的安全漏洞。
安全研究視角看macOS平臺EDR安全能力建設
公眾號ID:
官方微博:看雪安全
商務合作: