Michael Kwayisi

Exploiting MyJoyOnline Polls for Profit

Twitter · Facebook
A case study of how not to write a poll scriptA case study of how not to write a poll script

This afternoon I made a very unusual visit to myjoyonline.com to read some news. Then I came across this poll asking, "What do you make of the Ayew brothers' decision to temporarily quit the Black Stars?" Three options were available: "Good riddance", "Bad timing" and "Who cares?". I quickly voted option one as I'm a huge fan of the brothers. But I remembered something.

Almost a year ago, I discovered a vulnerability in this poll system, which allows you to vote as many times as you want. I sent an email to the site admin to inform him/her about this flaw. Whether the message reached its intended destination or not, I did not receive any reply. And today I realized the flaw is still alive and exploitable.

Before we continue, here is a disclaimer: "I cannot be held responsible for whatever you do with the information presented herein. Read this post at your own risk." So with that out of the way, let's do a recon to find out as much information as we can about the target system because the more we know about the system, the easier it becomes to game it.

The architecture

On the homepage is a section befittingly named Quick Poll. This section contains an HTML form element with 3 input radio buttons (the number of buttons is actually dependent upon the number of options to choose from), which determine the option you've selected. These radio buttons are named answerid. Within the same form are 2 other hidden input elements, named pollid (poll ID) and polldated (poll date; dunno why it's named in the past). The value of the pollid input element is the identifier for the poll (e.g. 123) while the value of polldated input element is the date of the poll (e.g. 2013-Feb-10).

When you submit the form by clicking the Vote button, the details (ID of the poll [pollid], associated date of the poll [polldated], and your selected option [answerid]) are sent to http://polls.myjoyonline.com/tgpolls/vote.php by way of an HTTP GET request (which is wrong because according to the HTTP protocol specification, the GET method should only be used for data retrieval but not submission).

When the details are received at the specified URL, the server-side script checks if a pollid cookie was sent by the browser. If indeed a pollid cookie exists with the same value as polldated (URL parameter), the script convinces itself that you've already voted. If a pollid cookie exists but does not have the same value as polldated, it assumes that you've voted before but not on this particular poll. Finally, if there is no pollid cookie, it gets positive that you've never voted before on the site.

After the destination page has finished processing your vote, it sends an HTTP cookie named pollid to the client browser. The value of this cookie is the value of the polldated parameter the client browser sent when submitting the form details. It finally outputs some JavaScript code to redirect you to the poll results page.

The exploit

Looking at the architecture of the system, it's very easy to vote multiple times. You just have to lie to the server script that you've never voted before (by not sending any pollid cookie) or at least not on this particular poll (by forging the value of the polldated parameter). But how long can we keep clearing this cookie or changing its value? Then we need to write a script to automate the task.

Being a Windows user, the simplest way was to write either a VBScript or JScript script. With that, I can take advantage of the Microsoft XML Library, which contains the MSXML2.XMLHTTP class string that can be used to send or retrieve content from the Web. Here are the contents of the script I wrote (in VBScript):

Option Explicit

Dim strUrl ' Target URL
Dim objXmlHttp ' Instance of MSXML2.XMLHTTP
Dim intI ' Counter

strUrl = "http://polls.myjoyonline.com/tgpolls/vote.php?pollid=156&answerid=436"
Set objXmlHttp = CreateObject("MSXML2.XMLHTTP.3.0")

For intI = 1 To 1000
objXmlHttp.Open "GET", strUrl & "&polldated=" & intI, False

Set objXmlHttp = Nothing

The job of the script is simple: vote 1,000 times. This is done by opening the target URL with some parameters and values. The parameters in the URL are pollid (specifies the poll you want to vote on), answerid (specifies your selected option; you can find the value for a specific option by viewing the HTML source), and polldated (specifies the date of the poll; in the script, this value is dynamically generated per request, effectively convincing the server-side script that I've not yet voted on this particular poll).

The solution

For online polls it's pretty hard to get a perfect solution to combat exploits like the one demonstrated above while remaining highly accessible. But there are some viable options better than what MyJoyOnline is currently employing. A few of such solutions are discussed below.

Vote by IP address. Using this method, votes are counted per IP address. Since every internet user has a unique IP address, this method is better than the cookie-only method implemented by MyJoyOnline. However, this method may prevent so many people from voting since many internet users surf the web behind proxies, therefore sharing a common IP address. Also in countries like Ghana, where the vast majority of internet subscribers are on dynamic IPs, this method will blindly prevent many legitimate users from voting as well.

Vote by registration. This approach is better than the IP address method. This method requires voters to be registered members of the site before they can vote. Nonetheless, a determined person will try to register many accounts in order to vote multiple times though him/her will be greatly slowed down. This approach may also result in very few people participating in the polls since so many individuals will not register just so they can vote. If MyJoyOnline had been a community site, then this approach would have been the best.

The hybrid approach. This method is implemented by using JavaScript to submit the form (AJAX) together with a secret key. With this method, a unique key/token is generated at the time of presenting the form to the user (CAPTCHA-like) that is sent back to the server when the vote is cast. If a vote comes in without the correct associated token, it is simply discarded. If a vote is accepted, the IP address may be logged and the appropriate cookie headers sent to the client browser. This method, however, requires the user to have JavaScript enabled in his/her browser, which in this day, we can safely assume the user has (except for a few mortals like me). I may actually write such a system in the near future to prove this theory.

Post a comment

    NOTE: You are replying to 's comment. [Cancel]