The launch of Fortnite Mobile on Android hasn’t been too great, especially since many of the supported devices really struggle to play the game with acceptable frame rates. The game launched as a Samsung Galaxy exclusive for only 3 days. The Fortnite Installer was first available on Samsung Galaxy Apps before Epic Games allowed non-Samsung players to download and install the full game from the Fortnite Installer obtained on Epic’s website. Shortly after the Fortnite Installer became available, Epic Games quietly pushed an update to the Installer. Now we know why: They patched a Man-in-the-Disk exploit that made it possible for a malicious app to silently install any app they wanted on Samsung Galaxy smartphones. Because there has been some confusion about how this flaw works, we’ll try to clear things up. First, we need to explain the basics of app installation on Android.
App Installation Flow on Android Smartphones
Silent installations from first-party sources
To silently install an APK on Android without prompting the user for permission, you need to have a system-level application with the INSTALL_PACKAGES permission granted. Examples of applications with this permission include the Google Play Store on most Android devices. First-party application stores on devices from Samsung, Huawei, and other device makers may also have the INSTALL_PACKAGES permission granted. If you want to install any app from the Google Play Store, it’ll handle the download and automatically install the app for you without further intervention after you press “Install.” (The Google Play Store even automatically grants certain runtime permissions such as the one for overlays, whereas apps installed from outside of the Play Store need to ask the user to grant these permissions.)
If you’re curious whether an app on your device has the INSTALL_PACKAGES permission, you can find out via an ADB command.
adb shell dumpsys package package.name.here | grep "INSTALL_PACKAGES"
For instance, the Google Play Store’s package name is “
com.android.vending“. Another app with this permission is Shell with the package name
com.android.shell. For those of you who use rootless Substratum via the Andromeda plug-in on Android Oreo, the Andromeda script run from your PC keeps the shell process running so Substratum can use it to install packages (the theme overlays) and then use the OverlayManager commands to enable the overlays.
Side-loading apps from third-party sources
If you attempt to download and install an app from outside of a first-party app store, you’ll first need to enable unknown installation sources. This lets the Package Manager Service within the Android framework (which has the INSTALL_PACKAGES permission) know that you acknowledge the risks of side-loading apps from third-party sources. On pre-Android Oreo devices, there’s a single toggle in Security settings to allow installation from unknown sources. On Android Oreo and later versions, an app calling for the installation of an APK must declare the REQUEST_INSTALL_PACKAGES permission and the user must whitelist that app so it can request app installs via the Package Manager Service. Since REQUEST_INSTALL_PACKAGES is an “appop” permission, that makes it one of the permissions that can be controlled from within Settings’ permission manager or via the
cmd appops shell command.
Once installation from unknown sources is enabled either globally or specifically for a requesting application, then the user can side-load an app. However, the Package Manager doesn’t allow the app to be installed silently. Rather, it’ll prompt the user whether they want to install the app and list any sensitive permissions that it requests to be granted on install. If the user accepts, then the app is installed with the requested non-runtime permissions. OEMs can also customize the Package Manager: For instance, the Package Manager in the Chinese version of Huawei’s EMUI 5 has a feature to scan the APK to decide if it’s safe and control what permissions are granted before installation. I have observed this on the Honor Note 8 running EMUI 5 imported from China, though I’m sure other Chinese Huawei and Honor devices also have this feature in their Package Managers.
In any case, that about sums up the difference between installing an app from an approved, first-party source and third-party source. If you attempt to install an app from the Play Store or equivalent app store with the INSTALL_PACKAGES permission, it’ll silently handle the install all on its own without further user intervention after you start the download. But if you download an APK from XDA Labs, APKMirror, or other third-party sources, the standard package installer will handle the install and prompt the user to install that package. So where does the Fortnite Installer come in and why is this all relevant?
A Flaw in Fortnite’s Installation Process
Earlier today, Google disclosed a vulnerability they discovered with the first version of the Fortnite Installer. The vulnerability was demonstrated on the Exynos Samsung Galaxy S8+ (dream2lte) but also affected all other Samsung Experience devices including the Samsung Galaxy Note 9 and Samsung Galaxy Tab S4. The vulnerability allows an already-installed malicious application to take advantage of the way the Fortnite Installer tries to install Fortnite for the first time on Samsung Galaxy devices. By using a private API in Samsung Galaxy Apps, the Fortnite Installer bypasses the need to prompt the user via the standard package installer to install Fortnite. That’s because Galaxy Apps has the permission it needs to handle the installation silently. There wouldn’t be anything wrong with this silent installation process if the app that’s being silently installed is the real Fortnite. But because of where the Fortnite Installer stored the downloaded APK file for the Fortnite game, it was easily exploitable.
According to the report on the Issue Tracker, the Fortnite Installer would download the Fortnite Mobile APK to
/sdcard/Android/data/com.epicgames.portal/files/downloads/. This is considered “external storage” on Android as /sdcard is a symbolic link to /data/media/CURRENT_USER, and /sdcard was the name used in the early days of Android when app data was stored on physical SD cards. Nowadays, app data is usually stored in app-specific directories in /data/data/, and each app only has access to the files in its own /data/data directory. Thus, if the Fortnite Installer stored the downloaded Fortnite APK to its own /data/data/ directory, it would be impossible for any app without read permissions (ie. without root access) to know what’s happening in this directory.
However, since the Fortnite Installer saved the downloaded APK in external storage, it could be monitored and overwritten by any app with external storage read permissions. Normally, apps write to /data/media, the “virtual SD card,” when they store files that need to be accessed by the user via MTP or by other apps. For an app to read or write to /data/media, they need to have the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions respectively (both are under the same permission group and are hence granted together). Before Android 4.4 KitKat, most apps requested these permissions upon installation because otherwise, they wouldn’t be able to read or write to the files in their package’s designated external storage directory in /data/media/…/Android/. With the introduction of FUSE to emulate FAT-on-sdcard style directory permissions in Android 4.4 KitKat, apps no longer need any permissions to access files in their designated directory in external storage. Accessing files in any other directory would still need the external storage permissions, which is what a malicious app can do to hijack the Fortnite installation process.
As shown in the video below, a malicious app with the READ_EXTERNAL_STORAGE permission monitors the Fortnite Installer’s download directory in external storage. When it detects that the download is complete and the fingerprint is verified, it replaces the downloaded Fortnite package with its own malicious package thanks to the WRITE_EXTERNAL_STORAGE permission. However, because of the way that Samsung Galaxy Apps verifies the Fortnite APK before installation (…it just checks if the package name is “com.epicgames.fortnite”), it is possible to have Galaxy Apps silently install the malicious package in the background with no user intervention or notification—so long as the malicious package’s name was “com.epicgames.fortnite.” Even worse, if this malicious package targeted SDK level 22 or lower (Android 5.1 Lollipop and earlier), it would automatically be granted all permissions defined in its manifest because runtime permissions are only mandatory for apps targeting SDK level 23 and above (Android 6.0 Marshmallow and later).
But what would happen on non-Samsung devices? Well, because Samsung Galaxy Apps isn’t installed on non-Samsung devices, the malicious APK won’t be silently installed in the background. Fortnite Installer is a third-party app and hence needs to first prompt the user to enable installation from unknown sources and then send a request to the package installer to install the fake Fortnite APK. It would then depend on the user to tap “Install” when asked if they want to install the app or not. This is problematic regardless of the fact that non-Samsung phones aren’t in danger of a malicious app being silently installed in the background. The average user would be none the wiser if a malicious APK crafted with “Fortnite” in its name and the Fortnite app icon is presented to them for installation.
Still, there’s a clear distinction between exploiting this flaw on Samsung Galaxy smartphones and non-Samsung smartphones. The former is a Man-in-the-Disk attack that also takes advantage of a hidden system API to silently install any app in the background, with any permissions, and with no need to trick the user into thinking they’re installing a fake Fortnite APK. The latter is a standard Man-in-the-Disk attack that can also happen to other apps that save APKs or other important data in external storage directories, as shown by the recent CheckPoint post. It just so happens that, thanks to the hidden Galaxy Apps API, this Man-in-the-Disk attack is more dangerous on Samsung Galaxy devices.
Fixing the Flaw
To Epic Games’ credit, they responded very quickly to the report on the Google Issue Tracker and rolled out an update to version 2.1.0 as fast as they could. The fix was simple—just save the downloaded Fortnite APK to the Fortnite Installer’s internal storage directory in /data/data rather than its external storage directory in /data/media. The Epic Games’ engineer requested that the flaw be disclosed after 90 days, though Google declined and made the issue public 7 days after a fix was rolled out. Epic Games’ CEO Tim Sweeney was not happy with the quick turnaround time from the initial security report to its disclosure. He offered the following statement to Android Central.
Epic genuinely appreciated Google’s effort to perform an in-depth security audit of Fortnite immediately following our release on Android, and share the results with Epic so we could speedily issue an update to fix the flaw they discovered.
However, it was irresponsible of Google to publicly disclose the technical details of the flaw so quickly, while many installations had not yet been updated and were still vulnerable.
An Epic security engineer, at my urging, requested Google delay public disclosure for the typical 90 days to allow time for the update to be more widely installed. Google refused. You can read it all at https://issuetracker.google.com/issues/112630336
Google’s security analysis efforts are appreciated and benefit the Android platform, however a company as powerful as Google should practice more responsible disclosure timing than this, and not endanger users in the course of its counter-PR efforts against Epic’s distribution of Fortnite outside of Google Play.
I can’t speak for how many existing Samsung Galaxy devices still have the older Fortnite Installer. Maybe Epic Games should tell these users to update their install by sending a message in Fortnite Mobile. Firebase’s nifty new In-App Messaging feature could do the trick. Although, it’s probably not a big deal anyway because, if a user with the older installer already downloaded the legitimate Fortnite, then any MITD attack won’t work because the malicious APK can’t be installed on top of the existing Fortnite installation. In any case, the discovery of this flaw so early after Fortnite’s release on Android—when there’s still so much controversy about their decision to ditch Google Play—certainly helps the argument that decision was careless. Whether that was Google’s intention behind publicizing this issue so quickly, we’ll never know.