Twitter
Wednesday
May252016

AirWatch Vulnerabilities from the GDS Archives

Overview

At GDS, we’ve researched many Mobile Application management (MAM) container platforms over the years. Early last year, we published a whitepaper and security checklist on the subject to assist developers, security teams, and buyers of MAM platforms. Today we’re releasing details on vulnerabilities in the AirWatch MAM platform that we discovered two years ago that have long since been patched. We still regularly run into these types of bugs in similar platforms in 2016, so we thought it’d be helpful to take a look at a few of them in detail.

In May 2014, we were doing independent vulnerability research poking around at the AirWatch Mobile Device Management Secure Content Locker (SCL) application for Android. During our brief analysis, we discovered a number of vulnerabilities in the SCL application that could allow an attacker with access to a user’s device to bypass the application security and gain access to the encrypted content stored in the application’s sandbox. GDS disclosed the vulnerabilities to AirWatch in May 2014. These have all been remediated by the application vendor and are listed below:

1. User Passwords Susceptible to Offline Brute Force Attacks

2. Inadequate Enterprise Wipe

3. Symmetric Key stored using Java String Object

4. Authentication Bypass via Exported Activities

5. Static IV Used in Cryptographic Operation 

These issues, discovered by Ron Gutierrez, were present in AirWatch Android Agent v4.5.3.782 and Secure Content Locker (SCL) v1.9.2, and were fixed in versions 5.1 and 2.1 respectively. GDS would like to commend AirWatch on their responsiveness and rapid deployment of fixes.

These issues will be discussed further in the rest of this blog post.

Issue Descriptions

User Passwords Susceptible to Offline Brute Force Attacks

The routines used to perform offline authentication to the AirWatch Secure Content Locker application used an unsalted SHA-256 hash to validate the user’s passphrase. This made it possible for an attacker, who gains access to a victim’s stolen device, to perform an offline brute force attack on this hash, in order to determine the AirWatch authentication credentials. Depending on how an organization integrates authentication with AirWatch these credentials are likely to be the user’s Active Directory password. However, as was in our case below this password could be an AirWatch specific password. Note, while AirWatch employs device root detection this does not prevent an attacker who has stolen the device from rooting it and then directly accessing the configuration file storing the hash. This configuration file is at the following location:

/data/data/com.airwatch.contentlocker/shared_prefs/com.airwatch.contentlocker_preferences.xml

An example of the contents of this file is shown below:

<string name="seedHash">NEHfC6vCot2lUdfNOfsjW8TgnNHkVWvyYbtJGI9Ug0g=</string>

GDS verified that this was indeed the AirWatch specific password set up for our test device using the following python code:

>>> import base64
>>> import hashlib
>>> output = base64.b64encode(hashlib.sha256("testing1234").digest())
>>> print(output)
'NEHfC6vCot2lUdfNOfsjW8TgnNHkVWvyYbtJGI9Ug0g='

Inadequate Enterprise Wipe

AirWatch provides an Enterprise Wipe option that is available to device administrators. This option performs an application level wipe rather than initiating a full device wipe, i.e. for organizations using AirWatch to remove company resources from an employee owned device while leaving personal data and the underlying phone configuration intact.

Unfortunately, the Enterprise Wipe functionality failed to adequately eliminate company data from the device’s application directory. Therefore, even after this wipe was performed potentially sensitive data was still present in the following directories:

/shared_prefs
/databases
/files
/sdcard/Android/data/com.airwatch.contentlocker/

This can be verified by performing an “Enterprise Wipe” yourself and then checking these directories to see the artifacts left behind, such as the “seedHash” from the finding above.

Symmetric key stored using Java String Object

This vulnerability had two distinct issues. Firstly, storing sensitive values in a Java String object will prevent the value from being properly cleared from memory. This is the same reason why it is not recommended to use String objects to process passwords. Java String objects are immutable and can persist long after they are required by the application. The application has little control over when the garbage collector will recycle the memory and even when it is collected the contents may persist until the memory has been reallocated and written to. This increases the risk of the key being read from device memory by malware or stolen using a privilege escalation vulnerability that does not require a device reboot. This vulnerability was verified by decompiling the source code of the binary application as shown below:

