Thursday, October 15, 2020

Mobile Screenshot prevention Cheat Sheet - Risks and Scenarios

Mobile Screenshot Prevention Cheat Sheet - Risks and Scenarios

The following article will try to analyze and explain risks and attack scenarios affecting mobile applications without any implemented prevention mechanism against screenshotting.

Briefly, what is the problem?

Extremely summarizing, mobile applications need to implement screenshot prevention mechanisms in order to avoid an attacker to steal sensitive data, such as credentials or private information, that are shown on the screen during the application execution.

The attacker could act by directly accessing the victim’s device, generating a screenshot using the device specific combo keys and then he would be able to send the generated screenshot to himself over the network. This kind of attack does not need any specific privilege or compromised device capability in order to get exploited. Just physical access to the device.

On the other hand, the attacker could act by using a malware delivered on the victim’s device in some successful way, such as an untrusted application that may be downloaded from an unofficial store or that can be sent directly to the victim. As soon as the victim’s device gets infected, the attacker is now able to access private data and, based on the privileges acquirable on the infected device, he would be able to generate screenshots and/or access system generated screenshots which are stored on the device and may contain useful information to carry on further attacks.

Attack Scenarios

Basically the following three attack scenarios can be used by an attacker in order to successfully exploit the vulnerability, based on which access level is achievable on the targeted device:

- The attacker has physical access to the targeted device: let’s assume the victim left his device unlocked at his desktop with a running application which is showing sensitive information. In this scenario it would be possible for an attacker to generate a screenshot using the device specific combo keys sending it to its own device through the network.  
- The attacker has planted a background running malware on the targeted device: let’s assume that the attacker has delivered a malicious application on the victim’s device by uploading a compromised application on the store or by getting the victim to download an application from an untrusted source and the target device has a compromised status that can allow the malware to have privileged access to system calls. In this scenario the attacker would be able to silently generate device screenshots that can be then sent to the attacker himself through the network, exfiltrating sensitive data. 
- The attacker has planted a foreground running malware on the targeted device: let’s assume that the attacker has delivered a malicious application on the victim’s device by uploading a compromised application on the store or by getting the victim to download an application from an untrusted source and the target device has modified status that can allow the attacker to read files outside of the application sandbox. In this scenario the attacker would be able to access system generated screenshots that may contain sensitive information and can then exfiltrate these files through the network.



The main risk related to this kind of vulnerability is sensitive information stealing.
Any information shown on the device display can be stolen if not explicitly protected.

So if an application is displaying private information in any of its views, it must be protected.

An attacker can use automated OCR (Optical Character Recognition) analyzers in order to automatically process the gathered screenshots and extract any information contained therein.

Any extracted information can then be then exfiltrated to an attacker controlled target in several possible ways, which would not be covered by this article.

The following list is just an example of which kind of data can be stolen:

  • - Passwords
  • - PII (Personal Identifiable Information)
  • - PHI (Personal Healthcare Information)
  • - Private data such as appointments, notes, etc.
  • - Contacts
  • - Email and message contents
  • - [...]

Real world: a concrete attack

As already stated, there are two kinds of approaches an attacker can use, based on how his device is  accessed. Both of them will be explained in the following paragraphs.

In both scenarios, we will assume that the Bill, the victim, is using the SuperSecureMail application. Bill resets his password, and the SuperSecureMail application generates a set of temporary credentials, showing them on the screen so that Bill will be able to copy them and access back to his mail account.

Scenario 1: The attacker has physical access to victim’s device

Bill is in his office, and he has just generated temporary credentials in his SuperSecureMail application. Now, since the application has generated a complex and strong password, Bill wants to write them on a piece of paper in order to later perform a login to his mailbox, but unfortunately he ran out of paper, so he decides to go to the office next door in order to borrow some. Doing this, Bill leaves his mobile device unlocked on his desk.

At this point the attacker can pick Bill’s device, and he can see the credentials on the screen. He has a little time before Bill’s return, so he decides to pick a screenshot of what is on the screen using the key combination that is specific to that device and then he sends himself the generated screenshot over a Bluetooth connection.

