To preserve game
progress across multiple devicesThe second benefit is especially
attractive to devoted Angry Birds players because it allows them to
stop playing on one device and pick up where they left off on
another. Figure 1 shows the Rovio registration page.
[caption id="attachment_4889"
align="aligncenter" width="546"] href="/content/dam/legacy/blog/2014/03/Fig1.png">
width="546" height="327"
class="size-full wp-image-4889 landscape-med"
alt="Figure 1. The registration page of the Rovio account. "
src="https://www.fireeye.com/content/dam/legacy/blog/2014/03/Fig1.png" />
Figure 1: Rovio’s registration page[/caption]
Figure 2
shows birthday information collected during registration. The
end-use license agreement (EULA) and privacy policy grant Rovio
rights to upload the collected information to third-party entities
for marketing.
[caption id="attachment_4894"
align="aligncenter" width="546"] href="/content/dam/legacy/blog/2014/03/Fig2.png">
width="546" height="327"
class="size-full wp-image-4894 landscape-med"
alt="Figure 2. The registration of the Rovio account includes personal information and EULA. "
src="https://www.fireeye.com/content/dam/legacy/blog/2014/03/Fig2.png" />
Figure 2: The registration of the Rovio account includes personal
information and EULA.[/caption]
In Figure 3, the
registration page asks for the user’s email address and gender.
When the player clicks the register button, Rovio uploads
the collected data to the Angry Birds Cloud to create a player
profile.
[caption id="attachment_4897"
align="aligncenter" width="546"] href="/content/dam/legacy/blog/2014/03/Fig3.png">
width="546" height="327"
class="size-full wp-image-4897 landscape-med"
alt="Figure 3. The personal information during the registration process."
src="https://www.fireeye.com/content/dam/legacy/blog/2014/03/Fig3.png" />
Figure 3: Rovio asks for email and gender information during
registration.[/caption]
Figure 4 shows another way Angry
Birds collects personal information. Rovio offers a newsletter to
update Angry Birds players with new games, episodes, and special
offers. During newsletter signup, Rovio collects the player’s
first and last name, email address, date of birth, country of
residence, and gender. This information is aggregated with the
user’s Rovio account profile by matching the player’s email
address.
[caption id="attachment_4899"
align="aligncenter" width="546"] href="/content/dam/legacy/blog/2014/03/Fig4.png">
width="546" height="396"
class="size-full wp-image-4899 landscape-med"
alt="Figure 4. Newsletter registration page with more personal information."
src="https://www.fireeye.com/content/dam/legacy/blog/2014/03/Fig4.png" />
Figure 4: Newsletter registration page requesting more personal
information[/caption]
[caption id="attachment_5017"
align="alignnone" width="549"] href="/content/dam/legacy/blog/2014/03/AngryBirds_illustration_v8.png">
width="549" height="729"
class="size-full wp-image-5017 portrait-med"
alt="Figure 5. Information flow among Angry Birds, the ad intermediate platform and the ad cloud."
src="https://www.fireeye.com/content/dam/legacy/blog/2014/03/AngryBirds_illustration_v8.png" />
Figure 5: Information flow among Angry Birds, the ad intermediate
platform and the ad cloud[/caption]
First, we are concerned
with the type of information transmitted to the advertisement
library. Figure 5 illustrates the information flow among Angry
Birds, the Angry Birds Cloud, Burstly (the embedded ad library and
ad mediation platform), and cloud-based ad services such as
Jumptap and Millennial Media.
Angry Birds uses Burstly as
an ad adapter, which provides integration with numerous
third-party ad clouds including Jumptap and Millennial Media. The
ad services use players’ personal data to target ads.
As
the figure shows, Angry Birds maintains an HTTP connection with
the advertising platform Burstly, the advertisement provider
Millennial Media, and more.
Traffic flow
Table 1 summarizes the connections,
which we explain in detail below.
class="c09 has-data-label has-auto-width">
PCap | | scope="col">Burstly (Ad Mediation Platform) | class="c09_td" scope="col">Third Party Ad Clouds
|---|
1 class="c09_td_value is-hidden-mml">1 | | class="c09_td"> POST
(personal information, IP) class="c09_td_value is-hidden-mml">POST (personal
information, IP) class="c09_td_value is-hidden-mml"> |
2 class="c09_td_value is-hidden-mml">2 | | class="c09_td">
class="c09_td_value is-hidden-mml"> | class="c09_td"> GET Ad
from Jumptap class="c09_td_value is-hidden-mml">GET Ad from
Jumptap
3 class="c09_td_value is-hidden-mml">3 | | class="c09_td">
class="c09_td_value is-hidden-mml"> | class="c09_td"> GET Ad
from Turn.com class="c09_td_value is-hidden-mml">GET Ad from
Turn.com
Table 1: PCap
information exchanged between Angry Birds, Burstly and third-party
ad clouds
Angry Birds uses native code called
libAngryBird.so to access storage and help the ad libraries store
logs, caches, database, configuration files, and AES-encrypted
game data. For users with a Rovio account, this data includes the
user's personal information in clear text or easily decrypted
formats. For example, some information is stored in clear text in
the web view cache called webviewCacheChromium:
style="font-family: "Courier New";">{"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":"eXXX...XXXe@XXX.XXX",
"isConfirmed":false}, "phoneNumber":null,
"facebook":{"facebookId":"","email":""},"socialNetworks":[]}
The device is given a universal id 1XXXX8, which is stored in
the webviewCookiesChromium database in clear text:
cu1XXXX8|{"name":"cu1XXXX8","value":"3%2XXX...XXX6+PM"}|13XXX...XXX1
The id "1XXXX8" labels the personal information when
uploaded by the ad mediation platform. Then the information is
passed to ad clouds.
1. The initial traffic captures in the
PCap shows what kind of information Angry Birds uploads to
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
style="font-family: "Courier New";">X-AspNet-Version:
4.0.30319
X-Powered-By:
ASP.NET
X-ReqTime:
0
style="font-family: "Courier New";">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
style="font-family: "Courier New";">Content-Length:
1690
Host:
neptune.appads.com
Connection:
Keep-Alive
style="font-family: "Courier New";">{"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",...
We can see the information transmitted to neptune.appads.com
includes gender, age, android id, device id, mac address, device
type, etc. In another PCap in which Angry Birds sends POST to the
same host name, the IP address is transmitted too:
HTTP/1.1 200
OK
…
POST
/Services/v1/SdkConfiguration/Get HTTP/1.1
…
Host:
neptune.appads.com
...
IpAddress":"fXXX...XXX9%eth0",...
According to href="http://whois.domaintools.com/appads.com">whois
records, the registrant organization of neptune.appads.com is
Burstly, Inc. Therefore, the aforementioned information is
actually transmitted to Burstly. It Both PCaps contain the keyword
“crParms.” This keyword is also used in the source code to put
personal information into a map sent as a payload.
Skyrocket.com is an href="http://www.insidemobileapps.com/2013/05/21/burstly-restructures-company-and-opens-skyrocket-to-all-mobile-developers/">app
monetization service provided by Burstly. The following PCap
shows that Angry Birds retrieves the customer ID from
Skyrocket.com through an HTTP GET request:
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
style="font-family: "Courier New";">X-AspNet-Version:
4.0.30319
X-Powered-By:
ASP.NET
X-ReqTime:
2
X-Stats:
geo-0
style="font-family: "Courier New";">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
style="font-family: "Courier New";">{"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. In this PCap, the ad
is fetched by including the customer id 1XXX8 into the HTTP POST
request to jumptap.com, i.e. Millennial Media:
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
style="font-family: "Courier New";">X-AspNet-Version:
4.0.30319
X-Powered-By:
ASP.NET
X-ReqTime:
475
X-Stats:
geo-0;rcf88626-255;rcf75152-218
style="font-family: "Courier New";">Content-Length:
2537
Connection:
keep-alive
GET
/img/1547/1XXX2.jpg HTTP/1.1
Host:
i.jumptap.com
Connection:
keep-alive
Referer:
http://bar/
style="font-family: "Courier New";">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
style="font-family: "Courier New";">Accept-Encoding:
gzip,deflate
style="font-family: "Courier New";">Accept-Language:
en-US
style="font-family: "Courier New";">Accept-Charset:
utf-8, iso-8859-1, utf-16, *;q=0.7
style="font-family: "Courier New";">{"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"}]}
In this pcap, the advertisement is retrieved from jumptap.com.
We can use the same customer id “1XXXX8” to easily track the PCap
of different ad libraries.
3. For example, in another PCap
from turn.com, customer id remains the same:
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
style="font-family: "Courier New";">X-AspNet-Version:
4.0.30319
X-Powered-By:
ASP.NET
X-ReqTime:
273
X-Stats:
geo-0;rcf88626-272
style="font-family: "Courier New";">Content-Length:
4714
Connection:
keep-alive
GET
/server/ads.js?pub=24…
style="font-family: "Courier New";">PvctPFq&acp=0.51
HTTP/1.1
Host:
ad.turn.com
Connection:
keep-alive
Referer:
http://bar/
Accept:
*/*
style="font-family: "Courier New";">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
style="font-family: "Courier New";">Accept-Encoding:
gzip,deflate
style="font-family: "Courier New";">Accept-Language:
en-US
style="font-family: "Courier New";">Accept-Charset:
utf-8, iso-8859-1, utf-16, *;q=0.7
style="font-family: "Courier New";">{"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
How is the personal information shared?
We also
researched the source code of the Burstly (ad mediation platform)
to trace the method calls for the information sharing. First in
com/burstly/lib/conveniencelayer/BurstlyAnimated Banner.java, when
Angry Birds tries to initialize the connection with Burstly,
initNewAnimatedBanner() is called as follows:
style="font-family: "Courier New";">this.initNewAnimatedBanner
(arg7.getActivity(), arg8, arg9, arg10, arg11);
Inside
initNewAnimatedBanner(), it instantiates the BurstlyView object
by calling:
BurstlyView v0
= new BurstlyView(((Context)arg3));
style="font-family: "Courier New";">v0.setZoneId(arg6);
Before the ZoneId is set, the initializeView() method is
called in the constructor of BurstlyView. Furthermore, inside the
initializeView() method, we found the following:
new
BurstlyViewConfigurator(this).configure(this.mAttributes);
Finally in the BurstlyViewConfigurator.configure()
method, it sets a series of parameters:
style="font-family: "Courier New";">this.extractAndApplyBurstlyViewId();
style="font-family: "Courier New";">this.extractAndApplyCrParams();
style="font-family: "Courier New";">this.extractAndApplyDefaultSessionLife();
style="font-family: "Courier New";">this.extractAndApplyPublisherId();
style="font-family: "Courier New";">this.extractAndApplyPubTargetingParams();
style="font-family: "Courier New";">this.extractAndApplyUseCachedResponse();
style="font-family: "Courier New";">this.extractAndApplyZoneId();
These method calls are to retrieve information from
burstly.com. For example, in the extractAndApplyCrParams() method,
it retrieves parameters from burstly.com and stores them in the
BurstlyView object:
String v0 =
this.mAttributes.getAttributeValue("http://burstly.com/lib/ui/schema",
"crParams");
if(v0 != null)
{
style="font-family: "Courier New";">BurstlyViewConfigurator.LOG.logDebug("BurstlyViewConfigurator",
"Setting CR params to: {0}", new
Object[]{v0});
style="font-family: "Courier New";">this.mBurstlyView.setCrParms(v0);
}
The key crParms is the same one used in the first PCap
to label the values corresponding to personal information such as
age and gender.
Conclusion
In summary, Angry Birds collects user’s
personal information and associates with customer id before
storing it in the smart phone storage. Then the Burstly ad library
embedded in Angry Birds fetches the customer id, uploads the
corresponding personal information to the Burstly cloud, and
transmits it to other advertising clouds. We have caught such
traffics in the network packet captures and the corresponding code
paths in the reversed engineered source code.
For FireEye
ThreatScore information on Angry Birds and more details about the
application’s behavior, FireEye Mobile Threat Prevention customers
can access their Mobile Threat Prevention (MTP) portal.