Interactive exploit kit redirection technique

The usual pattern we see when dealing with exploit kits starts with a legitimate website that gets compromised and used to automatically redirect its visitors to the actual malicious content. Techniques such as iFrame injection and HTTP redirections are frequently observed.

This week though, we found an interesting variation while doing research on some exploit kit traffic. We noticed that the compromised website contained code that actually interacts with the user by presenting a fake message about some script slowing down the browser. 


The code responsible for this interaction is an injected HTML form that is shown only when the visiting browser is Internet Explorer. We can also see that some data is sent along with the POST request, we will come back to this in a moment.


Of course, clicking on either Cancel or OK triggers the same POST request to an intermediate page, which in turn redirects the visitor to the Angler exploit kit by returning a small snippet of HTML and Javascript code:

Intermediate page returning the code performing the redirect

Intermediate page returning the code performing the redirect

The complete exploitation chain

The complete exploitation chain

Now let’s go back to the data sent along with the POST request. We can see that it is encoded with Base64, but decoding it yields random-looking data.

>>> ua_base64 = 


>>> base64.b64decode(ua_base64)


We can guess from the parameter name ‘ua’ that it contains the User-Agent string of the browser, which we know in our test was :

Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET4.0C; .NET4.0E; BOIE8;ENUSMSCOM)”.  

What if the parameters were all XOR’ed with the same keystream? Let’s use this plaintext knowledge to obtain the keystream by XOR’ing the base64-decoded encrypted User-Agent string with our known plaintext (in lower case). If our theory is correct, using the keystream obtained this way to XOR the value of the ‘furl ‘ parameter  would yield the URL of the Angler EK landing page…

import base64

def xor(message, key):

    decrypted = “”

    for i in range(0, len(message)):

        decrypted += chr(ord(message[i]) ^ ord(key[i%len(key)]))


ua = “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET4.0C; .NET4.0E; BOIE8;ENUSMSCOM)”

ua_plaintext = ua.lower()

ua_base64 = “tlP7Vt89hmr1vjdAW8YqmDT/sGFiyxROsPBX45R6HxinEeZC+YGrgEA0mmA3NDEJUYzgWm29EKShU2QPqxBXzVNMJvpfJN3QcVGGehPCNNXOlxo0JE94z0RTBgCq0VubolrWHmAexV14+cqx6qILC6z1EZDl4JFYd32wrMZrhNinl47lzpnvXwPluNsmh0CA”

furl_base64 = “s0j1T4l+yCai5DANXd0gmz38sX5pwRVb/vhQpcU9Qlj8G6tQ5Nc=”

keystream = xor(base64.b64decode(ua_base64), ua_plaintext)

print “Decrypted furl:”

print(xor(base64.b64decode(furl_base64), keystream))

$ python

Decrypted furl:



Typically the visitors are automatically redirected to the exploit kit when they visit a compromised website, so why bother with displaying a message first? It might be to prevent automated systems (malware analysis sandboxes, search-engine bots etc.) from reaching the exploit kit, making it harder for researchers to track and investigate such a threat.

The malware that was being distributed at the time we performed our research was Win32/PSW.Papras.CX  (SHA1: 7484063282050af9117605a49770ea761eb4549d).

Author Sébastien Duquette, ESET

  • Jammer

    Great analysis ladies and gents. I really enjoy some of the articles on the site and to be honest make’s me feel a little safer knowing me and others all use ESET. Nothing is bullet proof but it helps to be behind a bunker to take some of the brunt first.

Follow us

Copyright © 2017 ESET, All Rights Reserved.