Introduction
In early 2020, a new sophisticated malware for Android called FluBot began to appear. On infected devices, the malware can take full remote control of the device; access victim’s contact lists; send, intercept, and hide SMS messages; log the victim’s keystrokes; steal one-time passcodes; collect personal information; carry out overlay attacks and more. Originally, the malware authors mainly targeted Spanish banks but later expanded their targets to include Australian, German, Polish, and UK banks (HSBC, Santander, Lloyds, Halifax, and others).
The figure below shows an example of the command and control (C2) panel, which contains detailed statistics about victims’ devices.
How FluBot Works
FluBot spreads in several ways, often via SMS messages that include a link to track a parcel by a delivery company.
Sometimes it looks like an SMS voicemail notification, as shown in the Virgin Mobile example below. To hear the message, the user must click an embedded link that goes to a malicious page found on vulnerable WordPress websites.
In other cases, the link goes to a lure page hosted on a compromised web server where the victim is prompted to install a malicious application on their mobile device.
FluBot’s Abuse of Android’s Accessibility Service
FluBot isn’t the first Android malware to abuse Android's Accessibility Service. FluBot appears to have many of the main features of other contemporary Android banking malware:
- Full remote control of an Android device
- Overlay attacks against multiple bank applications to steal login credentials and credit card information (see overlay images below for HSBC and Halifax)
- Send/intercept/hide SMS messages and notifications
- Enabling key logging (screen text-grabbing) functionality
- Ability to steal one-time password codes
How FluBot Infects Devices
The following example shows how FluBot can spread from one infected device to countless others using an initial victim’s contact list.
- The victim received an SMS message that includes a link to a malicious URL.
- The victim clicks the link and is prompted to install an app.
- The victim downloads and opens the malicious app that installs FluBot.
- FluBot accesses the victim’s contact list and uploads it to the C2 server.
- FluBot downloads a list of new contacts to target.
- FluBot sends SMS messages to the new list of target contacts, thus propagating FluBot.
Key Points
This section includes details of the main functionality of FluBot and reviews some of the interesting commands FluBot uses in version 5.0 and version 4.9.
Static Analysis
FluBot uses a number of sophisticated techniques to make it difficult for researchers and security solutions to achieve their goals.
To complicate static analysis, the malware implements many techniques, several of which are described next.
String Encryption
Any significant strings in the malware are encrypted using a custom encryption scheme. Each class contains a function named “ that is responsible for encrypting suspicious strings within the class. It uses XOR encryption and utilizes a pre-defined list of hex numbers that are unique to each class. This list contains the encrypted strings.
The first two arguments subtracted results in the length of the string; the first argument is the offset of the pre-defined list and arg6 is the XOR key. (A tool for extracting the strings can be downloaded here.)
MultiDex
In Android there are limitation on DEX files. For example, you can’t reference more than 64KB of methods within a single DEX file. To overcome this limitation, the developer can set the compiler to split the DEX file into smaller DEX files and then use MultiDex to load those additional DEX files to the App.
MultiDex is a popular and valid Android module that is used to support MultiDEX files.
FluBot uses an implementation of MultiDex to hide its malicious code from static analyzers and reversers. It uses a hard-coded configuration that contains the location of the encrypted dex, location of the decrypted dex, their corresponding name, suffix, and folder, as well as a key for decryption represented as a string.
An encrypted DEX file is stored in the APK’s assets, decrypted, stored as a classes.dex file, archived in a Zip file, and loaded in runtime.
After loading the DEX file, the malware deletes it from the file system to avoid leaving artifacts. (On some variants it does not get deleted.)
DEX Decryption
FluBot uses an encrypted dex file in the assets, which then gets decrypted and loaded to perform its malicious activity. (An extractor tool can be downloaded here.) The encrypted file is a zlib-compressed, XOR-encrypted, and zlib-compressed again DEX file.
To decrypt the DEX file the malware does the following:
- Retrieves a decryption key from the config class. The decryption key is then split into bytes, and specific bytes are used during the decryption.
- Reads the encrypted file in chunks of 8,192 bytes using InflaterInputStream to get the zlib-decompressed data as first stage.
- A custom decryption is used on the first stage data using bitwise-operations.
- After decryption, the data is a zlib-compressed data again. The malware uses InflaterOuputStream to decompress (for a second time) and output the DEX file to the filesystem as a ZIP file using ZipOutputSteam (in chunks of 8,192 bytes).
- The decryption key, locations, and names are retrieved from a static config class. Its strings are encrypted with a simple 0x6033 XOR.
String Decryption
DGA: Version 5.2
In version 5.2 a new command, UPDATE_ALT_SEED, is introduced. It enables the attackers to change the DGA (domain generation algorithms) seed remotely. Once such a command is dispatched, FluBot stores the updated seed inside the shared preferences under “g” key.
The added feature can be seen in this function which is responsible for domain generation:
In the new version, FluBot uses 30 TLDs compared to only 3 TLDs in earlier versions.
DGA: Prior to Version 5.2
FluBot uses Domain Generation Algorithm to find and communicate with the C2 server. The DGA seed is based on the current month and year.
A domain list is then generated based on the DGA seed and one of three TLDs are appended: .ru, .su or .cn. FluBot tries to resolve the domains in the DGA domain list. If it successfully resolves one of them, it stores the domain inside the shared preferences under “f” key.
The following function is responsible for domain generation:
It stores the resolved DGA domain in “f” key:
Get Language and Set Texts, Toasts, and Phone Country Prefix Accordingly
The malware gets the victim’s region by the device’s language and sets the texts and toasts of the app accordingly. It also sets the country phone prefixes for SMS propagation.
If the device’s language is from any of these countries, the application won’t open.
Language list:
DNS Tunneling over HTTPS: Updated in Version 5.0
In version 4.9, FluBot resolved the IP addresses of DGAs and communicated directly with the server using HTTPS port 443. In FluBot version 5.0, the authors completely changed the way the malware communicates with the C2 server. In version 5.0 (and on some late builds of version 4.9), it communicates with the C2 through DNS Tunneling over HTTPS. Here’s how it works:
- The attacker sets a nameserver that will act as a C2 server and receive and send data through the DNS protocol.
- FluBot uses DNS resolving providers such as Google, Cloudflare, and Alibaba to infiltrate and exfiltrate the data to the C2 server.
- FluBot does not need to find the C2 IP address as it is not needed. The DNS provider will route the DNS request to the attacker’s nameserver and responds using a TXT DNS response.
- Every message is Base32-encoded and consists of:
- bot-id (random UUID)
- external device IP
- encrypted payload (see next bullet)
- The encrypted payload consists of:
- 2 bytes – Size of header
- Header - Base64-Encoded RSA-encrypted string contains:
- bot-id
- RC4 key
- RC4 encrypted payload (commands, logging, etc.)
- The Base32-encoded message is then split into chunks of 231-HostNameLength bytes and will be sent separately to the DNS resolvers. Each request will split the base32-encoded data to subdomains of 63 bytes long. An example of requests and responses from the C2 using DNS providers. This is an entire message sent in a fragmented-dotted-way.
The C2 Request:
- “fa9fc670” is the message ID
- First integer is the request number
- Second integer states if it’s the last request for the message ID
- All subdomains up until the hostname are the Base32 message
C2 Response looks the same but without message ID:
- First integer is the request number
- Second integer states if it’s the last response for the message ID
- The rest is a Base64-encoded RC4-encrypted response
To decrypt a message, concatenate every base32-data, without dots, for a single message ID. The result will be bot-id (random UUID) + external device IP address in plain text and the encrypted payload.
DNS Resolving over HTTPS: in Versions Prior to 5.0
In versions prior to 5.0, FluBot tries to resolve the generated DGA domains using a DNS-over-HTTPS technique. It uses common APIs of Google, Cloudflare, and Alibaba.
The malware randomly picks one of the resolvers and retrieves the C2 IP address.
Error Logging
Any uncaught errors that occur in the application will be logged to the C2. The main purpose is to help the attackers fix and improve the malware’s code in later versions.
Encrypted Communication via HTTP using RSA+RC4 Encryption
In versions previous to 5.0, communication with the C2 is encrypted with RSA + RC4.
Each sent and received message starts with a header that contains bot id + RC4 key, which is then RSA-encrypted with a hard-coded public key and Base64 encoded. Then the payload\command is RC4-encrypted with the RC4 key in the header.
The C2 also responds with the same header that gets verified by the malware to make sure the C2 received the header correctly and with the Base64-encoded RC4-encrypted command\data.
The communication is done over HTTP and sent to http://{dga}/p.php.
Shared Preferences
FluBot stores its configuration in Shared Preferences. Keys d and e are new in version 5.0. Key g is in version 5.2.
Key | Description |
a | Bot ID |
b | Default SMS package |
c | Disable notification interception |
d | Device’s external IP (new in version 5.0) |
e | DNS Resolvers (new in version 5.0) |
f | DGA Host |
g | DGA Seed (new in version 5.2) |
PackageName.hashCode() | Per-package inject payload |
FluBot Commands
FluBot authors continue to use sophisticated commands as the malware evolves.
UPDATE_DNS_SERVERS: New in Version 5.0
A new command featured in version 5.0 allows FluBot to update DNS resolvers in the malware’s configuration. The C2 communication in version 5.0 is done through a DNS-Tunneling-over-HTTPS technique. This feature enables the attacker to change its DNS resolvers once they put the attacker’s nameservers on the denylist.
UPDATE_ALT_SEED
New in version 5.2, allows the attacker to update the DGA seed remotely.
NOTIF_INT_TOGGLE - Notification Interception
FluBot has abilities to log and intercept any notification the phone receives. This is primarily used to steal one-time passcodes and sensitive information.
GET_SMS: Propagation Through SMS
This command retrieves a list of phone numbers and their corresponding lure messages for propagation purposes.
It will not send an SMS if the phone number is already in the victim’s contact list. It adds the phone number to the blocked contacts list along with the country prefix according to device’s locale. This will block any return calls or messages from the phished victim.
GET_SMS: Propagation Through SMS, Version 5.2
Version 5.2 of FluBot allows sending longer SMS message using sendMultipartTextMessage along with divideMessage functions.
Example: send phishing SMS messages to phone numbers in the US (Smishing).
RELOAD_INJECTS: Injections and Overlays
FluBot sends the victim’s list of installed applications to the C2 with the GET_INJECTS_LIST command. The C2 responds with a list of applications that has a configured inject\overlay (Read more about this technique).
Every application that a GET_INJECT command is sent to responds with the inject\overlay content.
Victim’s application list iteration:
Show a WebView overlay if a package with configured inject is in the foreground:
In versions 5.0 and later, the injects are wrapped with <--RF-->.
UPLOAD_SMS: SMS Logging
FluBot iterates the victim’s SMS inbox and sends all information to C2 by dispatching a LOG,SMS_LIST command. This includes phone address, body, date and time of submission, type.
SMS_INT_TOGGLE: SMS Interception
FluBot can intercept and hide new SMS messages. The main purpose of this feature is to hijack one-time passcodes sent to a victim’s phone.
GET_CONTACTS: Contact List Logging
FluBot iterates the victim’s contact list and sends all information to the C2. This includes names and phone numbers.
DISABLE_PLAY_PROTECT
FluBot uses Android’s Accessibility Service to disable Google Play Protect, a safety check mechanism for applications installed on a device. The malware starts an intent by redirecting to the Google Play Protect settings page and then clicks on the necessary buttons to disable it.
Run USSD: Recharge Using Phone Call
FluBot has capabilities of calling on demand. This enables the attacker to transfer funds by calling USSD services such as pay-through-phone.
Disable Battery Optimization
This command is used to disable any forced app sleep in the background by Android so that FluBot stays active while the phone sleeps.
Keylogger/Screen Grabber
This command enables attackers to grab text on the screen (key logging) using Accessibility Service.
UNINSTALL_APP
FluBot has the ability to uninstall an app on demand. It sends an action.DELETE intent with the package name to uninstall. The intent will open the package installer package. The Accessibility Service waits for the package installer to be in foreground so it can click on the uninstall button.
OPEN_URL: Opens a URL on the Device
FluBot can open a URL on demand by simply starting an action.VIEW intent. The C2 will send an OPEN_URL command with the URL to open in victim’s device. These URLs can be advertisements that pay the attacker, a website with known XSS to steal user’s data, a WebView-based exploit, etc.
SEND_SMS: Sends SMS Messages on Demand
FluBot can get a list of SMS payloads and numbers from the user, transfers them to the C2, and then sends SMS messages to new victims. This helps to further propagate the malware through spear-phishing attacks.
Command Handler
This function is responsible for dispatching the commands retrieved from the C2. The figure below shows the main functionalities and capabilities of FluBot versions 4.9 through 5.2.
Mitigating FluBot
David Warburton, principal threat research evangelist with F5 Labs, offers the following suggestions for mitigating FluBot.
Prevent
FluBot relies on tricking the user into downloading a trojan hosted on an attacker-controlled server. Android phones will, by default, prevent installation from outside of the Google Play store, though attackers know this and coach the victim into bypassing this restriction. A combined approach, using people and technology, should be taken to mitigate installation of apps from untrusted sources.
First, educate staff members and/or customers that they should rarely, if ever, install Android apps from outside of the Google Play store. They should understand that any message asking them to bypass security for the benefit of installing an app should not be trusted.
Secondly, if managed corporate mobile devices are in use by employees, consider mobile device management (MDM) solutions, which can lock down the ability to install apps from outside of the Google Play store.
It is worth noting that since FluBot is able to capture SMS messages and grab images from the screen, multifactor authentication (MFA) solutions may not prevent the abuse of stolen credentials since one-time passwords can be stolen from the SMS message or viewed on the victim’s screen. MFA solutions which, instead, make use of push notifications to approve login attempts may have some more success in preventing abuse but since FluBot is able to control an Android device using the Accessibility Service, this method may also be inadequate.
Detect
Preventing infection by this kind of trojan can be difficult, if not impossible, for non-corporate or unmanaged devices. It’s therefore critical to be able to identify when stolen credentials are being used by fraudsters and, additionally, detect when automated bots are launching attacks.
Modern application security solutions offer the ability to detect authentication abuse, including credential stuffing attacks. Unlike password brute forcing which can be trivial to mitigate, credential stuffing can be difficult to detect since malicious requests appear quite genuine in nature. Effective solutions should be able to match a supplied password against a list of known stolen credentials and combine this with the ability to detect when requests come from a compromised devices that may be part of a botnet.
Identify
With the ability to fully control the victim’s device and hide incoming SMS messages, it is essential that out-of-band methods are used to alert victims to activity on their account. Using, for example, email to alert the user of a new login or suspicious transaction, may be the only way to reliably inform them of malicious activity on their account.