In July 2019, Dr. Web reported about a backdoor trojan in Google Play, which appeared to be sophisticated and unlike common malware often uploaded for stealing victims’ money or displaying ads. So, we conducted an inquiry of our own, discovering a long-term campaign, which we dubbed “PhantomLance”, its earliest registered domain dating back to December 2015. We found dozens of related samples that had been appearing in the wild since 2016 and had been deployed in various application marketplaces including Google Play. One of the latest samples was published on the official Android market on November 6, 2019. We informed Google of the malware, and it was removed from the market shortly after.
The latest example of spyware in Google Play disguised as a browser cleaner
During our investigation, we discovered various overlaps with reported OceanLotus APT campaigns. Thus, we found multiple code similarities with the previous Android campaign, as well as macOS backdoors, infrastructure overlaps with Windows backdoors and a few cross-platform resemblances.
Besides the attribution details, this document describes the actors’ spreading strategy, their techniques for bypassing app market filters, malware version diversity and the latest sample deployed in 2020, which uses Firebase to decrypt the malicious payload. We also found out that Blackberry Cylance research team investigated this activity.
Our report is broken down into several sections.
- Malware versions – technical description of versions found, their features and relationships between them.
- Spread – information on specific tactics used by the threat actors for distributing their malware.
- Infrastructure – further details on uncovered infrastructure pieces as well as overlaps found.
- Victimology – thoughts on the actors’ interests in choosing their targets.
- Overlaps with previous campaigns – details of similarities with all related campaigns that we have identified.
More information on PhantomLance is available to customers of Kaspersky Intelligence Reporting. For more information, contact firstname.lastname@example.org
For the purposes of the research, we divided samples we found into a series of “versions” based on technical complexity: from the basic Version 1 to the highly sophisticated Version 3. Note that they do not fully correlate with the chronological order of their appearance ITW: for example, we observed Version 1 samples in late 2019 and in 2017, the year that we also saw Version 3.
Functionality of all samples are similar – the main purpose of spyware was to gather sensitive information. While the basic functionality was not very broad, and included geolocation, call logs, contact access and SMS access, the application could also gather a list of installed applications, as well as device information, such as model and OS version. Furthermore, the threat actor was able to download and execute various malicious payloads, thus, adapting the payload that would be suitable to the specific device environment, such as Android version and installed apps. This way the actor is able to avoid overloading the application with unnecessary features and at the same time gather information needed.
We attribute the latest Google Play sample (MD5: 2e06bbc26611305b28b40349a600f95c) to this version. This is a clear payload, and unlike the other versions, it does not drop an additional executable file. Our main theory about the reasons for all these versioning maneuvers is that the attackers are trying to use diverse techniques to achieve their key goal, to bypass the official Google marketplace filters. And achieve it they did, as even this version passed Google’s filters and was uploaded to Google Play Store in 2019 (see Spreading for details).
No suspicious permissions are mentioned in the manifest file; instead, they are requested dynamically and hidden inside the dex executable. This seems to be a further attempt at circumventing security filtering. In addition to that, there is a feature that we have not seen before: if the root privileges are accessible on the device, the malware can use a reflection call to the undocumented API function “setUidMode” to get permissions it needs without user involvement.
Note that this trick only works with Android SDK version 19 or higher.
Most of the aforementioned operations naturally require root access, but we believe that the root exploit may be delivered as payload in a server response to collected device info. Also, some of the applications that the malware mimics will have notified the user that they only work on rooted devices. For instance, Browser Cleaner can only clean up the browser cache if it is given root permissions.
Specimens of this version were also detected in 2019 and earlier. One of the samples was located in Google Play Store in November 2019 and described in the Dr. Web blog. Based on our detection statistics and spotted version stamps, we believe that this version is a replacement for Version 3, which we did not observe in 2019.
Below are the most valuable points and main differences from the Version 1.
The malicious payload APK is now packed in an encrypted file in the assets directory and is decrypted by the first stage using an AES algorithm. A decryption key and initialization vector (IV) are located in the first 32 + 16 bytes of the encrypted payload.
After decryption, the asset file will look like this.
As you can see, before the APK magic, the file header contains strings that are used for making further reflection calls to payload methods. Here is the first-stage code fragment with explanations regarding the payload loading process.
All Version 2 payloads use the same package name, “com.android.play.games”, which probably mimics the official Google Play Games package, “com.google.android.play.games”.
Moreover, we spotted developer version stamps in decrypted payloads.
|MD5||Developer version stamp|
It is worth mentioning payload manifests, which do not contain any permission requests. As stated in the description of Version 1, permissions required by the malicious features are granted via an undocumented Android API.
We have found two different certificates used for signing Version 2 payloads.
|6bf9b834d841b13348851f2dc033773e||Serial Number: 0xa4ed88e620b8262e
Validity: from = Wed Jan 20 11:30:49 MSK 2010
|8d5c64fdaae76bb74831c0543a7865c3||Serial Number: 0xd47c08706d440384
Validity: from = Wed Apr 13 05:21:26 MSK 2011
Although validity dates look spoofed in both cases and do not point to any real deployment times, by analyzing all payload certificates, we discovered that the second one (Ventoplex) was used to sign Version 3 payloads as well.
The latest samples of PhantomLance discovered in the early 2020 introduced a new technique for decrypting payloads: the malicious payload was shipped with its dropper, encrypted with AES. The key is not stored anywhere in the dropper itself but sent to the device using Google’s Firebase remote config system. The other technical features are very similar to the ones we observed in Version 2, so we tagged this generation as Version 2.1.
We were able to make a valid request to PhantomLance’s Firebase API. The response consisted of a JSON struct containing the AES decryption key, where the “code_disable” value is the decryption key for payload.
What is important, the dropper expects that the AES decryption key will be stored in a parameter named “code”, so this specific variant should not function properly. Besides, we noticed that Firebase previously returned one more field, named “conf_disable”, which has the same value as the “code_disable”, so we assume that the actors are still tinkering with this new feature.
Another interesting technique that the actors are trying to implement is a third-stage payload implant. The second-stage payload (MD5: 83cd59e3ed1ba15f7a8cadfe9183e156) contains an APK file named “data” (MD5: 7048d56d923e049ca7f3d97fb5ba9812) with a corrupted header in the assets path.
The second stage reads this APK file, decrypts it and rewrites its first 27 bytes as described below.
This results in an APK file (MD5: c399d93146f3d12feb32da23b75304ba) that appears to be a typical PhantomLance payload configured with already known C2 servers (cloud.anofrio[.]com, video.viodger[.]com, api.anaehler[.]com). This third-stage APK is deployed with a custom native library named “data.raw”, also stored at the assets path. This library is used for achieving persistence on the infected device and appears to be a custom daemonized ELF executable based on the open-source “daemon.c” Superuser tool component, while in previous samples, we saw MarsDaemon used for this purpose.
Code comparison of the library used to daemonize the third stage payload with daemon.c source code hosted on Github
While we have found that Version 2 has been used as a replacement for this one, as we have not observed any new deployments of Version 3 in 2019, it still looks more advanced in terms of technical details than Version 2. According to our detection statistics and deployment dates on application markets, Version 3 was active at least from 2016 to 2018.
Below are the most valuable points and main differences between Version 3 and Version 2.
The first-stage dropper appears even more obfuscated than that in Version 2; it uses a similar way of decrypting the payload, but it has minor differences. The encrypted content is split into multiple asset files under 10256 bytes in size plus an encrypted config file, and contains payload decryption details.
Below is the payload decryption sequence.
- Decrypt the payload config file from the assets with both a hardcoded name and AES key.
- Read the following values from the decrypted payload config file in this order:
- AES key for APK payload decryption
- Class and method names for reflection calls to the payload
- MD5 for APK payload integrity check
- Number and names of the split APK payload parts
- Decrypt the APK payload header hardcoded in the first stage with the AES key from the payload config. Write it to the APK payload file.
- Using decrypted names of the split payload parts, decrypt their content and append them to the APK payload file one by one.
- Check the integrity of the resulting APK payload file by comparing with the MD5 value decrypted from the payload config.
- Load and run the APK payload.
The following reversed code fragment represents the actual payload decryption process.
Each Version 3 payload has the same package name, “com.android.process.gpsp”, and is signed with the same certificate (CN=Ventoplex), used to sign some of the Version 2 payloads.
The only developer version stamp that we have found in Version 3 payloads is “10.2.98”.
Another notable finding is the 243e2c6433815f2ecc204ada4821e7d6 sample, which we believe belongs to a Version 3 payload. However, no related dropper has been spotted in the wild, and unlike the other payloads, it is signed with a debug certificate and not obfuscated at all, revealing all variable/class/method names and even BuildConfig values. Our guess that this is a debug developer version that somehow got leaked.
As a conclusion to this technical review, it is worth saying that all payloads across the different versions, even Version 1, which is in fact a clear payload without a dropper, share a code structure and locations where sensitive strings, such as С2 addresses, are stored.
The main spreading vector used by the threat actors is distribution through application marketplaces. Apart from the com.zimice.browserturbo, which we have reported to Google, and com.physlane.opengl, reported by Dr. Web, we have observed tracks indicating that many malicious applications were deployed to Google Play in the past and have now been removed.
These search results contain a link to already-removed malware in Google Play
Some of the applications whose appearance in Google Play we can confirm.
|Package name||Google Play persistence date (at least)|
Besides, we have identified multiple third-party marketplaces that, unlike Google Play, still host the malicious applications, such as https://apkcombo[.]com, https://apk[.]support/, https://apkpure[.]com, https://apkpourandroid[.]com and many others.
Example of a malicious application with a description in Vietnamese that is still available in a third-party marketplace (hxxps://androidappsapk[.]co/detail-cham-soc-be-yeu-babycare/)
In nearly every case of malware deployment, the threat actors try to build a fake developer profile by creating a Github account that contains only a fake end-user license agreement (EULA). An example is the one below, reported by us to Google.
This Google Play page contains a fake developer email
Here is a related Github account with the same handle, registered on October 17, 2019.
A Github profile that is part of the fake developer identity
The account contains only one report with one file described as some type of EULA.
During our extensive investigation, we spotted a certain tactic often used by the threat actors for distributing their malware. The initial versions of applications uploaded to app marketplaces did not contain any malicious payloads or code for dropping a payload. These versions were accepted because they contained nothing suspicious, but follow-up versions were updated with both malicious payloads and code to drop and execute these payloads. We were able to confirm this behavior in all of the samples, and we were able to find two versions of the applications, with and without a payload.
An example of this behavior can be seen in Ads Skipper (https://apkpure[.]ai/ads-skipper), in ApkPure.
Versions of Ads Skipper with (v. 2.0) and without (v. 1.0) a malicious payload in ApkPure
Third-party marketplaces like those mentioned in the table above often serve as a mirror for Google Play: they simply copy applications and metadata from Google Play to their own servers. Therefore, it is safe to assume that the samples listed in the table were copied from Google Play as well.
While analyzing the С2 server infrastructure, we quickly identified multiple domains that shared similarities with previous ones but were not linked to any known malware samples. This allowed us to uncover more pieces of the attackers’ infrastructure.
Example of related infrastructure
Tracking PhantomLance’s old infrastructure, which dated back four years, we noticed that the expired domain names had been extended. The maintenance suggested that the infrastructure might be used again in the future.
The PhantomLance TTPs indicate that samples are configured only with subdomains as C2 servers, while most, but not all, parent domains do not have their own IP resolution. We checked the ones that did have a valid resolution and found that they all resolved to the same IP address: 188.166.203[.]57. It belongs to the DigitalOcean cloud infrastructure provider and, according to Domaintools, hosts a total of 129 websites.
Looking up records for this IP address in our passive DNS database suggests that a few dozen of these websites are legitimate, as well as the aforementioned PhantomLance domains and two more interesting overlaps with OceanLotus infrastructure:
- browsersyn[.]com: known domain used as a C2 in a previously publicly reported sample (MD5: b1990e19efaf88206f7bffe9df0d9419) considered by the industry to be the OceanLotus APT.
- cerisecaird[.]com: privately received information indicates that this domain is related to OceanLotus as well.
We have observed around 300 infection attacks on Android devices in India, Vietnam, Bangladesh, Indonesia, etc. starting in 2016. Below is a rough cartographic representation of countries with top attempted attacks.
We have also seen a number of detections in Nepal, Myanmar and Malaysia. As you can see, this part of South Asia seems to be targeted by the actors the most.
Note that due to the chosen distribution vector (publication of malicious samples on publicly available application stores), there should be secondary infection of random victims not directly related to the actors’ interests.
To get more details on targeted victims, we looked at the types of applications that the malware mimicked. Apart from common luring applications, such as Flash plugins, cleaners and updaters, there were those that specifically targeted Vietnam.
- luxury.BeerAddress – “Tim quan nhau | Tìm quán nhậu” (“Find each other | Find pubs” in Vietnamese). An application for finding the nearest pub in Vietnam.
- codedexon.churchaddress – “Địa Điểm Nhà Thờ” (“Church Place”)
Publisher description (hxxps://apk.support/app-en/com.codedexon.churchaddress) translated from Vietnamese:
Information about churches near you or the whole of Vietnam, information about patronies, priests, phone numbers, websites, email, activities, holidays…
- bulknewsexpress.news – “Tin 247 – Đọc Báo Hàng Ngày” (“Read Daily Newspaper”)
Mimics the Vietnamese www.tin247.com mobile news application.
Overlaps with previous campaigns
In this section, we provide a correlation of PhantomLance’s activity with previously reported campaigns related to the OceanLotus APT.
OceanLotus Android campaign in 2014-2017
In May 2019, Antiy Labs published a report in which they described an Android malware campaign, claiming that it was related to OceanLotus APT. We checked the provided indicators using information from our telemetry and found that the very first tracks of these samples date back to December 2014.
It is important to note that according to our detection statistics, the majority of users affected by this campaign were located in Vietnam, with the exception of a small number of individuals located in China.
The main infection vector seems to be links to malicious applications hosted on third-party websites, possibly distributed via SMS or email spearphishing attacks. Examples below.
|Referring URL for victim||Malware URL||First request||Last request|
The latest registered malware download event occurred in December 2017. We observed a small amount of activity in 2018, but judging by the volume of hosted malware and the number of detections we observed, the main campaign took place from late 2014 to 2017.
To best visualize the similarities we discovered, we made a code structure comparison of the sample from the old reported OceanLotus Android campaign (MD5: 0e7c2adda3bc65242a365ef72b91f3a8) and the only unobfuscated (probably a developer version) PhantomLance payload v3 (MD5: 243e2c6433815f2ecc204ada4821e7d6).
Code structure comparison of a sample linked to OceanLotus and PhantomLance payload v3.
Despite the multiple differences, we observed a similar pattern used in malware implementation. It seems that the developers have renamed “module” to “plugin”, but the meaning remains the same. Overlapping classes look quite similar and have the same functionality. For example, here is a comparison of the methods contained in the Parser classes.
|Parser from 0e7c2adda3bc65242a365ef72b91f3a8||ParserWriter/Reader from 243e2c6433815f2ecc204ada4821e7d6|
|public void appendBoolean(boolean f)||public void appendBoolean(boolean value)|
|public void appendByte(byte data)||public void appendByte(byte value)|
|public void appendBytes(byte data)||public void appendBytes(byte value)|
|public void appendDouble(double val)||public void appendDouble(double value)|
|public void appendInt(int val)||public void appendInt(int value)|
|public void appendLong(long val)||public void appendLong(long value)|
|private void appendNumber(Object value)|
|public void appendShort(short val)||public void appendShort(short value)|
|public void appendString(String str)||public void appendString(String value)|
|public byte getContents()||public byte getContents()|
|public void appendFloat(float val)|
|public boolean getBoolean()||public boolean getBoolean()|
|public byte getByte()||public byte getByte()|
|public byte getBytes()||public byte getBytes()|
|public double getDouble()||public double getDouble()|
|public float getFloat()|
|public int getInt()||public int getInt()|
|public long getLong()||public long getLong()|
|public short getShort()||public short getShort()|
|public String getString()||public String getString()|
Using our malware attribution technology, we can see that the PhantomLance payloads are at least 20% similar to the ones from the old OceanLotus Android campaign.
OceanLotus macOS backdoors
There are multiple public reports of macOS backdoors linked by the industry to OceanLotus. We examined these in order to find possible overlaps, with the caveat that it was really difficult to compare malware implemented for two completely different platforms, since two different programming languages were obviously used for the implementation process. However, during the analysis of the macOS payload (MD5: 306d3ed0a7c899b5ef9d0e3c91f05193) dated early 2018, we were able to catch a few minor tracks of the code pattern used in the Android malware implementation described above. In particular, three out of seven main classes had the same names and similar functionality: “Converter”, “Packet” and “Parser”.
Summary of overlaps
Another notable attribution token that applies to most of OceanLotus malware across platforms is usage of three redundant, different C2 servers by each sample, mostly subdomains. Below is an example of this from the samples examined above and OceanLotus Windows malware described in our private report.
|OceanLotus Android campaign 2014-2017|
|OceanLotus MacOS backdoor|
|OceanLotus Windows backdoor|
Based on the complete analysis of previous campaigns, with the actors’ interests in victims located in Vietnam, infrastructure overlaps between PhantomLance and OceanLotus for Windows, multiple code similarities between an old Android campaign and MacOS backdoors, we attribute the set of the Android activity (campaign 2014-2017 and PhantomLance) to OceanLotus with medium confidence.
Considering the timeline of the Android campaigns, we believe that the activity reported by Antiy Labs is a previous campaign that was conducted by OceanLotus until 2017, and PhantomLance is a successor, active since 2016.
In summarizing the results of this research, we are able to assess the scope and evolution of the actors’ Android set of activity, operating for almost six years.
Kaspersky Lab products verdicts
Android campaign linked to OceanLotus (2014-2017)
macOS campaign linked to OceanLotus
PhantomLance payload-free versions
Android campaign 2014-2017
Domains and IP addresses
Android campaign 2014-2017