Showing posts with label screenshot security. Show all posts
Showing posts with label screenshot security. Show all posts

Thursday, May 27, 2021

Mobile Screenshot Prevention Cheatsheet - Testing and Fixing

Mobile Screenshot Prevention Cheat Sheet - Testing and Fixing



The following article will explain how to test mobile applications against any implemented screenshot prevention mechanism and then it will try to propose mitigations to such problem according to the context.

The following article is the second part of Mobile Screenshot Prevention Cheat Sheet - Risks and Scenarios published on IMQ Minded Security blog.

TLDR; None of the proposed solutions will provide a full protection against screenshotting. Therefore all of them shall be considered as mitigations.

Auditing Screenshot Prevention

In this section we will focus on testing and preventing mobile screenshot via static (e.g. perform a secure code review or a mobile application reverse engineering task) and dynamic (e.g. test a mobile application in its execution environment) contexts.

First things first: anyone approaching mobile application security should carefully read the OWASP Mobile Security Testing Guide (MSTG)[1][2].

Static Analysis

Assuming we have the source code of a mobile application and we have to check if the app implements any mitigation against screenshot attacks, either user or system generated. 
What should we look for?

Android

Usually the common remediation is to set FLAG_SECURE to LayoutParam, hence the first step is to search for it in the codebase. 
But, if we have access to the source code of an application somehow decompiled from a packaged application, it might be possible that the FLAG_SECURE keyword could have been obfuscated or replaced with its integer value.

Therefore, the values to search for, are:
  • FLAG_SECURE (high level symbol)
  • 8192 (numeric value)
  • 0x00002000 (hexadecimal numeric value)
If any of those values are found, it must be checked whether it is used as parameter set to the WindowManager LayoutParams

It should be noted that this flag must be set in all the Android Activities involved in the application and it would be effective for both user and system generated screenshots.

iOS

Since in iOS it is not possible to prevent user generated screenshots, we have to search for any code related to the notification system which can be used to provide awareness about the taken screenshot.
It is then possible to search for the following keywords:
  • userDidTakeScreenshotNotification (Swift)
  • UIApplicationUserDidTakeScreenshotNotification (Objective-C)
If any of the following keywords is found, it would be possible to then observe a function callback being executed after a user generated screenshot has been created.

