In October, the FTC announced it had reached a settlement effectively shutting down Retina-X Studios, maker of MobileSpy, PhoneSheriff and TeenShield. According to the FTC:
“Retina-X did not make sure purchasers were using the apps for legitimate purposes. In fact, to install the apps, purchasers often had to weaken the security protections on your smartphone (sometimes called jailbreaking or rooting). Plus, once a purchaser installed the app on your phone, they could remove the icon, so you wouldn’t know they were monitoring you.”
Eva Galperin, a security researcher from the Electronic Frontier Foundation’s Threat Lab, has been leading the fight against stalkerware and personally helping victims reclaim their digital privacy. But despite the recent actions by the FTC and attempts by device makers topurge their online app stores of stalkerware, this sort of surveillance software is still readily available online. In this blog, we’ll take a deep dive into one example of this kind of threat.
Introducing FlexiSPY
FlexiSPY boasts that one can “Spy On Any Computer With Our Powerful Computer Monitoring Software”.
They claim to have “invented the world’s first commercial Spy phone Application in 2006”. They also claim to have been “featured” in numerous publications:
The actual media coverage, however, is far from glowing:
The available features vary by device and operating system but include a comprehensive selection of tools to electronically surveil and physically track the victim.
Among these features are GPS tracking:
Covert photography:
And interception of email, calls and messaging:
Despite a small print disclaimer about “sneaky” usage, FlexiSPY is designed to be installed surreptitiously and to remain hidden from the victim while in use (note: the “user” referred to below is the person installing the app, not the unwitting victim actually using the phone).
FlexiSPY even offers an installation service and pre-hacked phones:
FlexiSPY for Android
The sample we’ll analyze was released earlier this year and was first submitted to VirusTotal in September. Like most Android apps, FlexiSPY is written primarily in Java but it also includes several native libraries compiled for the ARM processors found in most Android devices. The Java portions of the app can mostly be decompiled back to Java source code. However, the native libraries are harder to reverse-engineer and (as we’ll see later) can be used to hide application data.
Installation and Capabilities
FlexiSPY is designed to be installed secretively. On iPhones and Android devices, FlexiSPY specifies that the device should be jailbroken or rooted, giving the application low-level system privileges to circumvent routine protections between installed apps and to hide the FlexiSPY app from the device’s owner. And since the end user will never see the app or the installation process, FlexiSPY is free to request a wide range of Android permissions:
These permissions grant the app access to the devices call log, contacts, camera, messages, microphone, etc. In addition, FlexiSPY taps into Android’s accessibility features to spy on other apps such as Gmail.
By intercepting accessibility events, FlexiSPY is able to exfiltrate emails and contact information from the victim’s Gmail account.
If the victim becomes suspicious or the stalker needs to cover their tracks, FlexiSPY can remotely wipe all data from the device.
In the code responsible for displaying the end user license agreement to the person installing the software (not the victim!), we see a hint of the obfuscation FlexiSPY uses to avoid detection by antimalware and spyware-detection software. The URL is deliberately encoded so that their website does not appear as a plaintext string in the app.
Decoding the string “aHR0cHM6Ly93d3cuZmxleGlzcHkuY29tL2VuL2luc3RhbGxhdGlvbi1ldWxhLmh0bQ==” produces the URL “https://www.flexispy.com/en/installation-eula.htm”.
On installation, FlexiSPY presents itself as an innocuous-looking “Sync Services” app:
The installation process vaguely describes the application “collect[ing] and encrypt[ing]” the device’s data:
Hiding
As mentioned above, FlexiSPY can hide its own app icon and other traces from the device’s user. FlexiSPY claims this is “to stop the child from getting around family rules” or “to preserve screen real estate.” In practice, this is an effective way to prevent the victim from detecting that their device has been compromised. The icon can be hidden during installation:
The icon disappears completely from the desktop once this option is enabled:
In addition, this setting can be changed remotely through FlexiSPY’s web portal:
As we’ll see in the next section, FlexiSPY goes to great lengths to hide the true name and purpose of its application, both from the end user directly and from spyware scanners.
Evasion and Obfuscation
We previously saw that FlexiSPY used base64-encoding to obfuscate URLs. The app also uses RSA and AES encryption to hide various components from static analysis. For example, the app has the encrypted file “5009” included as an asset. Searching the decompiled Java code, we find that this filename is hardcoded as PCF_FILENAME.
At runtime, the complete path to this file becomes an instance variable mPcfPath of an AppEngine object:
This path is used in a call to loadProductConfiguration:
Unfortunately, loadProductConfiguration couldn’t be decompiled correctly.
Nevertheless, there’s enough information to see that the file is decrypted with ConfigDecryptor.doDecrypt():
From there, we see that the “5009” file is encrypted with AES.
Cracking the encryption is infeasible, leaving us with the option of either capturing the decrypted data from the running app or finding the encryption key and initialization vector. Fortunately, the latter is not too difficult. The actual encryption and decryption use standard Java libraries, including Cipher and SecretKeyFactory.
The initialization vector is generated by getIvParameterSpec().
The string of raw bytes is passed to the function d().
We’ve finally caught a break! All of these functions are standard parts of the Java crypto libraries, so we can drop this snippet into a freestanding Java program and extract the 16 byte initialization vector. Now, we move on to the secret key. Going back to the doDecrypt method above, we see that the raw encryption key comes from the function getKey():
Note the call to System.loadLibrary(“flsonyconfig”). This loads one of the native ARM libraries included in the app and makes it accessible via the Java Native Interface (JNI). The function T().h() is itself a JNI function:
The “native” keyword tells the Java compiler that the actual implementation of h() is in a native library. In the library libflsonyconfig.so, we find a function called Java_k_v_T_h, which indicates that it is the native implementation of the function k.v.T.h(). Native code generally can’t be decompiled as cleanly or reliably as Java bytecode but the result is good enough to reveal what is going on.
What we see are a series of function calls that each return a single character, which is then incremented by 25 (0x19 in hexadecimal):
All of these characters/bytes sit consecutively on the program’s call stack. The parameter param_1 is a pointer to a JNIenv object, which includes a table of functions that JNI user code can call. The function at offset 0x2c0 is NewByteArray(), so we can translate:
uVar1 = (**(code **)(*param_1 + 0x2c0))(param_1,0x10);
into
uVar1 = NewByteArray(0x10);
which allocates a 16 byte array for the raw encryption key. Likewise, since the offset 0x340 corresponds with the JNI function SetByteArrayRegion, we can translate:
(**(code **)(*param_1 + 0x340))(param_1,uVar1,0,0x10,&cStack44);
into
SetByteArrayRegion(uVar1,0,0x10,&cStack44);
which copies the 16 consecutive bytes starting at the location of cStack44 into the newly created buffer, a pointer to which is returned to the calling function.
By taking these 16 bytes and calling KeyGenerator with the appropriate parameters, we can generate the encryption key. We can now decrypt 5009, which turns out to be an XML-formatted configuration file (formatted for clarity):
This trick of embedding encryption keys in native code is used repeatedly. In FlexiSPY’s “crackmitigation” module, designed to prevent unauthorized/unpaid use of the app, we see the following:
Both fpu() and jbmc() are native functions that return obfuscated but hardcoded strings of bytes, as above. But jbmc() adds an extra hurdle by requiring an arbitrary parameter that is ultimately ignored.
The parameter param_2 is the location of the argument array and param_3 is the number of arguments. It doesn’t matter what argument is passed, as long as there is at least one. Then dhj_bwl() reconstructs the raw encryption key as before. Here, the FlexiSPY developers chose to use RSA encryption.
Having recovered both the ciphertext and the key, we can decrypt the ciphertext to get the URL “http://client.mobilefonex.com“.
Elsewhere, strings are obfuscated with a simple hardcoded XOR cipher:
“PQYUOBkGHxg2AUAfBRkXC1oXGR9xGl8Y” becomes diagnostics@flexispy.com and “PQYUOBkGHxg2AXM7ChIbB1IIDAg7CV8cMQYdAgsy” becomes diagnostic@digitalendpoint.com. The domain digitalendpoint.com is associated with FlexiSPY’s “employee behaviour monitoring” product:
Encryption is used inconsistently. At one point in the code, the URL and credentials for one of FlexiSPY’s servers are not encrypted at all but merely base64-encoded.
On the device, the app’s logs are DES-encrypted with a hardcoded key.
This is intended to make it harder to debug and modify the application but easy to circumvent:
A Security Flaw
FlexiSPY boasts on their website that their data has not been hacked, unlike other stalkerware makers.
Indeed, a number of stalkerware companies have been hacked, including Retina-X, Xnore and mSpy. But a flaw in FlexiSPY’s encryption makes it possible for an eavesdropper to intercept any of the personal data transmitted from the app to FlexiSPY’s servers. It begins with FlexiSPY’s failure to use https and instead rely on a home-rolled encryption protocol. Each session with the server is initiated by generating a 16-byte (128-bit) AES encryption key. A full 128-bit key is generated but then the last 48 bits are overwritten with hardcoded data.
The unmodified key is sent to FlexiSPY’s servers over plain http with the command code 100 (64 in hexadecimal) and the server replies with the same command code and 112 bytes of encrypted data:
The data is encrypted with the modified 128-bit AES key, which uses the first 10 bytes of the key sent by the client and the 6 hard-coded bytes above, and the initialization vector is the same one we found in the previous section. Upon decryption, this reveals a session ID and the server’s RSA public key:
We can see this exchange reflected in the device logs. Note that 1768422606 is 0x6967FAD0 in hexadecimal:
Following this exchange, the app begins generating a new AES key for each transmission. This key is encrypted using the server’s RSA public key and transmitted along with the AES-encrypted data. Because we only have the server’s public key and not the corresponding private key, we can’t decrypt these transmissions based on intercepted network traffic alone. But the initial key exchange happens over plain http and includes no validation, so an attacker with control of the local network (using a rogue access point like the WiFi Pineapple, for example) can intercept the initial AES key and reply with their own RSA public key and a new session identifier. Then, every subsequent selfie, SMS and surreptitious recording exfiltrated from the device can be decrypted by the attacker for the duration of the session.
We were able to reproduce this vulnerability on a test device at Juniper Threat Labs by redirecting traffic from mobilefonex.com to a server that responded with a hardcoded session identifier 3134983653 (0xBADC0DE5 in hexadecimal) and RSA public key, all encrypted using the app-generated AES key. The FlexiSPY app accepted the spoofed session identifier and key as seen in its log files:
We were able to successfully decrypt subsequent data sent from the app, thus circumventing the entire encryption scheme.
Detection and Remediation
Both network-based and endpoint protection have limited utility against the stalkerware model. SkyATP and JATP will detect the app when it is downloaded, but the attacker can choose to download the app on an unsecured network or simply purchase a pre-compromised phone. Similarly, being installed on a jailbroken or rooted phone gives the stalkerware app superuser access that can easily defeat an antivirus app installed directly on the device. Remediation should involve — at a minimum — a complete factory reset of the device. For a device that may have been purchased directly from a stalkerware vendor, replacing the device is the most secure option.
Indicators of compromise include network traffic to or from the following domains:
mobilefonex.com
flexispy.com
digitalendpoint.com
SHA256 hashes for other known versions of the FlexiSPY app:
0b60c93c5ef18d8562c21fd6bda4bb9cc629b47913a32fc4fd05acffc7df2cbc
254788b618c9e4558be3a718dd83aeb8eb87bc06f895a0d1c5b18275379a2860
35d4dd4c853a071fd2e05f8bfb05c9ac1138cc040bc701b998d9427d4602f413
3d77efd4d77c74bfeddbbcb498429b1fb8c8e5e89bea76ce789d61946f34e1ee
4e711734c571f89ad89015bde8956fdf76dfe8ab5140a7fe988214bf0c37db9a
66d0cd34a03c4a1613a638ef596648df724c148b6eb381fd080ab70c203e6022
b3a8a88b9fdd79880e3d2c501831b262a63c7638cfc9f796b7ec38d27e114499
b421f5a7056e4c42fa76ef2b1a132c6f99c179b159b5aa4045f100c6efe16755
b5571a899aca91ce5949c0dcf8483f02274007d2a7874e00d6fd3b676da3808a
b7a23301118ed495f62f01ee99df45d14928e14e5c7a2606278e8b3a8d949b8d
d0ebd581890e0cc562205e71ca2868375b4349ec2961828117cb866032445be8
d193923c821066caaa84bc16b99e603e247b35f7039ee50c02d3b117a1256625
d4ee8ace03282427e73869187c904da894ef02c17b842aedca66ebd26c7678ff
d70ecd0054a3fd8039bea3081cb945d2839db3b15d7f8a1c1d4a9350747013ec
d7cf15f08898313e87d36853532005ddf258ac11c4ae222c042ace22fa9859cf
f2d37e1ad33b35341e91823aaaa715f8cb6faf9cede6e0dd33f193b7142ee034
f8d613ed8e7df9dc1d675fdc0693e9cd6aef1c8e8452648af54a628cc1e71408
ff2b81f2bd13d42b3b3b12d3876625d2019c143417c045e51ee8abb4abcd698b
Conclusion
Despite the FBI’s takedown of Retina-X and the continued purging of apps on the Google and Apple app stores, stalkerware like FlexiSPY remains a severe threat to safety and privacy. These stalkerware apps are full-featured, allowing a stalker to access virtually any media or data on the phone, track the device’s location, record audio and video remotely and much more. On a jailbroken or rooted device, all of this may be invisible to the typical user, while prevention and mitigation remain ongoing challenges.