Toll fraud malware: How an Android application can drain your wallet
Toll fraud malware, a subcategory of billing fraud in which malicious applications subscribe users to premium services without their knowledge or consent, is one of the most prevalent types of Android malware – and it continues to evolve.
Compared to other subcategories of billing fraud, which include SMS fraud and call fraud, toll fraud has unique behaviors. Whereas SMS fraud or call fraud use a simple attack flow to send messages or calls to a premium number, toll fraud has a complex multi-step attack flow that malware developers continue to improve.
For example, we saw new capabilities related to how this threat targets users of specific network operators. It performs its routines only if the device is subscribed to any of its target network operators. It also, by default, uses cellular connection for its activities and forces devices to connect to the mobile network even if a Wi-Fi connection is available. Once the connection to a target network is confirmed, it stealthily initiates a fraudulent subscription and confirms it without the user’s consent, in some cases even intercepting the one-time password (OTP) to do so. It then suppresses SMS notifications related to the subscription to prevent the user from becoming aware of the fraudulent transaction and unsubscribing from the service.
Another unique behavior of toll fraud malware is its use of dynamic code loading, which makes it difficult for mobile security solutions to detect threats through static analysis, since parts of the code are downloaded onto the device in certain parts of the attack flow. Despite this evasion technique, we’ve identified characteristics that can be used to filter and detect this threat. We also see adjustments in Android API restrictions and Google Play Store publishing policy that can help mitigate this threat.
Toll fraud has drawn media attention since Joker, its first major malware family, found its way to the Google Play Store back in 2017. Despite this attention, there’s not a lot of published material about how this type of malware carries out its fraudulent activities. Our goal for this blog post is to share an in-depth analysis on how this malware operates, how analysts can better identify such threats, and how Android security can be improved to mitigate toll fraud. This blog covers the following topics:
The WAP billing mechanism: An overview
To understand toll fraud malware, we need to know more about the billing mechanism that attackers use. The commonly used type of billing in toll fraud is Wireless Application Protocol (WAP). WAP billing is a payment mechanism that enables consumers to subscribe to paid content from sites that support this protocol and get charged directly through their mobile phone bill. The subscription process starts with the customer initiating a session with the service provider over a cellular network and navigating to the website that provides the paid service. As a second step, the user must click a subscription button, and, in some cases, receive a one-time password (OTP) that has to be sent back to the service provider to verify the subscription. The overall process is depicted below:
It should be noted that the process depends on the service provider, thus not all steps are always present. For example, some providers do not require an OTP, which means that the mobile user can subscribe to a service by simply clicking the subscription button while the device is connected to a cellular network.
Fraudulent subscriptions via toll fraud
We classify a subscription as fraudulent when it takes place without a user’s consent. In the case of toll fraud, the malware performs the subscription on behalf of the user in a way that the overall process isn’t perceivable through the following steps:
- Disable the Wi-Fi connection or wait for the user to switch to a mobile network
- Silently navigate to the subscription page
- Auto-click the subscription button
- Intercept the OTP (if applicable)
- Send the OTP to the service provider (if applicable)
- Cancel the SMS notifications (if applicable)
One significant and permissionless inspection that the malware does before performing these steps is to identify the subscriber’s country and mobile network through the mobile country codes (MCC) and mobile network codes (MNC). This inspection is done to target users within a specific country or region. Both codes can be fetched by using either the TelephonyManageror the SystemPropertiesclass. The TelephonyManager.getSimOperator() API call returns the MCC and MNCcodes as a concatenated string, while other functions of the same class can be used to retrieve various information about the mobile network that the device is currently subscribed to. As the network and SIM operator may differ (e.g., in roaming), the getSimOperatorfunction is usually preferred by malware developers.
The same type of information can be fetched by using the SystemProperties.get(String key) function where the key parameter may be one or several (using multiple calls) of the following strings: gsm.operator.numeric, gsm.sim.operator.numeric, gsm.operator.iso-country, gsm.sim.operator.iso-country, gsm.operator.alpha, gsm.sim.operator.alpha
The difference with the first call is that the android.os.SystemProperties class is marked as @SystemApi, therefore an application has to use Java reflection to invoke the function. The MNC and MCC codes are also used to evade detection, as the malicious activity won’t be performed unless the SIM operator belongs to the ones targeted:
The following sections present an analysis of the fraudulent subscription steps in the context of the Android operating system. This analysis can help identify the API calls and the permissions needed for the implementation of a toll fraud scheme.
Forcing cellular communication
Variants of toll fraud malware targeting Android API level 28 (Android 9.0) or lower disable the Wi-Fi by invoking the setWifiEnabled method of the WifiManager class. The permissions needed for this call are ACCESS_WIFI_STATE and CHANGE_WIFI_STATE. Since the protection level for both permissions is set to normal, they are automatically approved by the system.
Meanwhile, malware targeting a higher API level uses the requestNetwork function of the ConnectivityManagerclass. The Android developers page describes the requestNetwork method as:
This method will attempt to find the best network that matches the given NetworkRequest, and to bring up one that does if none currently satisfies the criteria. The platform will evaluate which network is the best at its own discretion. Throughput, latency, cost per byte, policy, user preference and other considerations may be factored in the decision of what is considered the best network.
The required permission for this call is either CHANGE_NETWORK_STATE (protection level: normal) or WRITE_SETTINGS(protection level: signature|preinstalled|appop|pre23), but since the latter is protected, the former is usually preferred by malware developers. In the code snippet depicted below from a malware sample that can perform toll fraud, the function vgy7is requesting a TRANSPORT_CELLULAR transport type (Constant Value: 0x00000000) with NET_CAPABILITY_INTERNET (Constant Value: 0x0000000c):
Figure 3. Code from a Joker malware sample requesting a TRANSPORT_CELLULAR transport type
The NetworkCallbackis used to monitor the network status and retrieve a networktype variable that can be used to bind the process to a particular network via the ConnectivityManager.bindProcessToNetworkfunction. This allows the malware to use the mobile network even when there is an existing Wi-Fi connection. The proof-of-concept code depicted below uses the techniques described above to request a TRANSPORT_CELLULAR transport type. If the transport type is available, it binds the process to the mobile network to load the host at example.com in the application’s WebView:
While it is expected that the Wi-Fi connection is preferred even when mobile connection is also available, the process exclusively uses the cellular network to communicate with the server:
In fact, the user must manually disable mobile data to prevent the malware from using the cellular network. Even though the setWifiEnabledhas been deprecated, it can still be used by malware targeting API level 28 or lower.
Fetching premium service offers and initiating subscriptions
Assuming that the SIM operator is on the target list and the device is using a TRANSPORT_CELLULARtype network, the next step is to fetch a list of websites offering premium services and attempt to automatically subscribe to them.
The malware will communicate with a C2 server to retrieve a list of offered services. An offer contains, between else, a URL which will lead to a redirection chain that will end up to a web page, known as landing page.
What happens next depends on the way that the subscription process is initiated, thus the malware usually includes code that can handle various subscription flows. In a typical case scenario, the user has to click an HTML element similar to the one depicted below (JOIN NOW), and as a second step, send a verification code back to the server:
For the malware to do this automatically, it observes the page loading progress and injects JavaScript code designed to click HTML elements that initiate the subscription. As the user can only subscribe once to one service, the code also marks the HTML page using a cookie to avoid duplicate subscriptions. The following is an example of such a code:
On line 76, getElementsByTagNamereturns a collection of all the Document Object Model (DOM) elements tagged as input. The loop on line 78 goes through every element and checks its typeas well as its name, value, and altproperties. When an element is found to contain keywords, such as “confirm”, “click”, and “continue”, it is sent to the cfunction, as depicted below:
The if statement on line 36 checks if the element has already been clicked by calling the jdh function, displayed below in Figure 12. Finally, the c function invokes the click() or submit() function by the time the branch on line 37 (see figure 11) is followed:
The HTML page loading process is tracked using an onPageFinishedcallback of the WebViewClientattached to the WebView. Subsequently, a handler that listens for relative message types acts depending on the next steps that are required for the subscription to take place. In the code snippet below, the URL loaded in the WebView and a signalwith id “128”is sent to handler2to evaluate the service and initiate the subscription process:
Multi-step or target subscription processes may require additional verification steps. The handler depicted below checks the page URL loaded in the WebView. If the URL matches doi[.]mtndep.co.za/service/, then the handler runs the JavaScript code assigned to the Properties.call_jbridge_dump variable:
A signal with id “107” triggers some additional steps that require communication with the command and control (C2) server. This case is demonstrated in the following figures:
Upon receiving the signal, the handler invokes the v1.bhu8 function:
After checking for the web-zdm[.]secure-d[.]io/api/v1/activatein the server’s reply, the malware invokes the tpack[.]l2.bhu8[.]vgy7 function. This function sends the current URL loaded in the application’s WebView as well as some extra information like country code, and HTML code:
Intercepting OTPs
In most cases, the service provider sends an OTP that must be sent back to the server to complete the subscription process. As the OTP can be sent by using either the HTTP or USSD protocol or SMS, the malware must be capable of intercepting these types of communication. For the HTTP protocol, the server’s reply must be parsed to extract the token. For the USSD protocol, on the other hand, the only way to intercept is by using the accessibility service.
One method of intercepting an SMS message, requiring android.permission.RECEIVE_SMS permission, is to instantiate a BroadcastReceiver that listens for the SMS_RECEIVED action.
The following code snippet creates a BroadcastReceiverand overrides the onReceivecallback of the superclass to filter out messages that start with “rch”:
Subsequently, it creates an IntentFilter, which renders the receiver capable of listening for an SMS_RECEIVED action, and finally the receiver is registered dynamically:
To handle OTP messages that are sent using the HTTP protocol, the malware parses the HTML code to search for keywords indicating the verification token. The following code contains a flow where the extracted token is sent to the server using the sendTextMessage API call:
The additional permission that is required to enable this flow is SEND_SMS.
Another way of intercepting SMS messages is to extend the NotificationListenerService. This service receives calls from the system when new notifications are posted or removed, including the ones sent from the system’s default SMS application. The code snippet below demonstrates this functionality:
We triggered a notification with the title “SMS_Received” and text “Pin:12345” during our analysis, resulting in the following output in the application’s logcat:
Finally, besides the broadcast receiver and the notification listener techniques of intercepting an SMS message, a ContentObserver can be used to receive callbacks for changes to specific content. The onChange callback of the SmsObserver class (depicted below) is called each time the system changes the SMS content provider state:
Suppressing notifications
Since API level 18, an application that extends the NotificationListenerService is authorized to suppress notifications triggered from other applications. The relevant API calls are:
- cancelAllNotifications() to inform the notification manager to dismiss all notifications
- cancelNotification(String key) to inform the notification manager to dismiss a single notification
- cancelNotifications(String [] keys) to inform the notification manager to dismiss multiple notifications at once.
This API subset is abused by malware developers to suppress service subscription notification messages posted by the default SMS application. More specifically, upon successful subscription, the service provider sends a message to the user to inform them about the charges and offers the option to unsubscribe. By having access to the notification listener service, the malware can call any of the functions mentioned above to remove the notification.
Using dynamic code loading for cloaking
Cloaking refers to a set of techniques used to hide malicious behavior. For example, most toll fraud malware won’t take any action if the mobile network is not among its targets. Another example of a cloaking mechanism used by these threats is dynamic code loading. This means that certain malware codes are only loaded when certain conditions are met, making it difficult to detect by static analysis.
The following is a characteristic example of a multi-stage toll fraud malware with SHA-256: 2581aba12919ce6d9f89d86408d286a703c1e5037337d554259198c836a82d75 and package name: com.cful.mmsto.sthemes.
Stage one
This malware’s entry point is found to be the com.android.messaging.BugleApplication, a subclass of the Application class. The malicious flow leads to the function below:
The call on line 21 fills the filesarray with the filenames fetched from the assets directory. The for loop enters theif branch at line 32 if the name of the asset file ends with “355”. Querying the asset files of the app for such a filename yields the following result:
The PhoneNumberAlternateFormatsProto_355 is the source file which, in conjunction with a destination file and the string “xh7FEC2clYuoNQ$ToT99ue0BINhw^Bzy”, is given as parameters to the ns.j function:
The SecretKeySpec on line 68 is constructed from the first 16 bytes of the SHA-1 digest of the password string. This key is used to decrypt the file fetched from the assets using Advanced Encryption Standard (AES) in electronic codebook (ECB) mode. The decryption result is an ELF file that is saved in the application’s cache directory and loaded using the System.load function.
Stage two
The loaded library fetches the PhoneNumberAlternateFormatsProto_300file from the assets folder using the AAssetManager_fromJava function and writes it to a temporary file with the name b in the /data/data/<package_name>/ directory, as seen on line 93 below:
The file b is then decrypted using an XOR operation with the key “xh7FEC2clYuoNQ$ToT99ue0BINhw^Bzy”, which is given from the Java side (see following figures). The decrypted payload is saved with the name l in the application’s data directory:
Figure 27. The native handleTask called from the Java code
The same function loads the decrypted payload l and invokes the com.AdsView.pulgn using the DexClassLoader class loader (variable names have been changed for clarity):
Decrypting the second payload manually yields the following APK file:
It must be mentioned that the DexClassLoadercan be used to load classes from .jar and .apk files that contain a classes.dex entry.
Stage three
This decrypted APK consists of two main classes: the com.Helperand com.AdsView. The com.AdsView.pulgnfunction is the first to be invoked by the native library described in the previous section:
The runnable thread’s main functionality is to connect the host to xn3o[.]oss-accelerate[.]aliyuncs[.]com and download a JAR file named xn30, which is saved to the cache directory with name nvi and then loaded using the startSdk function, as shown on line 81 below:
The file xn30 is the final payload of stage three and is the one that performs the toll fraud activities previously described.
Mitigating the threat of toll fraud malware
Toll fraud is one of the most common malware categories with high financial loss as its main impact. Due to its sophisticated cloaking techniques, prevention from the side of the user plays a key role in keeping the device secure. A rule of thumb is to avoid installing Android applications from untrusted sources (sideloading) and always follow up with device updates. We also recommend end users take the following steps to protect themselves from toll fraud malware:
- Install applications only from the Google Play Store or other trusted sources.
- Avoid granting SMS permissions, notification listener access, or accessibility access to any applications without a strong understanding of why the application needs it. These are powerful permissions that are not commonly needed.
- Use a solution such as Microsoft Defender for Endpoint on Android to detect malicious applications.
- If a device is no longer receiving updates, strongly consider replacing it with a new device.
Identifying potential malware
For security analysts, it is important to be aware that conventional mitigation techniques based on static detection of malware code patterns can only offer limited remediation against this malware. This is due to the extended use of reflection, encryption, compression, obfuscation, steganography, and dynamic code loading.
There are, however, characteristics that can be used to identify this type of malware. We can classify these characteristics into three:
- Primary characteristics – patterns in plaintext included in the application that can be analyzed statically
- Secondary characteristics – common API calls used to conduct toll fraud activities
- Tertiary characteristics – patterns in Google Play Store metadata such as the application’s category, the developer’s profile, and user reviews, among others
The tertiary characteristics are useful for initial filtering for potential malware. Patterns observed in the apps’ metadata are related to malware developers’ attempts to infect as many devices as possible in a short amount of time, while remaining published on the Google Play Store for as long as they can. We’ve observed that attackers often follow these steps to keep their apps in the Google Play Store:
- Use open-source applications that belong to popular categories and can be trojanized with minimal effort. The preferred application categories include personalization (like wallpaper and lock screen apps), beauty, editor, communication (such as messaging and chat apps), photography, and tools (like cleaner and fake antivirus apps).
- Upload clean versions until the application gets a sufficient number of installs.
- Update the application to dynamically load malicious code.
- Separate the malicious flow from the uploaded application to remain undetected for as long as possible.
These applications often share common characteristics:
- Excessive use of permissions that are not suitable to the application’s usage (for example, wallpaper, editor, and camera apps that bind the notification listener service or ask for SMS permissions)
- Consistent user interfaces, with similar icons, policy pages, and buttons
- Similar package names
- Suspicious developer profile (fake developer name and email address)
- Numerous user complaints in the reviews
Once potential malware samples are identified based on these tertiary characteristics, the primary characteristics can be used for further filtering and confirmation. Applications cannot obfuscate their permission requests, use of the notification listener service, or use of accessibility service. These requests must appear in the AndroidManifest.xml file within the APK, where they can be easily detected using static analysis. The commonly requested permissions by malware performing toll fraud may include: READ_SMS, RECEIVE_SMS, SEND_SMS, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE, CHANGE_NETWORK_STATE. Requests for notification listener and accessibility service should be considered extremely suspicious.
Secondary characteristics also include suspicious API calls including: setWifiEnabled, requestNetwork, setProccessDefaultnetwork, bindProcessToNetwork, getSimOperator and cancelAllNotifications. However, since these calls may be obfuscated and may be hard to identify during static analysis, a more in-depth analysis may be necessary for certainty.
Improving Android security and privacy
Google continuously improves Android security and privacy as the mobile threat landscape evolves and new threats and adversary techniques are discovered. For example, in the operating system, API calls that can reveal potentially sensitive information continue to be removed or restricted, and in the Google Play Store, the publication policies guard against use of certain high-risk permissions (for example, the ability to receive or send SMSs) by requiring a Permission Declaration Form to be completed justifying their use. We anticipate Android security will continue to evolve to address abuse.
As discussed, applications currently can identify the cellular network operator and can send network traffic over the cellular network without any transparency to the user. Additionally, applications can request access to read and dismiss notifications, a very powerful capability, without needing to justify this behavior.
Conclusion
Toll fraud has been one of the most prevalent types of Android malware in Google Play Store since 2017, when families like Joker and their variants made their first appearance. It accounted for 34.8% of installed Potentially Harmful Application (PHA) from the Google Play Store in the first quarter of 2022, ranking second only to spyware.
By subscribing users to premium services, this malware can lead to victims receiving significant mobile bill charges. Affected devices also have increased risk because this threat manages to evade detection and can achieve a high number of installations before a single variant gets removed.
With this blog, we want to inform end users about the details of this threat and how they can protect themselves from toll fraud. We also aim to provide security analysts with guidance on how to identify other malicious applications that use these techniques.
Our in-depth analysis of this threat and its continuous evolution informs the protection we provide through solutions like Microsoft Defender for Endpoint on Android.
Learn how Microsoft Defender for Endpoint provides cross-platform security, including mobile threat defense capabilities.
Dimitrios Valsamaras and Sang Shin Jung
Microsoft 365 Defender Research Team
Appendix
Samples (SHA-256)
Sample | SHA-256 |
Initial APK file | 2581aba12919ce6d9f89d86408d286a703c1e5037337d554259198c836a82d75 (com.cful.mmsto.sthemes) |
Payload of stage two: Elf File (loader) | 904169162209a93ac3769ae29c9b16d793d5d5e52b5bf198e59c6812d7d9eb14 (PhoneNumberAlternateFormatsProto_355, decrypted) |
Payload of stage three: APK (hostile downloader) | 61130dfe436a77a65c04def94d3083ad3c6a18bf15bd59a320716a1f9b39d826 (PhoneNumberAlternateFormatsProto_300, decrypted) |
Payload of stage four: DEX (billing fraud) | 4298952f8f254175410590e4ca2121959a0ba4fa90d61351e0ebb554e416500f |
Common API calls and permissions
API Calls | Permissions | SDK |
setWifiEnabled | CHANGE_WIFI _STATE ACCESS_WIFI_STATE | <29 |
requestNetwork | CHANGE_NETWORK_STATE | >28 |
setProcessDefaultNetwork | <23 | |
bindProcessToNetwork | >22 | |
getActiveNetworkInfo | ACCESS_NETWORK_STATE | |
getSimOperator | ||
get (SystemProperties) | ||
addJavascriptInterface | ||
evaluateJavascript | >18 | |
onPageFinished | ||
onPageStarted | ||
onReceive for SMS BroadcastReceiver w/ android.provider.Telephony.SMS_RECEIVED | RECEIVE_SMS | >19 |
createFromPdu | RECEIVE_SMS | |
getMessageBody | ||
onChange for SMS ContentObserver w/ android.provider.telephony.SmsProvider’s content URI (“content://sms”) | READ_SMS | |
sendTextMessage | ||
onNotificationPosted |