The pictures we upload online are something we tend to think of as self-expression, but these very images can carry code to steal our passwords and data. Profile pictures, avatars, and image galleries are used all over the internet. While all images carry digital picture data — and many also carry metadata regarding camera or photo edits — it's far less expected that an image might actually be hiding malicious code.
Files are generally structured in a few different parts. Image files, for instance, generally begin with some declaration of the type of image file data present. This is usually something like a "Start of Image" marker, a sequence or number which indicates what is going to follow it. GIF files begin with GIF87a or GIF89a when viewed as ISO 8859-1 encoding, or "47 49 46 38 37 61" in hexadecimal.
These signatures are followed by data which corresponds to the arrangement and coloring of pixels in the image. This data, when enclosed in an image file, is enough to create a usable bitmap image. However, in addition to this visible image data, following the end of the image data, metadata such as EXIF can be inserted following an application marker segments. After these points, the image data has been both opened and closed with defined indicators, and anything after this data will not be processed as an image.
Metadata is generally only visible to the user when it's specifically parsed, and in the same way, hidden code will only be visible to a program which is looking for code to run. While this data often contains camera information, location data, or similar information related to the photograph itself, it could also be stuffed with another file, or in this case, executable code.
Despite the hidden content included in an image file, it still behaves as a standard image as the opening and closing components of the image content are sufficient for image-viewing programs to interpret and effectively display the image.
In the same way, when a website is told to look for a certain type of script, it will at least attempt to run, or look for something it can use for the action it is instructed to do. If this script is an image file rather than a text file, the website will be able to run the script so long as it can find the opening and closing elements of the code.
Websites such as forums, hosting sites, or other sites with user-generated content often allow for the uploading of images and posting of text or media content.
In certain cases, HTML script tags will be permitted, perhaps a widget available for users to add to their posts or pages. A script tag may be able to be inserted where it should not have been due to a lack of form verification, often by using an escape tag like the HTML textarea property... But even if not, you'll be able to host your own web page that sources scripts from other pages, and if those scripts try to access cookies from the domain they're hosted on, they'll be granted access.
Let's begin by cloning the git repository for the project. The commands in these examples are entered in a Kali Linux terminal environment.
git clone https://github.com/jklmnn/imagejs
After cloning the repository, we move into the directory with the following command.
Finally, to compile the program, we simply run:
We can save this text as the filename of our choice, or directly send it to script.js with the following command line string.
echo "window.alert("Null Byte");" > script.js
Once we have both the code we would like to embed and the image we would like to add the code to, we can embed them using the following parameters. The script in this example is titled "script.js" and the image "image.jpg" — both of which are in the same directory as the imagejs program, as we can confirm by running ls.
The syntax begins with running the program, imagejs. The first argument, in this case gif, indicates the file type. The second argument refers to the script we are using, and the final argument following the -i flag is the image we wish to modify.
./imagejs gif script.js -i image.gif
The name of the output file. in this case. will be "script.js.gif." However, we can rename it to whatever we choose.
To test the functionality of the script image, let's create an HTML test page with opening and body tags.
We can save this file as "script.html" or the filename of our choice. When we open it in a browser, it should look like the following image.
The <img> tag has been included in order to demonstrate that the GIF image is still entirely functional as an image, but it could be omitted and the script would still run.
Serving this from a file works as file systems don't specify file mime types. Most modern web servers will specify a mime type for the files it serves based on the file extension. If this is the case and the web server specifies an image mime type (such as image/gif), modern browsers will not attempt to execute the script as image mime types are not executable.
The following command will attempt to dump write cookies to the served up web-page. These cookies may be able to be used to impersonate users by stealing their authentication tokens. Now, obviously simply writing them to their browser isn't going to get them to you (you'll have to write a script to quietly post them to your own server), but this will serve as a simple proof of concept:
document.write('cookie: ' + document.cookie)
Finally, in order to deploy the attack, we need to find somewhere to upload our image and either another field that's vulnerable to XSS attacks where we are able to escape input verification and use a <script> tag, or (more easily) load the image (as a script) from our own phishing webpage. In the example below, we uploaded our avatar, 1337.gif, and following a </textarea> exit tag, we enclose it in script tags. After this, anyone who views this profile will have their cookies dumped to their browser window. Replace the script above with one that silently posts the values of document.cookie to a server of your choosing, and you've got your self a silent credential thief.