Since the application was not implementing any screenshotting countermeasure, the attacker now has a screenshot containing Bill’s credentials on its device and he can use the obtained information to access Bill’s mailbox and/or perform further attacks.

Scenario 2: The attacker has access to victim’s device through a malware

This scenario is a bit more complex than the previous one since the attacker needs to plant a malware to Bill’s device before starting the attack, moreover Bill has a device which is running a mobile operating system which implements a permissive access control policy and allows processes to perform privileged operations (e.g. the device is rooted or jailbroken).

There are many ways an attacker could use in order to trick Bill to install an attacker controlled malware. In this case the attacker knows that Bill loves to play with mobile games which are full of cute kittens.
Using this information, the attacker creates a real mobile game with the desired look but he also inserts malicious pieces of code into the application. These pieces of code will run in a specific mode in order to retrieve system generated screenshots of any mobile application installed on Bill’s device. 

After generating this mobile game, the attacker sends an email to Bill saying “Hey Bill, attached there is a mobile game that we think you would love! It is a preview and we care about your opinion, so it is free at this time but it is only for you!”.

Bill loves cute kittens. 

Bill installs the game and gets infected unknowingly by the attacker’s malware.

At this point, as in the previous scenario Bill has just generated temporary credentials in his SuperSecureMail application. Now, since the application has generated a complex and strong password Bill copies this password on the Notes application of his device.

Now, when Bill switches between the SuperSecureMail application and the Notes application, while bringing the SuperSecureMail application to the background the mobile operating system generates a screenshot of what the application is displaying in that moment. 
The screenshot is a standard image that will be shown in the device’s task manager and that will be stored in a specific path on the device’s file system that varies based on the operating system version.

Finally, the malware can scan the file system searching for operating system generated screenshots. When it finds them, it would be possible to exfiltrate these images to an attacker controlled domain where the data can be processed and the contained sensitive information can be extracted.

It must be noted that the aforementioned scenarios are only two of many kind of attacks that may take an attacker to exploit this kind of vulnerability. However they are two really common scenarios that can happen in the real world.

How to do this? Let's see the code!

The following sample of code[1] is showing how is it possible to generate a screenshot from an Android background service, using superuser’s privileges:

Process sh = Runtime.getRuntime().exec("su", null,null); 
OutputStream os = sh.getOutputStream(); 
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII")); 

Bitmap screen = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+ File.separator +"img.png");
ByteArrayOutputStream bytes = new ByteArrayOutputStream(); screen.compress(Bitmap.CompressFormat.JPEG, 15, bytes); 
File f = new File(Environment.getExternalStorageDirectory()+ File.separator + "test.jpg"); 
FileOutputStream fo = new FileOutputStream(f); fo.write(bytes.toByteArray());
FileOutput fo.close();

In a similar way the following example of iOS code [2] can be used in a Mobile Substrate module, running in a jailbroken device, to generate a screenshot of any application:

UIKIT_EXTERN CGImageRef UIGetScreenImage();
CGImageRef ref = UIGetScreenImage(); 
UIImage* img = [UIImage imageWithCGImage:ref];

The following library developed by Google can be used to generate screenshots from an Android background service without having access to superuser’s privileges:
In a similar way, if the attacker is targeting Android versions 21+, the following native framework can be used in order to achieve the same result, getting a screenshot generated on a standard device:

Example - 1: accessing system generated screenshots

In this paragraph is shown how an attacker can access system generated screenshots for the Safari application.
For this example, the Safari application has been opened and then it has been put on the background. This action resulted in the following image being shown in the iOS task manager:

System generated screenshots are located at the following location on iOS 12:

For example, in this case, Safari system generated screenshots are located at the following location:

The following screenshot is showing the content of the above folder:

Finally, opening the file named E341AE9B-B12A-4E8B-AB08-1DA156CDF9E2@2x.ktx we can see that the content is the screenshot that was shown in the iOS task manager shown before:

Example - 2: accessing user generated screenshots

In a similar way, user generated screenshots can be accessed from any application which the permission to access the device photo library was granted.
In this example, we are explicitly generating a screenshot of the Safari application.

