Code injection – a simple PHP virus carried in a JPEG image

As a developer and administrator for the webhosting company I saw many galleries and download scripts written in PHP. While the scripts were generally similar (used file_get_contents(), fopen(), readfile()), sometimes I’ve seen other, less traditional implementations.

A case of one of my company’s customers inspired me to write this article. Few months ago he reported to me with the problem of sending files via a PHP script. Some of his files were sent successfully but others did not and he could not get to the heart of the matter.

After a brief code inspection, it turned out that script written by him had some undesired, additional functionality. Because he’s been using include() clause to read an images, his script was vulnerable to the code injection!

How does it work?

Imagine a piece of badly-written PHP code responsible for reading the image from disk and sending it to the browser:

// [...]
if(preg_match('~^[a-z_\.0-9]+\.(jp[e]?g|png|gif)$~i', $filename)) {
// [...]

After successfull validation of the filename PHP script tried to display the file in a browser using the require() clause. In most cases, read operation was successful, but some files were corrupted and incomplete.

To explain the riddle you have to view the contents of the downloaded file in a text editor. If the PHP has been configured to display information about warnings and fatal errors (display_errors = on), you can notice a PHP parse error at the end of file contents.

Reading the PHP documentation quickly solves the problem.

When a file is included (or required), the file parsing drops out of PHP mode and into HTML mode at the beginning of the target file, and resumes again at the end. When PHP parses a file, it looks for opening and closing tags (<php and >), which tell PHP to start and stop interpreting the code between them.

It’s easy to guess that there’s a chance that included file contains opening tags as it’s valid contents. This creates a risk of a fatal error and remote code injection.

How to exploit this error?

The list of available attacks, of course, depends on the security level of the script. The easiest way is to send a PHP code in plain text file and save it under the extension of the target image/movie/file (eg virus.jpg).

(Un)fortunately many web applications validate not only the file extension but also an internal structure of the uploaded file (eg by checking the dimensions of an image file using getimagesize() function)

In that case you can not simply change the file extension of the virus (eg from virus.php to virus.jpg), because the PHP script will detect bad file format during the upload processs. Fortunately, most binary files may carry the PHP code without losing compatibility with the standard in which they were created.

A simple virus PHP step by step

While the described mechanism can be used in many different file formats, in the example here I will describe an attack on the poorly-protected PHP gallery.

To perform the code injection you just need a JPEG picture, EXIF tag editor and little knowledge of PHP.

I chosed the PHP logo as a virus carrier and this program as an EXIF editor.

To create a virus, open the image with EXIF editor:

Then add a new tag (by pressing the plus button in the green circle), the new editing window will pop up:

From the drop-down list choose DocumentName as a type of the tag and copy-paste the code below as the tag value:

<style>body{font-size: 0;} h1{font-size: 12px !important;}</style><h1><?php echo "<hr />THIS IMAGE COULD ERASE YOUR WWW ACCOUNT, it shows you the PHP info instead...<hr />"; phpinfo(); __halt_compiler(); ?></h1>

Click “Commit change (s)” to save the file:

Here is the result of my work, a JPG file with a hidden PHP code (you can download and try it yourself):

From now on, the PHP logo carries a PHP code which is invisible to most picture viewers. You can quickly test the virus by uploading it to a badly-written gallery and displaying it in a browser:


Most PHP scripts on the Internet use the binary-safe functions to read the files. The above example shows, however, the importance of validating input data, and that existing security mechanisms (such as built-in PHP getimagesize() function) can be easily deceived by an appropriately crafted files.

Ofcourse an image created in this article is not a real virus (because it’s unable to propagate itself or infect other files), but it may serve as a precursor to such a program. Also, this mechanism can be used as an unusual obfuscator, hiding the PHP code in binary files.

12 Responses to “Code injection – a simple PHP virus carried in a JPEG image”

  1. pradeep says:

    very finely described tute. Thanks a lot sir. It will really help me.

  2. Great! didn’t know that images can contains php script in it.

  3. Artur Graniszewski says:

    Well, JPEG files can contain not only PHP, but JavaScript also. What’s more it could be easier to inject malicious JS code into some of the existing galleries because many of them lack the necessary output sanitization, when displaying EXIF data to the user.

  4. Well, anyone who uses that code to check whether an image is really an image deserves it. getimagesize(), anyone?

    Good point about the EXIF data, Artur.

  5. edward latastar says:

    I’m a security noob. will php/js code within jpeg files only execute when opened through a webbrowser suporting javascript/php. or will it also work it’s wonders when opened by a image-viewer?

  6. Artur Graniszewski says:

    @edward, this solution works only on a PHP-enabled servers in case of PHP code injection. Also the Javascript code injection cannot be executed from within a desktop application, unless it is using an embedded webbrowser as a viewer (and it would be a rather strange case IMHO). There are however other techniques to break a desktop application and the most popular is a buffer overflow attack. You can read about this form of attack on different security blogs or browse a CVE list to check existing vulnerabilities.

  7. Andy Evans says:

    This would be an issue if you used include or require, but would it be with readFile or fopen fread? Also whats a good way to clean for bad exif data? I know you could just copy the image and wipe it, but what if your want to keep it, and just make sure it does not have any tags or scrips?
    Thanks for this great article! Very insightful!

  8. Artur Graniszewski says:

    readfile(), fopen() and file_get_contents() are binary safe functions. In case of these, you have to only watch for XSS attacks on your site. PHP wont be parsed, but HTML and JavaScript can in certain cases, for example when displaying EXIF data of tainted images (author name, camera details, GPS coordinates, etc).

  9. MyTest says:

    How to Safeguard from such attack or not

  10. anon says:

    thanx for th3 nic3 tutori4ls

  11. djsefu says:

    this is not working

  12. Chotu says:

    this is not working

Leave a Reply