On the other hand, for system generated screenshots, it would be necessary to analyze pieces of code which are responsible to handle the transitions between foreground and background application statuses.
Since the system generated screenshots are generated just before the application has been put in the background status, in these portions of code, if any remediation has been implemented, we are expecting to find some mechanism which would hide or obfuscate sensitive parts of the UI just before the screenshot has been generated.
It would then be possible to search for the possible values:
  • applicationWillResignActive (here we should find pieces of code hiding parts of the UI, e.g. by setting the hidden property on a view)
  • applicationDidBecomeActive (here we should find pieces of code showing parts of the UI, e.g. by unsetting the hidden property on a view)

    Dynamic Analysis

    TLDR; Let's try to generate a screenshot of the application and let's check if the application UI is shown in the device task manager.

    User Generated Screenshots

    First of all, let's focus on how we can generate a screenshot of our running application. Basically it will depend on which OS and device type we are testing.

    On a variety of Android devices, it is possible to generate a screenshot by using device specific combo keys. The most common combinations are:
    • VOLUME DOWN + POWER
    • VULUME UP + POWER
    It would be also possible to generate a screenshot by using the function tile in the system tray, but it strongly depends on the OS customizations.

    If we are using the Android emulator, we can use the specific button on the emulator toolbar:


    On iOS it depends on which physical keys are available on the target device. The two possible combo keys are:
    • POWER + HOME
    • VOLUME UP + POWER
    Finally, if we are using the iOS simulator, we can use the combo key CMD + S or we can use the drop down menu entry under File -> New Screen Shot.

    In all the above cases, the positive probe is the successful generation of a screenshot containing the same views actually on the device's screen, without any kind of modification and without any kind of notification generated on the device.

    If the running application is properly secured, we will see the following notification being generated on Android:

    On the other hand, since in iOS it is not possible to prevent a user to generate a screenshot of the application, if the running app is implementing a mitigation against screenshot generation it is not actually possible to define which behavior a pentester would see. 
    Some possible mitigations are:
    • The screenshot is partially obfuscated
    • A notification warns the user about the just generated screenshot
    • The application shows a message which informs the user about the just generated screenshot
    Beware that also a transparent and invisible mechanism could be implemented on iOS in order to warn the user about the screenshot generation, so dynamic analysis could not be sufficient in order to fully understand if an app is implementing some mitigation mechanism.

    System Generated Screenshots (AKA Task Manager Screenshots)

    On both the operating systems, the test is the same and is pretty straightforward:
    • Open the target application
    • Send the application in background by pressing the HOME button
    • Open the system task manager (e.g. by tapping the dedicated button on Android or by double tapping the home button on iOS, etc)
    At this point, if an application screenshot is shown identical as it was possible to observe when the app was in foreground, it means that no prevention mechanism was implemented.
    On the other hand, if a blank screen is shown or if the image is partially obfuscated, it does mean that the app is actually implementing some sort of full or partial prevention mechanism against system generated screenshots.

    Fixing Screenshot Issues


    Which APIs are provided to prevent or mitigate the issue?


    Android

    One flag to rule them all.
    Basically Android offers the LayoutParam FLAG_SECURE [3] which can be used to prevent both user and system generated screenshots.

    Simple and straightforward.

    iOS

    On iOS the developer is not provided the ability to prevent user generated screenshots. This is due to the strict UI/UX guidelines provided by Apple which are preventing developers from interfering with the standard OS behavior.
    Two kinds of APIs are interesting from the security point of view, when talking about screenshot prevention mechanisms.

    For user generated screenshots it is possible to use the userDidTakeScreenshotNotification [4] system wide notification. In this way, it would be possible to run code just after a screenshot was generated. 
    The most common approach is to generate a notification or an alert which warns the user about the generated screenshot. This would inform the user and will raise a red flag in case of the screenshot was not explicitly and voluntarily generated.

    On the other hand, for system generated screenshots, it is possible to refer to the applicationWillResignActive [5] application's lifecycle callback. This callback is invoked just before any application is moved from the foreground to the background and enables developers to execute code just before the system generated screenshots are created.
    These operations can include:
    • Putting an overlay over the whole application window
    • Hiding/masking sensitive parts of the UI
    • Navigating to other application parts which are not showing sensitive information

    Stop talking! Show me the code!

    This section is intentionally left without any comment, since explanations have been provided in the above sections.
    Just the source code that can be used in various scenarios and situations.
    Pro tip: If some data is VERY sensitive, such as the combination of a credit card PAN, its PIN code and the CVV2 code, don't put it in your views. If some data is not displayed on the screen, it can't be screenshotted!

    But since in the real world such approach is very often not applicable, let's dig into some mitigation implementations.

    Android

    Protects from:
    • User generated screenshots: ✔️
    • System Generated screenshots: ✔️

    Kotlin

    import android.os.Bundle
    import android.support.v7.app.AppCompatActivity
    import android.view.WindowManager

    class MainActivity : AppCompatActivity() {
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        window.setFlags(
          WindowManager.LayoutParams.FLAG_SECURE,
          WindowManager.LayoutParams.FLAG_SECURE
        )
      }
    }


    Java


    import android.os.Bundle;
    import android.view.WindowManager;

    public class MainActivity extends Activity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_SECURE,
                WindowManager.LayoutParams.FLAG_SECURE
            );
      }
    }


    References: [6]

    iOS

    Protects from:
    • User generated screenshots: ðŸ¤· (partial)
    • System Generated screenshots: ❌

    Swift

    NotificationCenter.default.addObserver(
        forName: UIApplication.userDidTakeScreenshotNotification,
        object: nil,
        queue: .main) { notification in
            //Notify the user, log the action, etc...
    }

    Objective-C

    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationUserDidTakeScreenshotNotification
                                                      object:nil
                                                       queue:mainQueue
                                                  usingBlock:^(NSNotification *note) {
                                                     //Notify the user, log the action, etc...
                                                  }];

    References: [6] [7]


    Protects from:
    • User generated screenshots: ❌
    • System Generated screenshots: ✔️

    - (void)applicationWillResignActive:(UIApplication *)application {
        
        // hide main window
        self.window.hidden = YES;
    }

    - (void)applicationDidBecomeActive:(UIApplication *)application {
        
        // show window back
        self.window.hidden = NO;
    }

    References: [8]

    React Native

    Protects from:
    • Android User generated screenshots: ✔️
    • Android System Generated screenshots: ✔️
    • iOS User generated screenshots: ðŸ¤· (partial)
    • iOS System Generated screenshots: ❌

    Android

    import android.os.Bundle;
    import com.facebook.react.ReactActivity;
    import android.view.WindowManager;

    public class MainActivity extends ReactActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_SECURE,
                WindowManager.LayoutParams.FLAG_SECURE
            );
      }
    }


    iOS

    import React from 'react'
    import { AppState, Platform, View } from 'react-native'

    const SecurityScreen = () => <View />

    const showSecurityScreenFromAppState = appState =>
      ['background', 'inactive'].includes(appState)

    const withSecurityScreenIOS = Wrapped => {
      return class WithSecurityScreen extends React.Component {
        state = {
          showSecurityScreen: showSecurityScreenFromAppState(AppState.currentState)
        }

        componentDidMount () {
          AppState.addEventListener('change', this.onChangeAppState)
        }
      
        componentWillUnmount () {
          AppState.removeEventListener('change', this.onChangeAppState)
        }
      
        onChangeAppState = nextAppState => {
          const showSecurityScreen = showSecurityScreenFromAppState(nextAppState)

          this.setState({ showSecurityScreen })
        }  

        render() {
          return this.state.showSecurityScreen
            ? <SecurityScreen />
            : <Wrapped {...this.props} />
        }
      }
    }

    const withSecurityScreenAndroid = Wrapped => Wrapped

    export const withSecurityScreen = Platform.OS === 'ios'
      ? withSecurityScreenIOS
      : withSecurityScreenAndroid


    Then, in your App component:

    import { withSecurityScreen } from './withSecurityScreen'
    ...
    export default withSecurityScreen(App);


    Pre bundled libraries are also available on NPM [10].

    References: [9] [10]

    Cordova / Ionic

    There are many Cordova plugins which can help on achieving the goal. 
    A good place to start is the cordova-plugin-prevent-screenshot-coffice open source repository.

    Protects from:
    • Android User generated screenshots: ✔️
    • Android System Generated screenshots: ✔️
    • iOS User generated screenshots: ðŸ¤· (partial)
    • iOS System Generated screenshots: ❌
    References: [11]

    Commercial Solutions

    Several commercial solutions are available on the market, however since there was no easy way to test any of them, this blog post will not promote or endorse any commercial tool.

    Conclusions - Wrapping it up

    TLDR; None of the proposed solutions will provide a full protection against screenshotting, therefore all of them should be considered as mitigations.

    Since all the OSs handle the application status transitions in a different way, and different versions of  OSs behave in a different way, it will always be possible to generate some sort of bypass of any implemented mitigation mechanism.
    Moreover, let's say that if an application is running on an untrusted - jailbroken or rooted - device  environment it is easy for an attacker to hook and bypass any kind of protection with some effort.

    The chosen mitigation should then be biased on which data the application is showing on the screen and how much sensitive is this data.
    Examples of such mitigation bypass are available in literature, such as [12].

    References


    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.

     

    Risks

    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")); 
    os.flush(); 
    os.close(); 
    sh.waitFor();

    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"); 
    f.createNewFile(); 
    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];
    CGImageRelease(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:
    • https://code.google.com/archive/p/android-screenshot-library/
    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:
    • https://developer.android.com/reference/android/media/projection/MediaProjection

    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:
    /var/mobile/Containers/Data/Application/{APPLICATION_BUNDLE_ID}/Library/Caches/Snapshots/{APPLICATION_PACKAGE_NAME}

    For example, in this case, Safari system generated screenshots are located at the following location:
    /var/mobile/Containers/Data/Application/B9008870-3F72-4B0E-ADEC-D867FBA060A2/Library/Caches/Snapshots/com.apple.mobilesafari

    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:
    /var/mobile/Media/DCIM/100APPLE/

    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”.