private String e(String paramString1, String paramString2)
{
 char[] arrayOfChar = paramString1.toCharArray();
 String str1 = this.d.getString("Vector", "");
 String str2;
 if (str1.length() == 0)
 {
   str2 = h();
   String str3 = Base64.encodeToString(str2.getBytes(), 0);
   SharedPreferences.Editor localEditor = this.d.edit();
   localEditor.putString("Vector", str3);
   localEditor.commit();
 }
 byte[] arrayOfByte;
 while (true)
 {
   PBEKeySpec localPBEKeySpec = new PBEKeySpec(arrayOfChar, a(paramString2,
                                                 str2, "A1rW4tchR0xin4t0R"),
                                               20000, 256);
   arrayOfByte = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
                                 .generateSecret(localPBEKeySpec)
                                 .getEncoded();
   if (arrayOfByte != null)
     break;
   return null;
   str2 = new String(Base64.decode(str1, 0));
 }
 return new String(arrayOfByte);
} 

The second issue is that using a String object to store a symmetric key value can lead to a decrease in the overall entropy of the key due to String objects attempting to convert the key material to charset encodings. On Android, the default charset is UTF-8 and any byte sequence that is not a valid UTF-8 character will be replaced with the byte sequence EF BF BD (hex), which corresponds to the Unicode codepoint U+FFFD ‘REPLACEMENT CHARACTER’. This introduces a security risk since invalid byte sequences within the key will be converted to the EFBFBD sequence reducing the overall entropy of the key.

Using the Cydia Substrate tool available on rooted Android devices we can write hooks for Java methods to, for example, print out the contents of the parameters during runtime. The following hook was written to print out the contents of the parameters to the com.airwatch.crypto.openssl.e.b(byte[], String) method.

MS.hookClassLoad("com.airwatch.crypto.openssle", new MS.ClassLoadHook() {
 public void classLoaded(Class<?> resources) {
   String methodName = "a";
   Method lmethod;
   try {
     lmethod = resources.getMethod(methodName, Context.class);
   } catch (NoSuchMethodException e) {
     Log.w(_TAG, "No such method: " + methodName);
     lmethod = null;
   }
   final MS.MethodPointer old = new MS.MethodPointer();
   if (lmethod != null) {
   MS.hookMethod(resources, lmethod, new MS.MethodHook() {
       public Object invoked(Object resources, Object... args)
                     throws Throwable {
         Log.i(_TAG, "com.airwatch.a.b.a() is hit");
         Log.i(_TAG, "param1: " + bytesToHex((byte[])args[0]));
         Log.i(_TAG, "param2: " + printString((String)args[1]));
         return old.invoke(resources, args);
       }
     }, old);
   }
 }
});
public static String bytesToHex(byte[] bytes)
{
 char[] hexChars = new char[bytes.length * 2];
 for ( int j = 0; j < bytes.length; j++ ) {
   int v = bytes[j] & 0xFF;
   hexChars[j * 2] = hexArray[v >>> 4];
   hexChars[j * 2 + 1] = hexArray[v & 0x0F];
 }
 return new String(hexChars);
}

The console output below shows the values returned by the application.

param1: 4B46FAF3F28FA6B3F7A44951D4F8330CCD0C82D42438D053209B21473EEA130545605F245D241E1B332ECBF87F263B9E

// Base64 decoded ‘master_encryption_key’ stored in SharedPreferences XML file.

param2: 1B3C495B47EFBFBD3426EFBFBD76EFBFBDEB8794EFBFBDEFBFBD47EFBFBDEFBFBD68EFBFBD0E4F332D5B76EFBFBDEFBFBD285938

// Derived Encrypted Key from AirWatch Password

As you can see in the output above, due to the charset conversion process this issue causes the resulting symmetric key to lose a total of 22 bytes of entropy rather than containing the the expected 32 bytes of entropy.

Authentication Not Enforced when calling Search or Main Activities directly.

The application contains several Activities, which can be found in the AndroidManifest.xml file, that can be abused to bypass the password lock screen. These Activities do not contain the necessary logic to force the user back to the authentication screen. By exploiting this issue an attacker can access metadata of files stored within SCL without knowledge of the user’s login credentials. Therefore, we can deduce that either the file metadata is not encrypted by the application, or that the application can decrypt the content stored in its application directory without requiring the user’s credentials. Either scenario is bad for an application such as this. A walkthrough for exploiting this behavior in the Search Activity is provided below. Explotation of the Main Activity is identical, the only caveat being that exploiting the Main Activity requires the device be to rooted.

