Lets try to embed this image as a script.
While opening it in a browser , browser throws an error indicating that JS contains illegal characters.
Now , an alert box pops up in the browser as this is a valid JS.
But it’s not a valid image.
Before diving into the main parts, lets dissect the JPEG file format of the above image of Aaron Swartz.
Below is a screenshot of the image when opened through a command line app called hexdump .
The first two bytes ,FF D8 , represent the start of an image (SOI) ,the next two bytes , FF E0 , represent that the coming two bytes , 00 10, represent the length of a JPEG header. 00 10 is a hex equivalent of decimal number 16, which means that the length of JPEG header is 16 bytes counting themselves.
FF DB in the screenshot represents the start of a quantization table , the explanation of which is beyond the scope of this write-up . We will hide our JS, alert(1), in between FF E0 and FF DB.
We are using hexeditor to inject our JS code in between FF E0 and FF DB. Note : There can be multiple FF DB ; multiple quantization tables . But we have to inject our code in between FF E0 and first FF DB.
When we blindly try to inject the code using (hexeditor -b aaron.jpg), it throws an error in browsers console as it is still not a valid JS.
So , let’s comment out the garbage using /* and */ . Everything written in between /* */ in js is happily ignored by the JS engine.
We have used 2F 2A which is a hex representation of /* to start the comment to ignore the garbage , but 2F 2A in decimal equals to 12074 bytes .However , we have 16 bytes in between 2F 2A and FF DB inclusive.
The first four bytes FF D8 FF E0 make a valid non-ASCII variable name and we have injected /* as a start of comment . Now , we have to close out the comment using */ ,use an equals to operator “ = “ and use our payload alert(1); and again start another comment /* .
Since we have 16 bytes in between 2F 2A and FF DB inclusive ,we have to pad out remaining with null bytes i.e. 12074- 16- 14 i.e 12044.
Let’s write a simple JS which injects 12044 number of null bytes , our payload and saves the final output as an image.
So , this script reads the JPEG file , converts the buffer into hex , inserts our payload in between 2F 2A and FF DB , changes the final hex into buffer , and writes the buffer into a file named newaaron.jpg .
Now , let’s open hexeditor to insert the end of comment before the end of image . The last bytes of JPEG file is FF D9. We will insert 2A 2F which is a hex equivalent of */ before FF D9 using hexeditor .
Now , let’s open it in a browser.
Lets view the source.
We can see the script through a debugger tab.
As you can see, we have ÿØÿà/*JFIF ……. */ = alert(1);/* …….. /*
This made a valid JPEG image as well as a valid script .
Note : As of Firefox 51 , this is fixed but you can verify it in your browser.
You can download the files and verify it manually .
Suggestions and criticisms are appreciated.
Any questions ? Contact me at facebook.com/MRcodedbrain