BOOK THIS SPACE FOR AD
ARTICLE ADA bit of an odd title, eh? Either way, this article will be about a very peculiar bug that I discovered somewhat recently, where it was possible to overwrite user’s/victim’s profile images. But, there’s also a twist to it.
Initial recon:
When a website has any kind of upload function, there are a few things to immediately take a look at, it’s not even hacking really, it’s using the upload function of the website as it is intended.
The first thing that I tend to look for is whether I can select any file to upload (if I can, I just make a note of that while still uploading the expected type of file which is usually of image type)
Upon uploading the expected file type, usually an image of some kind, the next thing to look for is where is that image being stored and the naming convention. If the image is stored on aws then I note that and get XXE payloads ready, if it’s the same domain, then I note that, but if it’s some third party host then I leave it be (this doesn’t take into consideration whether the pulled name inside img src can be xss payload)
In this case, the upload location was the domain, which meant it was time to try various tricks in order to see if I can get any other file type uploaded, or whether I can trick in any way for the uploaded file to be executed as anything other than a regular image. That failed. But, the naming convention and the upload request parameters and their values suggested idor potential.
How does it work?
In this case, it was soon obvious that each user would get their own folder assigned to them, and their folder is where all their uploaded images would get stored to. In addition, all the uploaded images get renamed to userid_randomnumber_(small-medium-or-large).png
Upon further inspection, the randomnumber turned out to be not that random, but a unix epoch timestamp. For example: 1598044883 is same as Friday, August 21, 2020 9:21:23 PM GMT
The obvious approach:
I went for the straightforward way, I simply changed the victim’s userid to mine, and attempted to upload my image. And, it worked. It turned out that it did upload my image to the victim’s folder. But, that’s kinda boring. What if I would overwrite victim’s existing image(s)?
Another weird one:
In order to understand how to break something, it’s a good idea to know the way it works. After some trial and error, it turned out that the way to overwrite existing image sort of worked.
The timestamp was the key. In order to overwrite the victim’s image, I needed the timestamp of that image, which was easy to get to (view source, and noting the img src value).
Having the timestamp, the userid, and the image in mind, I was all set. And, it worked. Sort of.
The sort of of it all:
As I mentioned earlier, there are three sizes that the uploaded image gets saved as. Of those three sizes, the one that was easy to spot during messing around with overwriting — the small one. Why? Because it was displayed on the profile page of the user/victim. Refreshing their page (obviously in a different browser) upon issuing the upload request, I could immediately tell what happened.
I tried again, but this time readying to write a report, which meant I went with a story mode: I pretended as though I am a regular user. I created a profile, uploaded my images, looked at them (this was the key part, something I haven’t done during the previous test) and refreshed the page couple of times. Confirmed that everything was looking good.
And then, as the attacker, I did the earlier mentioned attack. All while pretty much thinking about the content of the report, what screenshots to take, etc., and then as a regular user/victim, I refreshed the page with my finger hovering above Print Screen key, only for that same finger instead of pressing that key, having to move toward my head, to do a lot of head scratching. WTH?
It worked earlier, what changed?
I repeated the steps, but omitting the ones that I found irrelevant (clicking around as a regular user upon uploading the image, etc.), and it worked. WTH?
Redo:
When an attack works, and then it doesn’t, the main question is: what changed? That is what I kept going through as I was trying to figure out why it worked the first time, failed the second, and worked again on the third go. What had changed?
I followed the steps from the failed attempt, and compared them to the slightly less steps from the following successful attempt (because the first attempt had far fewer steps). And, it turned out, and I confirmed that with further testing, that if the user’s/victim’s images that the attacker wanted to overwrite had been visited prior to the attack, the attack wouldn’t work. At all. Visiting a link to the image in question would basically make it invulnerable to this attack. Which meant, even a bot crawling about and getting to the image would make that image invulnerable to overwrite. Go figure.
How to do it regardless:
It’s not impossible, but it is highly improbable. It requires conditions that are not easy to come by in a natural way. The idea is to trick the user/victim to be doing the upload at the same time that you are performing the attack. In order to do that, the timestamp parameter would have to be issued across multiple values. The reason for that is because the epoch timestamp includes minutes and seconds. Meaning, you can’t know the 100% exact time for the user. Therefore, the attack would have to involve burp intruder, or similar, in order to be able to set timestamp across multiple values. And, the really hard part, the attack would have to hit the 100% same time as the user/victim.
It shows that when you find the upload request with unexpected parameters, while it opens up the attack surface, it can also complicate things. But, it also shows, complex systems have bugs, albeit complex ones, but still. Something to keep in mind on your future journeys. And, maybe even revisit some of the past ones, you might have missed something :)