I had a client contact me today because a website I developed (that deals with sensitive information) wasn't loading correctly on one computer on Chrome. After poking around for a while it appears to be caused by the underlying source code being manipulated in Chrome. The code injection (a javascript snippet) appears BEFORE any DOM is parsed, and is actually happening to all sites she visits that have a <title>
tag (the code is inserted before any <title>
text in the code... it isn't parsing the DOM because the insertions are happening even if the <title>
string is inside a pre
tag or textarea
. Given that you can see the injection directly in view-source I'm fairly certain this isn't being injected by a plugin/extension (which I don't believe can modify source code before the DOM is registered). And the fact that it is happening on https sites means I assume it's something installed on the client's computer that's doing the code manipulation.
The injected code (reformatted for readability) is:
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function shuffle(array) {
var currentIndex = array.length,
temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
var __toUserAgent = window.navigator.userAgent;
Object.defineProperty(window.navigator, "userAgent", {
get: function () {
return __toUserAgent + '/b3S2rCM5-8';
}
});
var testPlugins = [];
for (var s = 0; s < window.navigator.plugins.length; s++) {
var plg = {
'name': window.navigator.plugins[s].name,
'description': window.navigator.plugins[s].description,
'filename': window.navigator.plugins[s].filename,
};
plg[0] = {
'type': window.navigator.plugins[s][0].type,
'suffixes': window.navigator.plugins[s][0].suffixes,
'description': window.navigator.plugins[s][0].description
};
testPlugins.push(plg);
}
if ({
'name': 'VT AudioPlayback',
'description': 'VT audio playback',
'filename': 'vtaudioplayback.dll',
'0': {
'type': 'application/vt-audio',
'suffixes': '',
'description': ''
}
}, {
'name': 'ChanWebPlugin',
'description': 'Chanw checking plugin',
'filename': 'chanwebplugin.dll',
'0': {
'type': 'application/chan-web',
'suffixes': '',
'description': ''
}
}) testPlugins.push({
'name': 'VT AudioPlayback',
'description': 'VT audio playback',
'filename': 'vtaudioplayback.dll',
'0': {
'type': 'application/vt-audio',
'suffixes': '',
'description': ''
}
}, {
'name': 'ChanWebPlugin',
'description': 'Chanw checking plugin',
'filename': 'chanwebplugin.dll',
'0': {
'type': 'application/chan-web',
'suffixes': '',
'description': ''
}
});
testPlugins = shuffle(testPlugins);
Object.defineProperty(window.navigator, "plugins", {
get: function () {
return testPlugins;
},
enumerable: true,
configurable: true
});
Basically, it seems to be editing the browser userAgent string slightly and then randomizing an array of plugin details, and then attempting to set the registered plugins on the browser.
Two questions:
I don't see how this would actually do any damage, but are there specific security concerns about the JS code being rendered here (we checked her bank's website and the code was being injected there as well)?
How is it possible for the underlying source to be changed? I understand JS-powered code injection attacks, but in this case the actual original source appears to have been edited. So html served via https is being changed on the fly (so it looks like the remote server actually sent the code). I was wondering if her Antivirus (AVG) might have been the culprit, but disabling protected temporarily didn't seem to fix it.
If AVG didn't cause or prevent the issue, any thoughts on how to prevent this?