Winning the Popularity Contest

Recently I took a look at a new social media/dating website and noticed an interesting feature – the site had a sort of “popularity contest” of sorts which runs every 30 days. Users vote on other users, scoring them out of 10 and whoever gets the most points wins their place at the top of the highscore table as officially the “Hottest Member”. So naturally I wanted to win!

Whilst what I found wasn’t a vulnerability as such, it made me laugh and had the desired effect – so I figured I’d write it up anyway. To protect the innocent I’m “mocked up” the screenshots in this article with selfies gratuitously submitted by my lovely Twitter followers. They’re not members of the actual site, they just wanted to help me out with my write up! Thanks to everyone who submitted selfies! 🙂

I wanted to win. I considered ways in which somebody could pull an attack off that would allow them to artificially win and two obvious possibilities could be:

  • To register a significant number of accounts and have all of those vote directly for my main profile
  • Compromise real member profiles through attacks such as brute-force or other account takeover issues and utilise those accounts to vote directly for my main profile.

There’s a couple of issues with this though, the first method is likely to be easy to detect and my fake accounts will likely just get banned, nullifying my points. For the second method, could I really compromise a high enough number of accounts to achieve my goal?

There are other ways of course, insecure direct object reference in the voting system, insecure password reset functionality on user accounts, authentication bypass on the login form….

However, playing around with the site I noticed a feature of the site that could be abused to achieve my aim. First though, an introduction to how the site works: Here’s a mocked up screenshot of the dashboard:

So the main dashboard interface has four main sections. The menu on the left: where you can message users, see who you’ve flagged as a favourite and where you can see who’s been checking you out. The centre: is the current user you’re rating. The right: shows whoever is considered the most attractive member of the site, this is where we’re aiming to be. It also shows a  random user and if you click that user you can rate them and you’ll also get another random user.

So the thing that I noticed, is that a large majority of users keep a constant eye on their “My Profile Views” page, which shows them who’s been checking them out. It turns out if you pop up on a users profile views a couple of times or more, they’ll naturally check you out – and of course vote on you.

However the winner of the popularity contest isn’t who gets the most people to vote for them, whoever gets the most 10s, or even who scores the highest proportion of 10s. It’s simply whoever scores the most points. So you can win with nothing but 1s as long as you get a lot of 1s.

So we could abuse this to gain significant traffic to the target profile, we just have to visit every user profile periodically over the 30 day period – and when those users see us “peeking” at us, there’s a change they’ll take a look at us – and might vote. So we can easily hook up a simple python web scraper  to repeatedly pull the profile pages of regular users and given enough time, like the 30 days the competition runs for, we can slowly “steal” votes.

Well, I say slowly…

But first – let me introduce you to the “Top Members” page, it looks something a little like this:

The interesting thing here is that it exposes what scores the last batch of users got (incidentally, taking a look through it seemed that first place was far ahead places 2-5 and those were in turn far ahead 6-20). So we know what our target to gain over the 30 days is. So we’re looking for something like 5450 points, which over 30 days is 182 points a day, which is only 18.2 votes of 10 – that doesn’t feel unachievable.

The only thing is, I didn’t have any statistics around how likely a user was to vote after seeing us appear in their feed, and also I didn’t know how many users the little spider script I wrote would find (as users are highlighted on the screen randomly it’s entirely feasible that the first user displayed would be user A, then user B and then user A again – effectively causing a loop and limiting the number of profiles found for each time the spider is run). I set the script to run daily and I set it to remember the profiles that it finds, so the second day it’ll find more and organically get around the looping issue above.

Here’s a graph that shows the results of running the script. It shows the total number of votes received each day by the most popular accounts as well as mine which are shown in blue. On day three I started running the script…

The most popular user was getting something like 180 points a day, on the second day of testing I achieved 1,700 points…ahh. This meant by the third day I was in second second place, with 27 days left to get myself to 1st.

Anyway – I had fun, I achieved the aim of the project and although I didn’t exploit something considered a “vulnerability”, as such, it highlights that sometimes taking a look at the underlying design and logic of an application is often enough to have the desired effect.