User generated screenshots can be found at the following location in iOS12:

Accessing this location, and opening the file named IMG_0039.PNG we can finally access the previously generated screenshot:

Conclusions and next steps

This article analyzed which risks and scenarios are afflicting mobile applications which are not explicitly implementing mobile screenshotting prevention, trying to clearly explain what an attacker can do in order to gather personal data and sensitive information.

What can a user do in order to prevent sensitive data from being stolen leveraging this kind of attack? 

It must be noted that the user by itself can not totally prevent these types of attacks, but he can mitigate them by using the following best practices:
  • Do not let people to have unauthorized physical access to the device
  • Do not install any application coming from a untrusted sources such as email attachments, unofficial application stores or any other source available on the web.
  • Do not modify the device and operating system statuses by using procedures such as rooting, jailbreaking or installing modified versions of the mobile operating system.

The next question would be: how can a mobile application be checked if it implements Mobile Screenshot countermeasures? How can this issue be fixed?

These topics will be covered in one of the next blog posts with the title: “Mobile Screenshot Prevention Cheat Sheet - Testing and Fixing”.

Thursday, July 30, 2020

Implementing Secure Biometric Authentication on Mobile Applications

Nowadays, almost every mobile device has a biometric sensor that allows developers to implement local authentication and also store sensitive data securely through dedicated APIs.
Biometric authentication is generally more secure than classic username/password approach. Anyway it must be considered that a wrong implementation could allow an attacker to easily bypass authentication mechanisms by using hooking techniques which can be performed with tools like Frida, Objection, and other similar utilities.

In this article we are going to expose some common mistakes that developers can make while implementing  biometric authentication and how to implement it in the correct way.

Biometric Authentication in Android

The Android platform introduced the biometric authentication in Android 6.0 (API level 23) with the class FingerprintManager which supported only fingerprint authentication.
In Android 9 (API level 28), the FingerprintManager was deprecated due to the release of android.hardware.biometrics.BiometricPrompt.
Lastly, In Android 10 (API level 29) the biometric authentication is managed through android.hardware.biometrics.BiometricManager.

It is worth considering that the Android platform introduces also the classes androidx.biometric.BiometricManager and androidx.biometric.BiometricPrompt that could be used instead of the previous ones. These classes will automatically query the BiometricManager on devices running Android 10 (API 29) and FingerprintManagerCompat on Android 9.0 (API 28) and prior versions.

The Android platform, unlike iOS, does not allow to save arbitrary data within Keystore. However, it allows to create encryption keys, which are saved in the Keystore. For every key it is possible to define the access criteria.
In order to implement effective biometric authentication, it is therefore necessary to create a key that can be used only after a successful biometric authentication. This key should be used to encrypt and decrypt a sensitive data such as an authentication token.

In order to use the biometric authentication all of the following requirements must be fulfilled:

1) Require the proper permission in the Android Manifest:

<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />

2) Check if the user can authenticate using biometrics:
This includes having a protected lock screen enabled, a biometric hardware available and a biometric identity registered (For instance a fingerprint). The following piece of code shows a sample implementation:

import androidx.biometric.BiometricManager;
. . .
BiometricManager biometricManager = BiometricManager.from(this);
switch (biometricManager.canAuthenticate()) {
    case BiometricManager.BIOMETRIC_SUCCESS:
        // User can authenticate using biometrics
    case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
        // No biometric features available on this device
        // Biometric features are currently unavailable
    case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
        // The user hasn't associated any biometric credentials with their account

3) Check if the application has the correct permissions:

context.checkSelfPermission(Manifest.permission.USE_FINGERPRINT) == PermissionResult.PERMISSION_GRANTED;

context.checkSelfPermission(Manifest.permission.USE_BIOMETRIC) == PermissionResult.PERMISSION_GRANTED;

The most important methods which must be used in order to implement the biometric authentication in Android are the following ones:

1) authenticate (which starts the authentication flow):

biometricPrompt.authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher));

2) onAuthenticationSucceeded (which is called upon a successful authentication):