Below you can see the intent filter for the SearchActivity from the AndroidManifest.xml file:

<activity android:name="com.airwatch.contentlocker.ui.SearchActivity"
         android:launchMode="singleTop"
         android:windowSoftInputMode="adjustPan">
 <intent-filter>
   <action android:name="android.intent.action.SEARCH" />
 </intent-filter>
 <meta-data android:name="android.app.searchable"
            android:resource="@xml/searchable" />
</activity>

 

With the SCL application closed out on the target device, connect your adb in the usual manner. After which enter the following commands to manually invoke the “SearchActivity” intent:

adb shell am start -a android.intent.action.SEARCH -n com.airwatch.contentlocker/com.airwatch.contentlocker.ui.SearchActivity -e "query" "t"

Upon pressing enter on the above command the SearchActivity intent will fire, and by checking your target devices screen, you’ll see that a search was performed for the input “t”, seen in the screenshots below:

Static IV Used in Cryptographic Operations

The last issue that GDS discovered in the AirWatch SCL application is a fairly pervasive bad practice throughout the cryptography world. As stated in the title, a static IV is used in several of the cryptographic operations performed by the application, including the one responsible for decrypting managed files – awFileDecryptUsingKeyIV. The awFileDecryptUsingKeyIV function accepts several arguments, the path to the encrypted file, the path to the output file, the decryption key, and the IV. The IV in this case consists of the numbers 0 through 15, repeated twice, to create a 32-byte long IV, where there is a static or constant IV, the resulting effect on cryptographic operations is that, it can facilitate practical attacks when comparing multiple ciphertexts. What this means is, the more things you encrypt, the easier it is to guess the decryption key.

A code snippet has been provided below. Since the decompiled code was obfuscated, the filenames and variables below will need to be mapped to the original codebase in order to locate the vulnerable code.

 27:   private static final byte[] j = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
..snip..
 95:   public static void a(File paramFile1, File paramFile2, String paramString)
 96:    {
 97:         i.lock();
 98:         try
 99:    {
100:        e.awFileDecryptUsingKeyIV(c.getFileStreamPath("fipsOpenSSlRSA.enc").getAbsolutePath(), paramFile1.getAbsolutePath(), paramFile2.getAbsolutePath(), paramString.getBytes(), j);
101:        return;
102:   }
103:        finally
104:   {
105:        i.unlock();
106:   }
107:        throw localObject;
108:   }

 

As can be seen in the decompiled code snippet above, our encryption IV value is the 0 through 15 repeated twice in a byte array.

Monday
May092016

Local Request Forgery

This post explains how to abuse Internet Explorer’s Local Intranet Zone using malicious web pages served from the local disk. In corporate environments this could lead to impersonation of the victim on internal web applications and exfiltration of data outside the corporate network. 

Internet Explorer renders web pages in Security Zones; each zone comes with security settings that reflect the level of safety of that zone. 

When Internet Explorer opens a web page, the Urlmon DLL determines the zone from which the page was loaded. There are four predefined security zones:

  • Local intranet zone: all sites inside an organisation.

  • Trusted sites zone: all sites considered trusted.

  • Restricted sites zone: all sites considered not trusted. 

  • Internet zone: all Internet sites (not in the Trusted or Restricted zones)

In addition to the above four zones, the hidden My Computer zone includes all files served from network shares, the local hard disk and removable drives.

 

Cross-Site Request Forgery (CSRF) is an attack that abuses the inherent trust a web server places in the browser. Generally, any request within an authenticated session is assumed to be made, directly or indirectly, by the user. The attack described below can be considered a variation of Cross-Site Request Forgery where the attacker can also read the response. Instead of coercing the user to visit a malicious Internet website, the attacker sends an email with a malicious HTML page attached; when the victim opens this page with Internet Explorer it is loaded from the local file system and Internet Exploror (IE) renders it in the My Computer security zone. This zone allows scripts to issue requests to any website bypassing both the Same Origin Policy (SOP) and Cross-Origin Request Sharing (CORS).

 

