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