public void onAuthenticationSucceeded(
        @NonNull BiometricPrompt.AuthenticationResult result) {
// . . . .

The cipher referred in the first parameter of the authenticate method should be used in order to decrypt a secret data which has been previously stored in the device. Such cipher can use both asymmetric and symmetric algorithm.

In the following example we are going to create a key for a cipher which uses AES-CBC-PKCS7.

KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, “AndroidKeyStore”);
keyGenerator.init(new KeyGenParameterSpec.Builder (KEY_ALIAS,
        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)

When creating the key for the cipher that will be used in the biometric authentication flow, the most important options are the following ones:

1) setUserAuthenticationRequired(true): available from API level 23, when set to true, the key can be used only if the user has been authenticated. Additionally, the key will become irreversibly invalidated once the secure lock screen is disabled, or when the secure lock screen is forcibly reset. 

2) setUserAuthenticationValidityDurationSeconds(-1): available from API level 23, when set to -1 the key can only be unlocked using a biometric identity. If it is set to a different value, the key can be unlocked using a device screenlock too.

3) setInvalidatedByBiometricEnrollment(true): available only from API level 24, when set to true, the key is irreversibly invalidated when a new biometric is enrolled, or when all existing biometrics are deleted. Consider that the value is true by default.

Before authenticating the user with biometrics, the cipher should be initialized in order to check if the key is still valid. This can be done as follows:

