很多流行的app,包括憤怒的小鳥在內,收集并且分享玩家的個人信息的廣泛程度,遠遠超過大多數人所了解的。
一些媒體只是進行了表面的報道,沒有深入追蹤。在去年十月,紐約時報發表了一些關于憤怒的小鳥和其他一些app收集數據的相關報道。在今年2月,多家報社聯合公共利益網站ProPublica和英國報社進行一些列報道,詳細說明政府機構使用游戲(和一些app)收集用戶數據。甚至是歷史悠久的CBS在早些時候用了60分鐘來對Rovio分享用戶位置信息的事情進行了報道。
google應用商店中Android版的憤怒的小鳥是在3月4號更新的,這個版本依舊在分享個人信息。事實上,超過2.5億的用戶為了方便在不同設備上訪問,創建了Rovio賬戶,他們的年齡、性別等等很多信息,會在不知不覺中被分享。并且很多在玩游戲時沒有使用Rovio賬戶的用戶,他們的設備信息也會被共享了。
一旦Rovio賬戶創建,用戶信息就會被收集,但是用戶很難阻止這些app收集信息。他們把收集到的用戶信息可能會放到多個地方:憤怒小鳥的云端,Burstly(廣告中介平臺)和一些第三方的廣告網絡,就像Jumptap和Millennial Media這類。雖然用戶可以通過在玩憤怒小鳥時不使用Rovio賬戶來避免信息被收集,但是不能阻止游戲共享這些設備信息。
在這篇blog中,我們將分析“憤怒的小鳥”收集信息的過程。我們還會演示應用程序、廣告中介平臺和廣告云之間的關系,展示三者之間如果共享收集到用戶的數據。當然我們會拿出證據來支持我們的觀點,比如FireEye Mobile Thread Prevention(MTP)捕獲的數據包(PCap),來支持我們的分析結果。最后我們會通過逆向,在代碼層面進行分析。
為了調查信息共享的機制和內容,我們對多個版本進行了研究,發現很多版本都是明文傳遞收集到的電子郵件,地址,年齡和性別這些信息。
我們發現憤怒的小鳥多個版本存在收集信息的問題,包含最新版本4.1.0(3月4號在google應用商店中更新的版本),到目前為止,超過2億用戶進行了下載,很多用戶會被收集信息。
Angry Birds鼓勵用戶創建Rovio賬戶,這樣會給用戶帶來以下好處:
1、保存分數和游戲中的武器。
2、在不同的設備中保持相同的進度。第二個好處對玩家特別有吸引力,因為它允許在一個設備上停止游戲,一個設備就可以接著上個設備上的進度接著游戲。
圖一顯示Rovio的注冊頁面
圖一:Rovio的注冊頁面
圖二顯示了在注冊過程中收集生日信息,遵循最終使用許可協議(EULA)和授權Rovio可以上傳用戶信息,同時把信息上傳到第三方機構進行營銷。
圖二:Rovio注冊過程中收集信息和遵守EULA
圖三,注冊頁面提示用戶輸入郵件地址和性別。當用戶點擊注冊按鈕。Rovio上傳收集到的數據到云端,同時創建用戶
圖三:Rovio在注冊過程中輸入郵箱地址和性別
圖四顯示憤怒的小鳥通過其他方式收藏用戶信息。Rovio推送給注冊用戶更新游戲的提示,信息片段和特殊優惠。在時事通訊注冊過程中,Rovio收集用戶的名字、郵箱、生日、居住國和性別。這些信息會和用戶的Rovio賬戶信息的郵箱進行比對
圖四:時事通訊注冊頁面要求更多的用戶信息
圖五:憤怒的小鳥、廣告平臺和廣告云之間的信息流。
首先,我們關注的是那些信息被傳送到廣告庫中。圖5顯示了“憤怒小鳥”的信息流:“憤怒小鳥”的云端,Burstly(內嵌廣告庫和廣告中介平臺),以及Jumptap和Millennial Media等這些基于云的廣告服務。
“憤怒的小鳥”通過Burstly對廣告進行植入,它提供了大量的第三方廣告云包括Jumptap和Millennial Media,通過識別用戶信息來實現精確廣告推送。
如圖所示。憤怒的小鳥保持與廣告平臺Burstly和廣告提供商Millennial Media之類相關平臺的HTTP連接。
數據流: 表一是一個總結,下面會有詳細講解
表1:“憤怒的小鳥”,Burstly和第三方廣告云之間的信息傳遞
“憤怒的小鳥”在本地調用叫做libAngryBird.so的代碼來訪問存儲,同時幫助廣告庫存儲日志,緩存,數據庫,配置文件和AES加密游戲數據。對于用戶使用的Rovio賬戶,這些包含用戶信息的數據是明文或者只是進行了簡單的加密。
例如:一些信息被明文存儲在緩存中,被稱為webviewCacheChromium。
{“accountId”:”AC3XXX…XXXA62B”,”accountExtRef”:”hE…fDc”,”personal”:{“firstName”:null,”lastName”:null,“birthday”:”19XXXXX-01″, “age”:”30″, “gender”:”FEMALE”, “country”:”United States” , “countryCode”:”US”, “marketingConsent”:false, “avatarId”:”AVXXX…XXX2c”,”imageAssets”:[...], “nickName”:null}, “abid”:{“email”:[email protected], “isConfirmed”:false}, “phoneNumber”:null, “facebook”:{“facebookId”:”",”email”:”"},”socialNetworks”:[]}
這個設備被賦予一個通用id 1XXXXX8,這是明文存儲在webviewCookieChromiun
cu1XXXX8|{“name”:”cu1XXXX8“,”value”:”3%2XXX…XXX6+PM”}|13XXX…XXX1
當上傳用戶信息到廣告中介平臺時,這個id "1XXXX8"是用戶信息的標簽。然后將信息傳遞給廣告云
1、捕獲的初始數據包流量顯示什么信息會被"憤怒的小鳥"上傳到Burstly
HTTP/1.1 200 OK
Cache-Control: private
Date: Thu, 06 Mar 2014 XX:XX:XX GMT
Server: Microsoft-IIS/7.5
ServerName: P-ADS-OR-WEBC #22
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
X-ReqTime: 0
Content-Length: 0
Connection: keep-alive
POST /Services/PubAd.svc/GetSingleAdPlacement HTTP/1.1
Content-type: text/json; charset=utf-8
User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; Ascend Y300 Build/KOT49H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Content-Length: 1690
Host: neptune.appads.com
Connection: Keep-Alive
{“data”:{“Id”:”8XXX5″,”acceptLanguage”:”en”,”adPool”:0,”androidId”:”u1XXX…XXXug”,”bundleId”: “com.rovio.angrybirds”,…,”cookie”:[{"name":"cu1XXX8","value":"3XXX6+PM"},{"name":"vw","value":"ref=1XXX2&dgi=,eL,default,GFW"},{"name":"lc","value":"1XXX8"},{"name":"iuXXXg","value":"x"},{"name":"cuXXX8","value":"3%2XXXPM"},{"name":"fXXXg","value":"ref=1XXX712&crXXX8=2,1&crXXX8=,1"}], “crParms”:”age=30,androidstore=’com.android.vending’, customer=’googleplay’, gender=’FEMALE’, version=’4.1.0′”, “debugFlags”:0, “deviceId”:”aXXX…XXXd”, “encDevId”:”xXXX….XXXs=”, “encMAC”:”iXXX…XXXg=”, “ipAddress”:”",“mac”:”1XXX…XXX9″, “noTrack”:0,”placement”:”", “pubTargeting”:”age=30, androidstore=’com.android.vending’, customer=’googleplay’, gender=’FEMALE’, version=’4.1.0′”,”rvCR”:”", “type”:”iq”,”userAgentInfo”:{“Build”:”1.35.0.50370″, “BuildID”:”323″, “Carrier”:”",”Density”:”High”, “Device”:“AscendY300″, “DeviceFamily”:“Huawei”, “MCC”:”0″,”MNC”:”0″,…
我們可以看到上傳到neptune.appads.com的信息包括,性別、年齡、安卓id、設備id、mac地址、設備類型等等
在其他數據包中看到、"憤怒的小鳥"通過POST把IP地址發送到同一個主機
HTTP/1.1 200 OK
…
POST /Services/v1/SdkConfiguration/Get HTTP/1.1
…
Host: neptune.appads.com
…
IpAddress”:”fXXX…XXX9%eth0″,…
根據Whois記錄,注冊neptune.appads.com的組織就是Burstly,上述信息被發送到Burstly。在數據包中都包含 “crParms.” 這個關鍵字,當源碼發送個人信息時,這個關鍵字是作為有效載荷的。
Skyrocket.com是Burstly提供的一個應用貨幣虛擬化的服務。跟蹤數據包,發現"憤怒的小鳥",通過HTTP GET請求,從Skyrocket.com查詢用戶ID
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html
Date: Thu, 06 Mar 2014 07:12:25 GMT
Server: Microsoft-IIS/7.5
ServerName: P-ADS-OR-WEBA #5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
X-ReqTime: 2
X-Stats: geo-0
Content-Length: 9606
Connection: keep-alive
GET /7….4/ad/image/1…c.jpg HTTP/1.1
User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; Ascend Y300 Build/KOT49H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Host: cdn.skyrocketapp.com
Connection: Keep-Alive
{“type”:”ip”,”Id”:”9XXX8″,…”data”:[{"imageUrl":"http://cdn.skyrocketapp.com/79...2c.jpg","adType":{"width":300, "height":250, "extendedProperty":80}, "dataType": 64, "textAdType":0,"destType":1,"destParms":"","cookie":[{"name":"fXXXg", "value": "ref=1XXX2&cr1XXX8=2,1&cr1XXX8=1&aoXXX8=", "path":"/", "domain": "neptune.appads.com", "expires":"Sat, 05 Apr 2014 XXX GMT", "maxage": 2…0}, {"name":"vw","value":"ref=1XXX2&...},...,"cbi":"http://bs.serving-sys.com/Burstin...25&rtu=-1","cbia":["http://bs….":1,"expires":60},..."color":{"bg":"0…0"}, "isInterstitial":1}
2、在這個數據包中。通過HTTP POST從jumptap.com(即Millennial Media)獲得包含用戶id的廣告信息
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html
Date: Thu, XX Mar 2014 XX:XX:XX GMT
Server: Microsoft-IIS/7.5
ServerName: P-ADS-OR-WEBC #17
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
X-ReqTime: 475
X-Stats: geo-0;rcf88626-255;rcf75152-218
Content-Length: 2537
Connection: keep-alive
GET /img/1547/1XXX2.jpg HTTP/1.1
Host: i.jumptap.com
Connection: keep-alive
Referer: http://bar/
X-Requested-With: com.rovio.angrybirds
User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; Ascend Y300 Build/KOT49H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Accept-Encoding: gzip,deflate
Accept-Language: en-US
Accept-Charset: utf-8, iso-8859-1, utf-16, *;q=0.7
{"type":"ip","Id":"8XXX5","width":320,"height":50,"cookie":[],”data”:[{"data":"<!-- AdPlacement : banner_ingame_burstly…","adType":{"width":320, "height":50, "extendedProperty":2064 },"dataType":1, "textAdType":0, "destType":10, "destParms":"", "cookie":[{"name":"...", "value":"ref=...&cr1XXX8=4,1&cr1XXX8=2,1", "path":"/", "domain":"neptune.appads.com", "expires":"Sat, 0X Apr 2014 0X:XX:XX GMT", "maxage":2XXX0}, {"name":"vw",..., "crid":7XXX2, "aoid":3XXX3, "iTrkData":"...", "clkData":"...","feedName":"Nexage"}]}
這個數據包中,廣告是從jumptap.com得到,我們也能使用相同的用戶id"1XXXX8"去跟蹤不同的廣告庫
3、例如,在其他來自turn.com的數據包,用戶id和剛才的相同
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html
Date: Thu, 06 Mar 2014 07:30:54 GMT
Server: Microsoft-IIS/7.5
ServerName: P-ADS-OR-WEBB #6
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
X-ReqTime: 273
X-Stats: geo-0;rcf88626-272
Content-Length: 4714
Connection: keep-alive
GET /server/ads.js?pub=24…
PvctPFq&acp=0.51 HTTP/1.1
Host: ad.turn.com
Connection: keep-alive
Referer: http://bar/
Accept: */*
X-Requested-With: com.rovio.angrybirds
User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; Ascend Y300 Build/KOT49H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Accept-Encoding: gzip,deflate
Accept-Language: en-US
Accept-Charset: utf-8, iso-8859-1, utf-16, *;q=0.7
{“type”:”ip”,”Id”:”0…b”,”width”:320,”height”:50,”cookie”:[],”data”:[{"data":"<!-- AdPlacement : banner_ingame_burstly --> "http://burstly.ads.nexage.com:80..." destParms":"", "cookie":[{"name":"f...g", "value":"ref=1...0&cr1XXXX8=k,1&cr...8=i, 1","path":"/", "domain":"neptune.appads.com", "expires":"Sat, 0X Apr 2014 0X:XX:XX
我們研究了Burstly(廣告中介平臺)的源代碼,來跟蹤叫做信息貢獻的方法。
首先在 com/burstly/lib/conveniencelayer/BurstlyAnimated Banner.java
當"憤怒的小鳥"和Burstly初始話連接時,initNewAnimatedBanner() 會被調用
this.initNewAnimatedBanner (arg7.getActivity(), arg8, arg9, arg10, arg11);
Inside initNewAnimatedBanner(), it instantiates the BurstlyView object by calling:
BurstlyView v0 = new BurstlyView(((Context)arg3));
v0.setZoneId(arg6);
在Zoneld設置之前, initializeView()被BurstlyView這個構造函數調用,此外在 initializeView() 中,我們發現以下幾點:
new BurstlyViewConfigurator(this).configure(this.mAttributes);
最后在 BurstlyViewConfigurator.configure()中,設置了一些參數
this.extractAndApplyBurstlyViewId();
this.extractAndApplyCrParams();
this.extractAndApplyDefaultSessionLife();
this.extractAndApplyPublisherId();
this.extractAndApplyPubTargetingParams();
this.extractAndApplyUseCachedResponse();
this.extractAndApplyZoneId();
下面這個方法被用作從burstly.com還原信息。例如,在extractAndApplyCrParams()
中,從burstly.com得到一些參數同時把它們存儲到BurstlyView對象
String v0 = this.mAttributes.getAttributeValue("http://burstly.com/lib/ui/schema", "crParams");
if(v0 != null) {
BurstlyViewConfigurator.LOG.logDebug("BurstlyViewConfigurator", "Setting CR params to: {0}", new Object[]{v0});
this.mBurstlyView.setCrParms(v0);
}
關鍵字crParms和第一個數據包中的標簽一樣,都是被用來標識像年齡和性別這類的用戶信息
綜上所述、"憤怒的小鳥"會收集用戶個人信息和自定義的ID,在存儲到本地之前進行上傳。然后Burstly的廣告庫導入到“憤怒的小鳥”的自定義ID,上傳相應的個人信息給Burstly云和其他廣告云系統。
我們在網絡中捕獲到響應的數據包、同時逆向分析了代碼。