Since IE 7, Protected Mode adds an integrity mechanism to restrict write access to securable objects (like processes, files, and registry keys) with higher integrity levels. If Protected Mode is disabled cookies are included when (malicious) scripts issue HTTP requests. The Local Intranet Zone is used in many corporate environments for internal web applications. Note that Protected Mode is disabled by default for the Local Intranet Zone on all current versions of Internet Explorer. Consequently, the malicious web page attached to an email described above can include JavaScript to target an internal application to which the victim is authenticated. This JavaScript will bypass SOP and CORS, because the page is rendered in the My Computer Zone, which enables the attacker to perform requests and read responses.

 

Demo Application

A simple demo web application was built as a Proof-of-Concept. The application is served from the Local Intranet Zone domain www.corporate.internal as shown in the screenshot below:

 

Monet HR is a web application used for HR purposes, it allows employees to view and manage their personal data such as personal and employment information, compensation, holidays, etc. 

 

The demo application exposes a single Servlet to authenticated users:

http://www.corporate.internal/monet/logged/userHandler

The servlet allows the user to perform two actions:

  • getCSRF (retrieves the CSRF token associated with user’s session)

  • getInfos (retrieves user’s information, it requires a CSRF token)

 

Pre-Requisites:

  1. The target web application is served from the Local Intranet Zone.

  2. Protected mode is turned OFF for Local Intranet Zone (default).

  3. The victim is authenticated on the target web application.

 

Attack PoC

  1. The victim receives an email with a web page attached.

  2. The victim opens the web page with Internet Explorer.

  3. The victim clicks on “Allow Blocked Content” button.

  4. (only for demo purposes) The victim clicks on “Steal Infos”, this triggers the malicious script.

 

The page served from the local file disk is rendered in the My Computer Zone, and can therefore bypass the Same Origin Policy and Cross Origin Resource Sharing. It can send requests to any application in the Local Intranet Zone, and cookies will be included in the request.

  1. When clicking on the button Steal Infos the JavaScript first issues an XHR to http://corporate.internal/monet/logged/userHandler to retrieve the CSRF token. This violates CORS (the script sends a cross-domain POST request with content type application/json but no preflight OPTIONS request is performed). It also violates SOP as the script can read the response coming back from a different origin.

  2. Having retrieved the CSRF token the JavaScript issues another request to the demo application, requesting the user’s information (a CSRF token is required in the JSON object). Again the JavaScript violates CORS and SOP, as it sends a POST request (with application/json content type) and it can read the user’s personal information back
  3. The malicious page then exfiltrates the stolen data to a third party website (lrfpoc.herokuapp.com) using a POST request with content type application/json (thus still in violation Cross-Origin Resource Sharing) and can read the response to that request as well (still violating SOP).

The above explanation can be referenced in the screenshot below where request and responses are printed in the DOM.

 The attacker can then view the exfiltrated data on a domain outside of the corporate network:

 

Mitigation:

The attack described above may be considered a variation of Cross-Site Request Forgery. However, server-side CRSF mitigations are not applicable. The demo application employed in the PoC required the submission of an anti-CSRF token, but since the malicious JavaScript can bypass SOP and CORS, it can read the CSRF token and use it in the request.

As this is a client-side issue, the only effective mitigation is to ensure that Internet Explorer enforces SOP and CORS by enabling Protected Mode for the Local Intranet Zone. Since Internet Explorer 7.0 on Windows Vista, this can be achieved through Group Policy Objects (GPO).

Source: http://gpsearch.azurewebsites.net/#911

 

Wednesday
May042016

Convert2FPR: Introducing ESLint and PMD support.

Convert2FPR:  introducing ESLint and PMD support.

Expanding on our previous blog post where we released a tool to convert Findbugs’ XML output into Fortify’s FPR format, we’ve now released two additional XSL transformations to provide ESLint and PMD XML output conversion.  

ESLint is an open source JavaScript lint application written using Node.js. ESLint allows all rules to be completely configurable, allowing developers to create their own rules. A number of security plugins for client-side JavaScript and Node.js have emerged recently.

PMD is a source code analyser that supports Java, JavaScript, PL/SQL, Apache Velocity, XML and XSL. GDS released security rules for PMD in a previous post.

