<p>Short answer (for now): this & similar attacks are being addressed in 2.1.1 (not yet complete) to address CVE-2013-5960. Release 2.1.0 *only* addressed CVE-2013-5679.</p>
<p>-kevin<br>
Sent from my Droid; please excuse typos.</p>
<div class="gmail_quote">On Dec 2, 2013 10:56 AM, "Renaud Dubourguais" <<a href="mailto:renaud.dubourguais@synacktiv.com">renaud.dubourguais@synacktiv.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi guys,<br>
<br>
After some investigations, we found a new way to bypass the HMAC<br>
validation in the ESAPI Symmetric Encryption.<br>
<br>
Problem description:<br>
====================<br>
<br>
The security fix for the CVE-2013-5679 vulnerability ("MAC Bypass in<br>
ESAPI Symmetric Encryption") does not prevent a malicious user to bypass<br>
the HMAC validation on a serialized cipher text.<br>
<br>
A serialized cipher text generated by ESAPI has the following structure:<br>
<br>
<kdfInfo/kdfPrf:int> : identification of the key derivation function<br>
<timestamp:long> : time when the cipher text is generated<br>
<cipherlen:short> : size of the "cipher" string<br>
<cipher:str> : algorithm for encryption and decryption<br>
<keysize:short> : size of the HMAC validation key (in bits)<br>
<blocksize:short> : size of the encryption blocks<br>
<ivlen:short> : size of the IV (in bytes)<br>
<iv:str> : Initialisation Vector<br>
<ciphertextlen:int> : size of the cipher text in bytes<br>
<ciphertext:str> : encrypted value<br>
<maclen:short> : size of the HMAC in bytes<br>
<mac:str> : HMAC of the IV and the cipher text<br>
<br>
The "keysize" field, under the control of a malicious user, is used to<br>
compute the HMAC encryption key. The ESAPI library checks for a minimal<br>
key size of 56 bytes using an assertion. However, if the application is<br>
not started with the "-ea" java option (which is usually not the case in<br>
production environments), assertions are turned off. By setting the<br>
"keysize" field in a serialized CipherText to a value between 1 and 8<br>
(bits), ESAPI will compute the HMAC using a 1 byte key, which can be<br>
trivially brute-forced to produce a valid HMAC.<br>
<br>
>From the code:<br>
==============<br>
<br>
If "keysize" is set to [1-8], the CryptoHelper.computeDerivedKey()<br>
method used to compute the HMAC encryption key will return an "authKey"<br>
of 1 byte. The following extract from the file<br>
org/owasp/esapi/crypto/CryptoHelper.java shows were the<br>
computeDerivedKey() is called:<br>
<br>
public static boolean isCipherTextMACvalid(SecretKey sk, CipherText ct)<br>
{<br>
   if ( CryptoHelper.isMACRequired( ct ) ) {<br>
            try {<br>
                SecretKey authKey = CryptoHelper.computeDerivedKey(sk,<br>
ct.getKeySize(), "authenticity");<br>
                // VULN: If ct.getKeySize() is 1, authKey.length will be<br>
1 byte<br>
                boolean validMAC = ct.validateMAC( authKey );<br>
                return validMAC;<br>
            } catch (Exception ex) {<br>
                logger.warning(Logger.SECURITY_FAILURE, "Unable to<br>
validate MAC for ciphertext " + ct, ex);<br>
                return false;<br>
            }<br>
        }<br>
        return true;<br>
    }<br>
<br>
The computeDerivedKey() method is found in the file<br>
org/owasp/esapi/crypto/KeyDerivationFunction.java:<br>
<br>
public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int<br>
keySize, String purpose)<br>
                        throws NoSuchAlgorithmException,<br>
InvalidKeyException, EncryptionException<br>
     {<br>
[...]<br>
                assert keySize >= 56 : "Key has size of " + keySize + ",<br>
which is less than minimum of 56-bits.";<br>
                // VULN: assert not triggered in production<br>
[...]<br>
                keySize = calcKeySize( keySize ); // if keySize is 1,<br>
calcKeySize() returns 8 bits<br>
[...]<br>
                do {<br>
                        mac.update( ByteConversionUtil.fromInt( ctr++ ) );<br>
                        mac.update(label);<br>
                        mac.update((byte) '\0');<br>
                        mac.update(context);<br>
                        tmpKey = mac.doFinal(ByteConversionUtil.fromInt(<br>
keySize ) );<br>
<br>
                        if ( tmpKey.length >= keySize ) {<br>
                                len = keySize;<br>
                        } else {<br>
                                len = Math.min(tmpKey.length, keySize -<br>
totalCopied);<br>
                        }<br>
                        System.arraycopy(tmpKey, 0, derivedKey, destPos,<br>
len);<br>
                        label = tmpKey;<br>
                        totalCopied += tmpKey.length;<br>
                        destPos += len;<br>
                } while( totalCopied < keySize );<br>
[...]<br>
                return tmpkey; // VULN: tmpkey will only contains 1 byte<br>
     }<br>
<br>
If CryptoHelper.computeDerivedKey() returns an "authKey" containing only<br>
1 byte, ct.validateMac(authKey) will compute a HMAC using a 1-byte key.<br>
It will then compare the calculated HMAC with the HMAC in the CipherText<br>
sent by the attacker. The validateMAC() method is in the file<br>
org/owasp/esapi/crypto/CipherText.java :<br>
<br>
public boolean validateMAC(SecretKey authKey) {<br>
            boolean requiresMAC =<br>
ESAPI.securityConfiguration().useMACforCipherText();<br>
<br>
            if (  requiresMAC && macComputed() ) {<br>
                byte[] mac = computeMAC(authKey); // VULN:<br>
authKey.length is 1 byte<br>
                assert mac.length == separate_mac_.length : "MACs are of<br>
different lengths. Should both be the same.";<br>
                return CryptoHelper.arrayCompare(mac, separate_mac_);<br>
[...]<br>
<br>
It means that a malicious user can set the "keysize" field to a value<br>
between 1 and 8 in the CipherText structure, recompute all possible HMAC<br>
in the CipherText using a 1-byte key, until CipherText.computeMAC(key)<br>
matches the forged HMAC. Brute forcing 1 byte takes only 256 iterations<br>
in the worst case. When the right value is found,<br>
CipherText.validateMAC(key) will return "true" and the HMAC check will<br>
be bypassed.<br>
<br>
Impacts:<br>
========<br>
<br>
Once the MAC is bypassed, the attacker will be in a good position to<br>
attack the encryption layer, by using for example padding oracle<br>
attacks. Other cryptographic attacks are also possible depending on the<br>
encryption algorithm and mode used.<br>
<br>
Affected versions:<br>
==================<br>
<br>
2.1.0<br>
2.1.1-SNAPSHOT (from svn)<br>
<br>
Proof of concept:<br>
=================<br>
<br>
A sample application using the ESAPI library and a proof of concept of<br>
the attack can be found here:<br>
<a href="http://www.synacktiv.fr/ressources/owasp_esapi_hmac_bypass_poc.tgz" target="_blank">http://www.synacktiv.fr/ressources/owasp_esapi_hmac_bypass_poc.tgz</a>.<br>
<br>
To decrypt a token, use:<br>
$ java EsapiVictim d <token><br>
<br>
To generate a token, use:<br>
$ java EsapiVictim g key=value<br>
<br>
To use the exploit trying to bypass the HMAC validation of<br>
EsapiVictim.java, the java classpath should be adjusted following your<br>
system, then do:<br>
<br>
$ python esapi_brute.py <token><br>
<br>
If esapi_brute.py bypasses the MAC validation, a padding exception will<br>
be thrown by the EsapiVictim application:<br>
"Caused by: javax.crypto.BadPaddingException: Given final block not<br>
properly padded"<br>
<br>
Remediation:<br>
===========<br>
<br>
Enforce a minimal size for the HMAC key at runtime (and not using<br>
"assert" which is usually turned off). Other vulnerabilities may lurk in<br>
the dark, as the serialized CipherText exposes sensitive parameters used<br>
for the decryption and HMAC validation. Do we really need the "keysize"<br>
field in the CipherText structure?<br>
<br>
--<br>
Renaud Dubourguais<br>
Security Expert - Synacktiv<br>
<br>
_______________________________________________<br>
Esapi-dev mailing list<br>
<a href="mailto:Esapi-dev@lists.owasp.org">Esapi-dev@lists.owasp.org</a><br>
<a href="https://lists.owasp.org/mailman/listinfo/esapi-dev" target="_blank">https://lists.owasp.org/mailman/listinfo/esapi-dev</a><br>
</blockquote></div>