A few days ago I was looking at how various apps store data on a users phone. I was thinking about how Apple sandboxes NSUserDefaults and potential ways to modify the information an app has stored without jailbreaking my device. It’s commonly known that if a user has jailbroken their device, they have access to pretty much everything including NSUserDefaults; however, if a device isn’t jailbroken (aka. you have no access to its file system), it should be much harder to access this information.
While playing around with this, I was able to exploit the high score system in a game called 2048. I changed back my high score after I was done and only incrimented my score by 100-200 points so I could legitimately beat it after I was done.
Here’s how I modified the stored score:
So I remembered back to a few months ago when I had 2 apps with the same bundle identifier (accidentally). The apps “merged.” The icon was for 1 app while the actual app itself was the other. The assets were also mixed up. A quick google search showed me that NSUserDefaults is sandboxed using an apps bundle identifier. The first thing I did was download the app I wanted to experiment with (2048) from the iTunes store onto my computer so I could obtain the bundle ID. I then navigated to ~/Music/iTunes/iTunes Media/Mobile Applications/ and duplicated “2048 1.2.ipa.” I then changed the extension to .zip and unzipped it. In this folder I navigated to Payload/ and then right clicked on “2048″ and clicked “Show Package Contents.” I then opened up Info.plist in my text editor (textmate). I scrolled down until I found “CFBundleIdentifier.” For 2048, this happens to be “com.ketchapp.2048″.
The next thing I did was create the fake app. I opened up Xcode and created a new singe view application. I set the bundle identifier of this app to the one I found from the application bundle. I added a UITextView and set the text of it to
I then ran this app on my phone (with 2048 installed) was able to look at the output from that. I noticed a entry called “highscore.” I then added the following code to the app delegate to change that variable (I used a much smaller number)
Now that the variable has been changed, all I had to do was put the old app back on my phone. I did this by going to Xcode Organizer and going to the “Applications” tab under my device. I clicked add and chose the IPA I downloaded earlier (from iTunes). I then waited for it to install and restarted my phone. When I turned it back on, the old app was back and my high score was the one I set with my fake app.
Here’s the thing. The way 2048 was written, it seems it sets its game center scores based on the NSUserDefaults value. This means when I went to game center, I was in a very high rank. While testing this, I didn’t use any absurdly high numbers as to not draw attention to myself. I also used an alternate account.
Honestly, this isn’t a huge exploit. The average user doesn’t have the time or knowledge to do this; however, if you want to secure your app against it, here are a few things you can do:
1) Avoid using NSUserDefaults (not always practical; however, you could use the keychain instead)
2) Encrypt data stored in NSUserDefaults (no one will bother to crack your encryption just to get a higher score)
3) Store data on a server as well and then check if the local version and server version are the same