We’ve also added a fast XSL transformation for Findbugs, which transforms only security related issues to the FPR format.

The example below demonstrates current the usage of the tool:

 

Findbugs
$ java -jar convert2FPR.jar findbugs report.xml

Fast-Findbugs (Security Issues only)
$ java -jar convert2FPR.jar findbugs-fast report.xml

ESLint
$ java -jar convert2FPR.jar eslint report.xml

PMD
$ java -jar convert2FPR.jar pmd report.xml

 

The first parameter represents the input format; the second parameter is the XML report we wish to transform. The output file is ./report.fpr .

The source code and compiled tool can be found in our Github Repository: 

https://github.com/GDSSecurity/Convert2FPR/

Tuesday
Mar082016

Introducing PS>Attack

I’ve been a huge PowerShell fan ever since I first discovered it as a Systems Administrator many years ago. It’s an incredibly easy to use, intuitive and powerful language and helped me efficiently address a lot of tasks that came across my plate. Unfortunately, the other Systems Administrators that I worked with were less keen to pick it up. Years of pointing and clicking had made them nervous about using a command line.

For different reasons, the Information Security community is in a similar state. PowerShell is an incredible platform for both offense and defense. There is a lot of cutting edge work being done by members of the PowerShell community, but the Information Security community at large is unaware of a lot of their contributions. This may stem from a lack of interest in Windows development or fear of having to learn yet another scripting language. No matter the reason, a lot of security professionals are missing out on some great work.

Enter PS>Attack

To help make using offensive PowerShell easier, I’ve created PS>Attack. PS>Attack is a custom made console that is designed to emulate PowerShell and enhance it. Built into PS>Attack are over 110 offensive PowerShell commands representing some of the greatest work going on in the offensive PowerShell community. This selection of tools runs the entire gamut of a security assessment including Reconnaissance, Privilege Escalation, Backdoors and Data Exfiltration. It also includes a custom command called “get-attack” which helps to serve as an attack search engine. It takes a word or phrase and returns a list of commands and their descriptions that match what you’re looking for.

Get-Attack returning a list of commands related to the word “Password”

All of this is bundled into a single executable that runs on anything from a fresh install of Windows 7 all the way up to a fully patched version of Windows 10. There’s no installer, just double click and start attacking.

Not Just for the Lab

In creating PS>Attack, I didn’t want to create a tool that was only used in a lab environment. I wanted to create something that was useful and could find its way into a penetration tester’s bag of tricks. To this end, PS>Attack is designed to evade antivirus and other hurdles. The various scripts and payloads that provide the commands are encrypted before being embedded into the executable. When PS>Attack is run, these scripts are decrypted directly into memory, so the plain text payloads never touch the hard drive. This helps avoid detection by most antivirus solutions.

PS>Attack is also written using native .NET functions and objects to process PowerShell code, it does not rely on “powershell.exe”. Because .NET is such an important part of Windows, this means that it’s very difficult for an organization to prevent PS>Attack from accessing the functionality it needs to run.

Getting PS>Attack

PS>Attack is available on our Github account. You can either compile the code yourself using Visual Studio or you can download pre-compiled binaries from the “releases” tab.

Acknowledgments

PS>Attack relies on a lot of tools to make itself effective and it’s important to make sure that the authors of those tools get the attention they deserve. Scripts from the following tools and frameworks are incorporated into PS>Attack. These tools represent some of the best work being done in offensive PowerShell today:

Monday
Jan252016

GDSCon 2016 - Wrapup

Thanks to all those who attended GDS’s inaugural GDSCon 2016 conference in London. We had a close to capacity crowd at 68 attendees!

To overview what was covered on the day:

  • Keynote: Letters from a broken fence line: Cyber lessons learned in Helmand province
  • Building security into the development lifecycle
  • A peek into what GDS Labs has been up to
  • Testing your defences (or are you testing what you think you are?)
  • Lessons from the Red Team trenches
  • Hybrid security assessments
  • Why using crypto is not Plug-and-Play
  • Fun with exploiting XML entity expansion

And not to be left out - thanks to the team running the lock picking village on the day.

The GDS events team will be going through all the great feedback to help make the next GDSCon event even better!