You may have read recently about a newly-discovered attack that involves injecting code into your browser using poisoned image files.
Code-carrying image files are usually a serious security concern, especially if they involve deliberately malformed content that was criminally crafted to trip up your browser, or PDF reader, RTF viewer, video player, and so forth.
A well-known example from late in 2013 was a TIFF handling vulnerability in Microsoft Windows.
This TIFF exploit was used by criminals, who lured you to open an innocent-looking document file containing a booby-trapped TIFF image; crashed Microsoft Office; grabbed control of your CPU; and tricked your computer into running executable code without any official popups or warnings.
An attack of that sort is known as a remote code execution exploit, or RCE.
RCEs usually rely not only on remotely delivered content that is deliberately and criminally unusual, but also on software behaviour that isn’t supposed to happen.
Fortunately, this latest poisoned code injection isn’t anywhere near as dangerous as the TIFF hole: it doesn’t exploit a vulnerability that allows it to take over without warning.
But it does tell an interesting, even amusing, story of subterfuge and guile, so here you are.
The start of the attack
Indeed, for the first 8981 lines, the file is jquery.js – the official, unmodified, uncompressed file from version 1.6.2.
(As you can see from the datestamp, the crooks are often many versions and several years behind, too.)
The malicious addition comes right at the end.
You’ll notice a pair of functions that stand out rather obviously, at least to a security researcher:
String obfuscation is especially handy for disguising the presence of suspicious URLs in the malicious code.
In the “poisoned image” approach we’re studying here, however, the string isn’t encoded as another string – it’s encoded into a series of coloured pixels!
Here’s how the crooks did it.
The initial image
The image that is fetched by the loadFile() function above is 17×17 pixels.
Magnified 20 times, it looks like this:
Looking at the image doesn’t give much away.
If we open the image file in a hex editor, there’s still nothing obvious to see:
PNG files are stored as a series of data sections, the most important of which is IDAT, the actual image data.
The raw data (highlighted in blue above) in the IDAT section is compressed, disguising still further any patterns that might otherwise be obvious.
But if we convert the image to a raw RGB file, in which each pixel is represented by three bytes denoting the amount of red, green and blue it contains, things start to get interesting:
Each pixel has the same value for red, green and blue, as we’d expect for a greyscale image.
And the majority of those greyscale values map into the range in the ASCII chart reserved for digits and letters:
We can also see the stand-out values 0x20 (space, annotated in pink) and 0x0D-followed-by-0x0A (the carriage return-line feed combination used on Windows to denote the end of a line of text, annotated in green).
The hidden source code
The darker regions in the image correspond to the lower values in the ASCII chart, namely the digits and punctuation marks.
It relies on the browser to render the image into an HTML5 canvas, which transparently (if you will pardon the pun) deals with decoding and decompressing the raw image file.
The source code is then sucked back in, pixel by pixel, from the rendered version of the image.
Indeed, the malware could switch to a different file format, such as JPEG or GIF, without any additional code required in the bogus jquery.js file.
The invisible components
As you can see from the code listing above, even a keen-eyed user won’t spot the 17×17 pixel greyscale-image-that-isn’t, because it is rendered 10,000 pixels off to the left of the window:
oImg.style.left = "-10000px";
The code that’s extracted from the invisible image and submitted to eval() creates a similarly out-of-shot IFRAME:
elm.style.left = '-1000px'; elm.style.top = '-1000px';
This script, in turn, produces yet another IFRAME, once again positioned invisibly:
document.write("<iframe style='position:absolute; top: -200px;' src=...");
At this point, at least in our experiments, things ended in an amusingly ironic anticlimax.
The final webpage we reached, after all this jiggery-pokery, was this:
That’s an empty page, so even if it were visible, our colourful journey would end in nothing:
A final warning
Of course, the cybercriminals could quickly and easily vary the web trajectory followed by the image-rendering trick in the bogus jquery.js file.
They could change the image itself or the location and contents of any of the IFRAMEs that are subsequently fetched, so we can’t promise that things will end with the same sort of wry smile in your case…
Note. Sophos products detect and block the files in the attack described above as Troj/JSRedir-NG.