WebView是App中的一個核心元件,也是App內部與Web世界互動並呈現給使用者的一個視窗,目前已廣泛應用於很多 App中。
但自誕生伊始,Android WebView就充斥著各種各樣的重大漏洞,這既與系統WebView有關,也與WebView複雜的使用有關,導致其容易被開發者誤用。
毫不誇張的說,WebView已成為Android App中最重要的遠端攻擊面,也是最容易出現重大漏洞的薄弱環節。
下面就讓我們來回顧看雪2020第四屆安全開發者峰會上《Android WebView安全攻防指南2020》的精彩內容。
演講嘉賓
何恩,OPPO子午網際網路安全實驗室安全專家,專注於Android 安全,擅長Android App和框架層的漏洞挖掘,獲得過幾十個Google Android VRP和GPSRP安全致謝,在原烏雲知識庫、先知安全論壇和OSRC公眾號發表過多篇有影響力的Android安全文章。曾任中國電科第三十研究所安全專家,安全領域從業16年,在CNCERT 2016和POC 2018安全峰會上發表過有關Android安全的技術演講。
演講內容
以下為速記全文:
大家好,我是何恩,我今天給大家帶來的是一個有關安卓APP應用安全攻防的議題。這是我的一個自我介紹,我所擅長的領域主要還是在安卓的AOSP框架層和APP層面的漏洞挖掘。
我今天分享的內容包括以下五個方面,首先會從Android WebView誕生時期的漏洞講起,介紹其安全攻擊面,從而引出它的安全配置和使用,然後介紹目前經常出現的URL白名單校驗問題,接下來是安全防禦的實踐,最後是總結。
一.WebView攻擊面
首先介紹Android WebView漏洞的基本模型。WebView是安卓APP內部的一個瀏覽器,是APP與外部世界交流的視窗。由於它的功能非常複雜,商業化的需求導致它的功能繁多,配置也非常多,此外它還有眾多的JS層面的回撥函式,導致Android WebView容易出現一些比較嚴重的安全問題。Android WebView漏洞的根源就在於強制其訪問了攻擊者控制的網頁。由於網頁中含有攻擊者可以控制的JS,因此可能釣魚、竊取私有目錄檔案、甚至是RCE,帶來比較大的危害。
從Android WebView的攻擊面來看有三類,常見的就是透過Android WebView本地的通訊介面,第二個就是一個遠端攻擊面,使用者透過點選一個APP自定義的偽協議從而拉起WebView訪問攻擊者可控的網頁,除此之外還有一些特殊的攻擊面。前面已經有嘉賓分享了針對瀏覽器核心的方面,而今天我分享的議題則是主要在於WebView的不當配置和使用。
回顧WebView的攻防發展歷程,在其剛剛開始使用的時候,在安卓5.0以下,4.4版本左右的時候,大家比較關注的漏洞就是系統的JsInterface介面暴露。有研究者發現可以透過這個去反射執行任意程式碼,從而導致RCE,這在當時非常常見,也是安卓中非常著名的漏洞。
在WebView使用的中期,可能兩年前左右,我們可以看到一些由於WebView跨域配置不當導致的私有檔案竊取的漏洞,當時玄武實驗室把漏洞的危害進行了放大,如果對APP的所有私有檔案都進行了竊取,甚至可以把受害使用者的身份資訊克隆到另外一個裝置中去。
而現在,我們可以看到形形色色的WebView漏洞,主要是由於URL校驗不當,從而導致載入任意網頁或者是呼叫一些特權介面。
回顧歷史漏洞,就是在Android 4.4之前,系統存在JavaScriptInterface介面,可以被反射呼叫執行任意程式碼。之前我挖掘過一個某地圖APP的漏洞,它開放了一個埠號為6677的網路埠,我們可以透過訪問這個網路埠去操縱APP內部的WebView,並訪問攻擊者可控的網頁。雖然這個漏洞是比較古老的,但從安全編碼的角度來看,還是建議開發者去除系統中不用的JsInterface介面。
二.WebView的配置與使用
接下來我們看一下WebView的配置與使用。其實有關WebView的配置與使用主要是集中在下面的設定當中,當setAllowFileAccess為true,下面的任一設定為true時,攻擊者可以利用WebView的漏洞竊取APP任意目錄下的私有檔案。這也是一個非常常用的手法,這個操縱是需要WebView去下載惡意JS到手機中的公共儲存區,然後透過AJAX去竊取私有檔案。當時的應用克隆應該就是利用了下面這種手法。
仍然只有setAllowFileAccess為true,其他兩個設定均為false時,是否仍然可以竊取檔案呢?答案是肯定的,第二種手法在WebView早期版本中有效,我把它稱之為移花接木。
它透過軟連結的方式去竊取任意私有檔案,這就意味著WebView不做任何設定(因為setAllowFileAccess為true是預設的),攻擊者就可以WebView訪問任意URL的漏洞來竊取使用者APP的私有檔案。
其攻擊過程首先是操縱WebView去訪問一個攻擊APP自己公開出來的網頁,然後這個網頁執行的內容其實就是延時去讀取自身。在延時讀取自身的時間視窗內,這個檔案悄悄被進行了替換,替換成了軟連結,指向受害APP的一個私有檔案,最終讀取竊取其內容。
其實還有一種方式。這個方式目前沒有在公開場合被披露過,但在最近的一些WebView的版本上它仍然是有效的。在WebView存在訪問任意URL的情況下,仍然只有setAllowFileAccess為true,如何放大攻擊的危害呢?我把它稱為含沙射影,主要思路是去汙染Cookies。
首先,讓受害APP的WebView訪問攻擊者可控的網頁,該網頁設定一段特殊的Cookie,也就是在受害APP的Cookies檔案中寫入payload。
接下來攻擊APP再次操縱WebView去訪問自己開放的網頁,這個網頁其實是一個軟連結,指向受害APP自己的Cookies檔案。透過這樣的一個過程,就能操縱受害APP去載入自己的Cookies檔案。因為這個檔案是自己的,所以一定能夠載入出來,但是這個檔案已經被我們汙染了,裡面的payload執行,也就會讀取這個檔案自身,從而放大了WebView任意載入漏洞的危害,並能竊取WebView所載入的所有的Cookies。
圖上是攻擊的效果,大家可以看到,Cookies檔案是被汙染了一段js程式碼,接下來是軟連結指向了受害APP的cookies檔案。
下面,我再講遇到的另一個有關loadDataWithBaseURL的使用案例。在這個案例中,該函式涉及到兩個引數,一個是訪問的域名,還有一個是訪問的內容。我們經常能夠看到,如果域名和內容同時可控,那麼攻擊者就可以構造一個任意域下的XSS漏洞。
我要介紹的這個案例就是一個谷歌的流行APP,這個APP有很多的deeplink,可以用來操縱其WebView訪問任意URL。由於WebView沒有做任何設定,也就是預設設定,這就意味著它可以用前面我提到的手法去竊取它的Cookies檔案。同時,它還有一個特殊的deeplink,可以讓APP的WebView去透過谷歌Doc載入URL指定的連結,但這個URL是攻擊者可控的,因此帶來的危害非常嚴重,使用者只要點選一次Deeplink,其access_token就會被髮送到攻擊者的伺服器,從而讓攻擊者竊取使用者的資訊。
該APP還有一些特殊的deeplink,可以載入攻擊者指定的Fragment,但傳入不存在的Fragment Class時,APP就會崩潰,原因是Fragment對應的類被例項化,但卻不存在。
於是我就開始思考,如果傳入APP中本身就存在的一些合理的Fragment Class時,會產生何種安全危害?這裡我對它的上百個Fragment Class進行了嘗試,最終將該漏洞轉化為了WebView的loadDataWIthBaseURL漏洞利用,我這裡可以控制前兩個引數,從而實現了在漏洞APP自己域名下的XSS。
對開發者而言,我的安全建議就是,需要把這些跨域的設定預設設定為false。如果開發者要載入確定的HTML,可以使用它自己的asset目錄,同時也要防範目錄穿越問題,對檔名進行過濾,儘量不使用loadDataWithBaseUrl。
三.WebView URL校驗
接下來我們進入URL校驗部分。這裡涉及到一個基本問題,就是很多APP的開發者會把自己的域名作為白名單域名,然後對這個域名進行檢查,如果檢查透過才會開啟高敏感許可權的JsInterface介面,或者說讓WebView去載入。這就導致有很多誤用URL進行檢查的案例。
下面是一個簡單的案例。比如說對File協議進行檢查,有很多的方式可以去繞過。其中,正確的做法是從URL裡取Scheme,忽略大小寫再進行判斷。
URL校驗失校的案例非常多,常見原因有endWith沒有閉合點號等。在沒有閉合點號的情況下,攻擊者可以在域名前加其他的字母進行繞過。
還有使用startsWith、contains、indexOf、正則匹配等非嚴格字串匹配方式,以及很多其他的繞過方式。
除此之外,還有一種方式是透過WebView loadUrl與Uri.parse理解的不一致。對WebView的URL來說,它是正確理解,會把“\”識別為“/”,正常進行載入,但是在Uri.pase解析的時候沒有對“\”進行處理,沒有按照WhatWG規範把“\”識別為path的開頭,就出現了不一致。這個漏洞對於安卓8.1及之前的版本都有效,所以攻擊者用這種方式可以成功打擊很多低於8.1版本的裝置。
下面是我針對這類漏洞遇到過的一些案例。對於某個影片編輯APP,發生過兩次URL校驗繞過。還有某音樂APP,也是使用了這個漏洞,只不過它是透過deeplink去控制URL引數,並使用“\”的技巧去繞過校驗。另外,還有某聊天APP,它存在邏輯問題,會把自己的協議替換成HTTP,攻擊者就可以在後面加上@符號進行繞過。
此外,還有一種是URL Scheme繞過,它檢查了host但沒有檢查scheme,就可以透過“javascript:”繞過。需要注意的是,在WebView的低版本中,如果跟上白名單host和實際存在的檔案的路徑,WebView仍然可以正常解析。在WebView載入的時候,會忽略host,正常載入後面路徑指向的檔案,所以攻擊者仍然可以用這種方式去繞過。
下面來說說透過hearachical Uri繞過的方式,漏洞特徵是直接從外部去取Uri,未經過Uri.parse,可以透過反射構造herachical Uri繞過。
如果白名單域名內的服務端出現跳轉漏洞的時候,開發者沒有對其進行檢查,攻擊者就仍然可以繞過。這種漏洞自身危害可能不大,但結合著WebView的特權介面的呼叫,就可能會帶來更大的危害。而解決方案就是在App的shouldOverideUrlloading函式中對URL進行檢查。
最後要說的一種是利用競爭條件繞過URL校驗的方式。這種繞過的特徵是開發者僅對JsInterface API這個層級進行一個檢查,同時它維護了一個WebView當前載入的URL。API對其進行URL檢查,如果檢查透過就返回特權介面的內容,如果檢查不透過就拒絕執行。
大家可以看到,這個跳轉函式如果開發者使用了跳轉的域名,也就是用第二個url引數去設定WebView當前要載入的URL的話,就會存在一個條件競爭的漏洞。這個漏洞的形成原因在於攻擊者是可以去控制WebView當前要載入的URL的,因為它是從跳轉的過程中去取的,因此攻擊者也可以控制這個當前載入的url。
這段程式碼的原理在於JS放在攻擊者可控的網頁中,往白名單域名去跳轉,透過跳轉,一些函式會被回撥,這個時候WebView當前要載入的URL就被改寫成了白名單域名。但是這個頁面還有一個時間視窗去銷燬,在還沒有銷燬的間隙,Test函式可以反覆嘗試,是有機會成功執行的,如果成功執行就會去呼叫getToken竊取資訊,這就是對競爭條件漏洞的利用。
同時,WebView也可能會處理intent scheme,如果校驗不嚴,就會存在一些Intent跳轉的漏洞,比如攻擊者可以去構建一個intent去指向受害APP自己的元件,或者受害APP有許可權訪問的元件,就會帶來比較嚴重的launchAnyWhere問題。
說完了形形色色的URL校驗問題,那麼如何做好安全的URL校驗呢?嚴格來說,CheckDomain的使用位置應該在WebView載入和跳轉前,在JavascriptInterface介面中呼叫,這是針對安卓原生註解的JsInterface介面。如果只對介面級進行防禦,可以採用JsBridge的介面,此時可以在JS的回撥函式中去檢查URL的引數,就可以避免我們之前所說的條件競爭的問題。
這裡我對URL的校驗函式和Intent scheme校驗都做了一些拆解。
另外,對於安全研究員和開發者來說,如果要對自己的WebView應用進行審計的話,以下是我列舉的一些安全審計點。
四.WebView安全防禦
前面我們講到了WebView的安全配置的白名單校驗,裡面的坑是非常多的。
那最後我就來講講WebView的安全防禦,主要就是我們的APP開發者要構建一個安全SDK;構建安全基線,包含了我們一些預設的安全的設定以及白名單的校驗,可以透過雲控進行下發。
同時我們這個白名單校驗可以有針對性地校驗,並對許可權進行分級,不同的白名單的頁面應該有不同的能力。
以上就是我對WebView安全的介紹。
五.總結
總結一下,今天我給大家介紹了WebView安全的歷史問題、本地攻擊面和遠端攻擊面、安全配置和使用以及形形色色的URL校驗問題。
對於開發者而言,使用WebView的原則有以下幾點:首先是內容可信,僅允許最小的域名或者有這個功能需求的域名讓WebView載入。同時還要保證特權最小,並不是所有的介面都要開放,而是隻使用所需要的介面。最後一個原則就是可以把一些WebView的預設配置和白名單校驗封裝到標準SDK中進行使用。
最後,感謝OPPO子午網際網路安全實驗室的小夥伴們,我們一起討論和進步,也感謝下面的大佬提供了一些深入淺出的文章,受益匪淺。謝謝大家,我今天的議題分享就到這裡!
本屆峰會議題回顧
2020看雪SDC議題回顧 | 逃逸IE瀏覽器沙箱:在野0Day漏洞利用復現
2020 看雪SDC議題回顧 | LightSpy:Mobile間諜軟體的狩獵和剖析
2020 看雪SDC議題回顧 | DexVmp最新進化:流式編碼
……
更多議題回顧盡情期待!!
注意:關注看雪學院公眾號(ikanxue)回覆“SDC”,即可獲得本次峰會演講ppt!
其他議題演講PPT,經講師同意後會陸續放出,請大家持續關注看雪論壇及看雪學院公眾號!
- End -