Enumerating Android installed applications without special permissions

Sometimes I took some random Android app I’ve recently installed on my phone and start performing some tests on it. It’s not uncommon to see unauthenticated API requests, plaintext HTTP communication and some obfuscation logic or hardcoded credentials rammed down at client code. As I use to say in my SCADA talks,

“everything that is ‘new’ is prone to ‘newbie’ mistakes”

This is not different for mobile development. The urge for delivery and the hype of start-ups and its fast-paced deployment philosophy usually results on developments with little to no attention to security.

Well, today I was reversing one of those applications. I won’t disclose the name of it for obvious reasons so don’t ask. I started simply by jacking up ProxyDroid to Burp and started to use the app normally.

Then I saw something on Burp that made me REALLY concerned.

POST /api/userCompetitors?uuid=MY_ANDROID_ID&competitors=COMPETITOR_APP_I_HAD_INSTALLED

That prick was spying on me! So I got a little mad and decided to rip the apk open and take a look at the code to see how that was being done.

As I rolled my eyes through the code seeking the “competitor mining” code, I was getting some usual juice like finding that all of the requests were unauthenticated that could lead to almost complete data extraction from partners, customers and transactions, scary!

And then I found it! Consider the following snippet from the app:

private static final Map<String, String> competitors = new HashMap();

    competitors.put("br.com.REMOVED", "REMOVED");
    competitors.put("gr.REMOVED.REMOVED", "REMOVED");
    competitors.put("br.REMOVED.com", "REMOVED");
    // ... edited ...
  public static List<String> getCompetitors()
    ArrayList localArrayList = new ArrayList();
      // Get Installed Packages?? I don't remember anything about this on the "Permissions" tab
      Iterator localIterator = getInstalledPackages().iterator(); 
      while (localIterator.hasNext())
        String str1 = (String)localIterator.next();
        String str2 = (String)competitors.get(str1);
        if (str2 != null)
          Log.d(TAG, "Found competitor: " + str2);
    catch (Exception localException)
      Log.e(TAG, "Could not get competitors", localException);
    return localArrayList;

So it seems that any app can call getInstalledPackages from the PackageManager class on Android SDK and enumerate all you installed apps? Yes, this is true.

And there’s more! According to the documentation:

A List of PackageInfo objects, one for each package that is installed on the device. In the unlikely case of there being no installed packages, an empty list is returned. If flag GET_UNINSTALLED_PACKAGES is set, a list of all applications including those deleted with DONT_DELETE_DATA (partially installed apps with data directory) will be returned.

So any app can also return apps you uninstalled!

But Jan, how bad is this?

Well, basically I don’t like anything tracking me and that’s why I make extensive use of privacy tools when I’m online, so I don’t like either any app phoning-home with the list of apps I have.

In the case above, this company was using this in order to collect market data from competitors and payments gateway. As many may think this is “part of the business” I think this is not also wrong and offending as this capability of the Android System really should have its own permission.

For me, as there is no system-defined permission for reading installed apps, this is clearly a case of “it’s not a bug, it’s a feature” that is really creepy.

UPDATE: Comments from Zigurd on Hacker News

I’ve submitted this post to Hacker News and an user raised some interesting questions that I’ll post below and comment on them:

Package names weren’t made to be private

There are a few rationales one could cite for this:

One could probably obtain the package names of all the apps out there, so, as long as package names can be used to access components in Android, this is information that could be extracted by trial and error anyway.

I totally agree on “package names weren’t designed to be private”. As I cited this is a feature not a bug but I think it should. Not that the package name should be a secret but you shouldn’t be able to retrieve the installed ones from the user system.

The impact doesn’t pose a threat

On the other hand, everything you can do with this knowledge is controlled by sandboxing and permissions, so having this knowledge doesn’t give you anything beyond what you could have with a good guess.

Lastly, one would have to reinvent package naming around names that cannot be guessed. To sum it up, package names weren’t designed to be private, and retrofitting privacy to package names is hard.

I disagree with “everything you can do with this knowledge is controlled by sandboxing and permissions, so having this knowledge doesn’t give you anything beyond what you could have with a good guess.” because this information can be used to later push application-specific ads or even try to present the user with data in order to make him click on an ad or link and get exposed.

There are several ways on enumerating (guessing) installed packages

I agree there is a privacy concern, however, if you took away that method in the package manager, you could still try invoking, say, standard methods in components in packages and guess their names.

The developers’ domain names are public, so there is no way to prevent guessing parts of package names in Android and probably no way to prevent guessing complete package names.

Let’s take a use case: I want to secretly check if you have banking apps installed. I can install them and discover their package names. Then I can make a malicious app that checks if some component of those apps exists, by checking for an intent filter match, for example. Then I present you with a targeted phishing attack that looks like those apps’ screens. You didn’t need to enumerate all installed packages to do that.

I get this point and I do agree that are diferrent ways on enumerating apps but you need to do some guessing. The evil part I think is that you can enumerate ALL apps without need to guessing.

There are legitimate uses for enumerating all the packages

There are legitimate uses for enumerating all the packages. I’ve used it for a plug-in architecture for an app that enables 3rd party plug-ins.

And I also agree with you that there are legitimate uses for that, as you have for sending/receiving SMS, but my point is: Users should be warned that this app is attempting to do that so they can judge where to install it or no, as you have for all other sensitive information.

I’m really happy on having this article bringing up this discussion because it’s an example of how even to minor issues, the security concerns should be evaluated.


comments powered by Disqus