public Cipher getCipherForBiometrics() {
    try {
        final Cipher cipher = Cipher.getInstance(
                       KeyProperties.KEY_ALGORITHM_AES + "/"
                        + KeyProperties.BLOCK_MODE_CBC + "/"
                        + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        final SecretKey key;
        final KeyStore keyStore =  KeyStore.getInstance(“AndroidKeyStore”);
        key = (SecretKey) keyStore.getKey(KEY_ALIAS, null);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher;
    } catch (KeyPermanentlyInvalidatedException e) {
        return null;
    } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
            | NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException e) {
        throw new RuntimeException("Failed to init Cipher", e);

Once the cipher is properly initialised it should be used as an argument for the authenticate method in order to start the biometric authentication flow.

. . .
Cipher cipher = getCipherForBiometrics();
if (cipher != null) {
    biometricPrompt.authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher));
. . .

The biometric authentication flow is then managed by the Android platform, and the method onAuthenticationSucceeded is called upon a successful authentication.

It is worth considering that this method can also be called by using hooking techniques and tools such as Frida. The difference between a valid authentication flow and a tampered authentication flow is the BiometricPrompt.CryptoObject.

Indeed, when a valid authentication flow is performed the Android platform properly instantiate the cipher contained within the BiometricPrompt.CryptoObject, and then this must be used to decrypt critical data such as the aforementioned authentication token.

Instead, when this method is called by using hooking techniques the cipher is not properly instantiated and when using it to decrypt the data, an exception will be raised.

public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
        Cipher cipher = result.getCryptoObject().getCipher();
        byte[] decrypted = cipher.doFinal(// get here authentication token encrypted);
        String authenticationToken = decrypted.toString();
        // save the authentication token somewhere
       . . . 

This implementation is secure even against hooking techniques because when calling the onAuthenticationSucceeded callback with Frida, the AuthenticationResult object does not contain a valid cipher instance since the used key, that has been defined as accessible only after a biometric authentication, has not been unlocked by the Android OS and the cipher will raise an Exception when trying to decrypt the data.

During the various assessments performed on mobile applications we’ve found different insecure implementation of the biometric authentication that looks like the following one:

public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {

This kind of implementation is insecure since does not make use of the  BiometricPrompt.CryptoObject contained in the AuthenticationResult object, but it assumes that the authentication has been properly validated since the method onAuthenticationSucceeded has been called and allows the user to enter the application.

It is worth considering that even implementation that makes use of the BiometricPrompt.CryptoObject could be insecure if they do not decrypt data that are necessary to login the user (such as an authentication token, JWTs and so on). Indeed even Exceptions could be captured using hooking techniques and could be ignored in order to continue the application flow. 

Biometric Authentication in iOS

The iOS platform introduced the biometric authentication starting from iPhone 5s in 2013. At that time it supported only the fingerprint authentication known as Touch ID.

When Apple released the iPhone X, the Face ID was added as biometric option that could be used to authenticate a user.

The biometric authentication flow is usually implemented with the LocalAuthentication framework. It is worth considering however that the LocalAuthentication framework is an event-based procedure and can be bypassed with hooking techniques and tools such as Frida or Objection.

Unlike Android, the iOS platform allows to save arbitrary data within the Keychain defining the access criteria for every stored item.

In order to implement an effective biometric authentication, it is suggested to use the Keychain methods instead of the LocalAuthentication framework. Such approach consists in storing sensitive data (such as an authentication token) within the Keychain, and defining the proper access criteria so that the data can be used only after a successful biometric authentication.

In order to use the biometric authentication, it is required to check if the biometric hardware is available and if the user has enrolled biometric identitites. This can be done using the canEvaluatePolicy method as shown below:

var error: NSError? if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { // handle biometric authentication . . .

The canEvaluatePolicy method with the deviceOwnerAuthenticationWithBiometrics flag, returns true only if the hardware to authenticate the user through biometrics is available and if the user has enrolled biometric factors.

When storing sensitive data for a biometric authentication within the Keychain it is recommended to use the following flags:

1) kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly: requires that a passcode is set on the device. The data is accessible only with the device unlocked and it is deleted when the user deactivates the passcode.

2) kSecAccessControlBiometryCurrentSet/kSecAccessControlBiometryAny: requires a user to authenticate with biometrics (e.g. Face ID or Touch ID) before accessing the data in the Keychain item. When using kSecAccessControlBiometryCurrentSet, whenever the user adds a fingerprint or facial representation to the device, it will automatically invalidate the entry in the Keychain. This makes sure that the keychain item can only be unlocked by users that were enrolled when the item was added to the keychain.

The usage of the other flags should be avoided when storing data relative to biometric authentication since they do not mandatory require the usage of biometric factors to retrieve the data when accessing the application.

Following it is reported an example on how to securely save data in the Keychain for biometric authentication:

var error: Unmanaged<CFError>?
guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
                                                          &error) else {
    // failed to create AccessControl object
var query: [String: Any] = [:]
query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrLabel as String] = "label_for_auth_token" as CFString
query[kSecAttrAccount as String] = "App Account" as CFString
query[kSecValueData as String] = "here_goes_auth_token".data(using: .utf8)! as CFData
query[kSecAttrAccessControl as String] = accessControl

let status = SecItemAdd(query as CFDictionary, nil)
if status == noErr {
    // successfully saved
} else {
    // error while saving

When requesting the sensitive data, the iOS platform will ask for biometric authentication returning data or nil depending if the biometric authentication was successful or not.

During the various assessments performed on mobile applications we’ve found different insecure implementation of the biometric authentication that make use of the evaluatePolicy method and are similar to the following one:

let context = LAContext()
var error: NSError?
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Authenticate with biometrrics to access the application") { success, evaluationError in
    guard success else {
        // Authentication Failed

This kind of implementation is insecure since does not make use of the Keychain, but it assumes that the authentication has been properly validated since the success condition has been met and allows the user to use the application.

Using hooking techniques or tools such as Frida or Objection this kind of implementation could be bypassed without providing a valid biometric authentication.

It is worth considering that even implementations that make use of the Keychain could be bypassed if the proper flags are not set when storing the data in it.

Specifically the usage of the flag kSecAttrAccessibleWhenUnlockedThisDeviceOnly and kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly should be avoided since they do not require that a passcode has been previously set on the device and does not delete the data when the passcode is disabled. Furthermore if the device has no passcode, the data is always accessible since the device is considered always unlocked.

Finally the usage of the other SecAccessControlCreateFlags, except for the aforementioned kSecAccessControlBiometryCurrentSet/kSecAccessControlBiometryAny should be avoided since they do not mandatory require a biometric authentication. Indeed the device passcode could be used as well.


When implementing biometric authentication on mobile application it is recommended to always use solutions that relies on cryptography and secure hardware such as the Keystore for Android and the Keychain for iOS.

Event-based authentication implementation should be considered insecure since they could be easily bypassed on rooted or jailbroken devices by using hooking techniques or tools such as Frida or Objection.

Highly sensitive applications such as banking apps or financial related applications should always rely on strong implementations when using biometric authentication and they should delete the sensitive data when the biometric set is changed or completely disabled.

Finally, for sensitive applications it is also suggested to implement frameworks in order to enhance their resiliency by detecting rooted/jailbroken device or attacks that make use of hooking techniques in order to reduce the risks of being exploited.




This article is the result of research through the official Android and iOS developer guides, the OWASP Mobile Security Testing Guide ( and the assessment activities on mobile applications performed by Minded Security’s consultants.


  • Michele Tumolo 
  • Giuseppe Porcu

Tuesday, June 30, 2020

Behave! A monitoring browser extension for pages acting as "bad boi".

Browsing: What Could Go Wrong?

There's so much literature about client side attacks, but most of the focus is usually about classical malware attacks, exploiting software vulnerabilities.

Malicious scripts happen to be executed every day by thousands of people and most of the times Malware/Virus/Malvertising try to exploit vulnerabilities or to lure the user to install software on his own machine with the intent of staying undetected as much as possible in order to do its criminal business. 
That's what AntiMalware/Virus/[...] are for.

It's the principle of minimum energy: usual malware wants comfortable, smooth, local execution. 

However, there's quite a number of alternative attacks on the client side, with minimal fingerprint that tend to drag less attention and that might go unnoticed on several environments.

Indeed there's a history of  such alternative attacks as:
  • Local Port Scan: Impact: Information Gathering which could be used to perform further client side attacks (Malware) or to have a better unique user profile (Advertising/RiskAnalysis).
  • Cross Protocol attacks: Impact: according to the protocol there might be an abuse of specific features. Such as SMTP abuse etc.
  • DNS rebinding: Impact: SOP bypass resulting in reading sensitive information of internal network servers.

which are not news at all. They are, indeed, quite old attacks that are still as reliable as difficult to completely "fix" by browser vendors because they abuse core features of the Web ecosystem.

Behave! A Monitoring Extension for pages acting as "bad boi"

With those attacks in mind, we thought that, by taking advantage of the browser API at extension layer, a browser extension might help monitoring HTML pages behavior.
That's Behave!
Available as an extension for:

It monitors and warn if a web page performs any of following actions:

  • Browser based Port Scan
  • Access to Private IPs
  • DNS Rebinding attacks to Private IPs
Here's Behave! pointing its finger to a malicious page hosted by host performing access to local IPs:


Behave! Future Plans 

There's a quite a bunch of stealth&malicious client side techniques that could be abused at several levels of security that might be monitored by Behave! in the future.

Monday, May 18, 2020

Remote Working - Web Chats: Threats and countermeasures


With recent worldwide events, a sharply increasing number of companies are offering remote services to their customers. Even traditional businesses are implementing new features or pushing the migration of existing features to new needs of dematerialization of human-to-human relationships. 
Web chats are an example of such trends.

Web chats

Rich messages web chats are a common feature implemented by companies to overcome the need of social distancing, while maintaining a close relationship with customers.
An example of rich messages web chat would be a graphical widget loaded by web site visitors to establish a chat session with a human operator, with the objective of sharing documents in a multimedia environment: users can share PDF files (e.g. personal documents, scans), video or audio files (e.g. vocal record of a formal declaration, acceptance of conditions and clauses for contracts, identity recognition) or even unpredicted formats, to deal with the abundance of multimedia files offered by end-user environments.
To do so, preview feature has a crucial role.


As shown below, a typical scenario is a web server exposing chat capabilities, allowing human operators in a trusted network (e.g. a LAN) to interact with remote customers.
Usually, customers interact with the chat using a common browser over an untrusted network (the Internet, their own device); chat operators interact with customers using a browser or the backoffice component of the web chat, which commonly offers rich features, such as document viewing, session management, multiple channels interaction and capabilities to interact with customers in an "enhanced" manner.

This article will describe several attack vectors from potentially malicious remote customers against targeted chat operators and the software they use to interact with customers: the objective of described workflows is attacking the trusted internal corporate network.

Rich data exchange interaction

Backoffice chat components trie to recognize messages, files and URLs submitted by chat users with the aim of previewing them or offering operators with advanced tools to manipulate data.
Different recognition approaches are usually in place: parse file extensions, MIME type of uploaded files, and actually reading the real content of the file prior to supplying it to the operator.
If the recognition procedure does not thoroughly include a secure implementation of all the mentioned approaches, chat operators and internal resources may be prone to security threats.


Web chats can accept several formats for files, sent by users (e.g. with drag & drop) or submitting URLs.

HTML payloads

The simplest and most known attack vector is abusing the HTML parser of web chats:

Customer enters <b>ciao!</b>
Operator sees ciao!

Customer enters <script>alert("XSS!")</script>
Operator sees:

Malformed PDF file upload

User supplied PDF files can be opened by chat operators in embedded viewers in the backoffice component of the web chat or downloaded on their workstation, within the trusted corporate network.
Such files can be vehicle of arbitrary code (e.g. JavaScript or other active code), which can therefore be executed on the endpoint of chat operators, exploiting known vulnerabilities in the browser or in any other software used by operators to view the file.

As an example, PDF files can contain dynamic JavaScript code, very similar to how XSS attacks work:

Thus, malformed PDFs, especially if loaded with an outdated Adobe Acrobat version, can be an attack vector for further exploits (e.g. meterpreter payloads, malwares, droppers..) against the internal network, the browser, the operating system or other components in the trusted backoffice environment.

Note: any security concern for PDF files should be extended to Office documents (Word, Excel, Powerpoint), especially if older and/or not hardened versions of Microsoft Office are in use.
For example threats may include malwares embedded in Office documents or CSV Formula Injection attacks.

Malicious URLs (Abusing preview feature)

Web chats tries to parse URLs pasted by users' messages, with the aim of previewing their content.
If the parsing procedure is executed correctly, the PDF is previewed by an embedded viewer, and it can therefore lead to scenarios described above.
On the contrary, if the parsing procedure is not correctly executed, the preview mechanism (triggered by the presence of ".PDF" string in the URL) can lead to unexpected events.

For example, if the URL ends with ".pdf" string, the web chat may attempt to dynamically load any preview module. As shown below, ".pdf" in the URL does not indicate a real PDF file, but a folder named ".pdf" on an arbitrary web server.

Content of the attacker's web site:

$ ls ./.pdf -1
minded (executable file)
minded.html (malicious HTML file)
minded.pdf (malicious PDF file)

Behaviour of the preview on chat operator's software:

Several social engineering scenarios can be constructed over this behaviour, for example convincing the chat operator (whose job is trying to efficently interact with a customer) to download other files.

Semi-automatic scenarios, on the other hand, can include the execution of arbitrary code in HTML files, abusing the preview feature. For example, it would be possible to spawn a BeEF HTML hook against the browser in use by the chat operator:

The command & control server (used by the attacker / evil customer) would look similar to the following:

Consequently, the attacker can use a large plethora of social engineering / hijacking techniques.

For example, spawning fake system messages / Java Applet load requests:

Or even spawning fake Clippy Office Assistants:

Embedded players

Web chats may also include MP3 players, which, depending on the library in use by the chat software, may be prone to vulnerabilities related to outdated software modules.


  • Validate any uploaded file according to a predefined list of expected file types:
- Extension
- Content Type
- Actual content of the file
  • Rescale / Resize with a 1:1 ratio any multimedia file, before allowing chat operators to open the file, in the attempt of removing any metadata
  • Properly hardening procedures should be applied to any software in use by chat operators:
- Update PDF viewer software to the latest available version
- Apply proper security options (e.g. Enhanced security and protected mode in Adobe Acrobat) to harden PDF viewer software
  • Define a list of allowed file types for the preview feature, avoiding any other format: if chat operators are expected to receive only URLs, documents and images, define a list where only PDFs and JPGs/PNGs are allowed, while any other extension is excluded from previewing components.