Update 2: After writing this post, I also discovered another vulnerability in Trivia Crack that allowed for giving users unlimited lives/spins. At that time, I added this as another feature to Trivia Cracker. Yesterday (1/29/2016), Trivia Cracker started preventing this feature (automatic question answering continues to work — as described in this post). But what’s funny is, in addition to preventing it, the Trivia Crack server also calls me out specifically!
Update 1: Using similar techniques to the below, I’ve also released a cheating Chrome extension for Candy Crush. Get it here.
As the holiday season began a few weeks ago, I started to notice that a new app, Trivia Crack, was becoming popular with my friends. For those of you who don’t know, Trivia Crack is a new game for Android, iPhone, and Facebook. The premise of the game is simple, and very similar to another popular app from last year, QuizUp. Essentially, you answer trivia questions of various categories, competing against your friends for bragging rights. Despite the simplicity (or maybe due to it), Trivia Crack has become very popular as of late – racking up 5.3 million likes on Facebook and becoming the top free app in the Google Play (Android) store.
You’d think the developers of such a polished and successful game might have taken the time to implement it in a way that is secure from cheating, but it turns out writing a program to cheat at Trivia Crack is actually fairly simple. Over the course of a weekend, I was able to write and release a Chrome extension, Trivia Cracker, that turned me from a medicore-at-best Trivia Crack player to a seemingly genius demigod. You can see Trivia Cracker in action below:
So what’s wrong with Trivia Crack’s implementation that allowed me to so easily build a tool that lets anyone cheat? In short – when the Trivia Crack client requests from the Trivia Crack server the next question to ask the user, the server responds not just with the question and the possible answers, but also sends which answer is the correct answer. The details of the vulnerability, how I found it, and how I built a Chrome extension to take advantage of it are below.
1 – Finding the vulnerability
After losing to my friends in Trivia Crack one too many times, I decided I wanted to see if I could win in my own, special way. While I’m not so good at random trivia, I am pretty good at reverse-engineering. I suspected I might be able to take advantage of sending my own requests to Trivia Crack’s servers, or using some data in the responses from Trivia Crack’s servers, to gain an edge in the game. So I started by researching what kinds of data the Trivia Crack client and server pass back and forth.
To inspect this data, I played Trivia Crack in my browser on Facebook, while recording and inspecting the requests and responses sent between Trivia Crack’s client and server using a tool I’d created previously called Gargl. Yes, I know I could have used Fiddler or Chrome’s Developer Tools to do the same. I decided to use Gargl instead because in addition to letting you view client/server requests/responses, Gargl also lets you modify and parameterize these requests, and then auto-generates modules in a programming language of your choice so you can make these same requests without writing a line of code. More on that later.
Anyway, after telling Gargl to start recording and going to Trivia Crack on Facebook in my browser, the first step was to figure out which of the many requests being sent on this Facebook page were related to Trivia Crack, versus Facebook itself. Inspecting the HTML on the page showed that the Trivia Crack content is embedded into Facebook via an iframe. The element right above this iframe was a form meant to post to a peculiar URL- https://preguntados.com/game.
My limited knowledge of Spanish reminded me that “pregunta” means “question,” which seems related to trivia, so I suspected this was the domain where Trivia Crack is hosted. Going to the https://preguntados.com/game URL confirmed that suspicion:
The next step was just to start playing Trivia Crack, and as I played look at the requests Gargl finds that the page is making to any url containing “preguntados.com”:
As I answered Trivia Crack questions, I noticed a new request seemed to be issued for each question. Actually, the request seemed to be issued before I even “spun the spinner” in Trivia Crack to determine what category the next question would be:
This made me think maybe the questions were predetermined, and the “random spinner” in fact was predetermined to land on a certain category (and ask a certain question) based on the response from the server to the “api.preguntados.com/api/users/<userID>/games/<gameID>” request that sent before you click the “Spin” button. To me, this meant I could probably alert the user to the question they are about to be asked ahead of time, so they would have as much time as they wanted to think about it or look it up. This would be an advantage because in Trivia Crack, you only get 30 seconds to answer a question once the question is shown, to prevent the user from looking up answers. In addition, in some game modes its not just the number of questions you get correct, but also the amount of time you take to answer, that determines if you win. If I could show the user the question ahead of time, they could obviously answer it much more quickly once Trivia Crack itself shows the question.
So I figured I had a lead and dug into the details of this request. It turns out this request actually provided a much larger “cheater’s advantage” than I thought…
2 – The vulnerability in detail
Using Gargl to look at the “api.preguntados.com/api/users/<userID>/games/<gameID>” request/response in detail, I was able to confirm that it does indeed provide the question to be asked, as well as the possible answers, in the response. However, I was surprised to find that the correct answer to the question is also embedded in the response!
As you can see above, the response to this request contains the question, the possible answers, and which index in the array of possible answers is the correct answer. So if this data is indeed about the next question, after I click “Spin,” I should be asked “Which of the following African countries doesn’t have a coast?” and the correct answer should be answers from above, which is “All of them do”. Clicking “Spin” proved this hypothesis correct:
I also used my browser to find that repeated GET requests to “api.preguntados.com/api/users/<userID>/games/<gameID>” always give the same response, until you answer the question it provides. This means I could request this URL from my own tool and still receive the same question as the Trivia Crack client on Facebook would receive.
A response containing the correct answer, when the goal is that the user must determine the answer themselves, is in direct conflict with the “Defensive Programming” practice of programming – particularly the “never trust the client” web programming principle. Since the server has no control over how the client acts, it can’t assume the client will not act in a malicious way, and so must protect itself. The correct way of implementing answer checking behavior is to do it on the server side. Don’t send the correct answer to the client at any point, and instead make the client send the user’s answer to the server, where the server will then check it for correctness and credit the user if correct (and of course, only allow one answer to be sent per user per question).
However, Trivia Crack did not do this, and instead trusts the client. Now it was just a matter of creating a malicious client to take advantage of the fact that the correct answer is sent in the response. Ideally, one that would be easy for non-technical users to install and use. Hmm…how about a Chrome extension that just adds a button to the Trivia Crack game, when played on Facebook, that when clicked answers the current question correctly automatically??
3 – Taking advantage of the vulnerability
And just like that, Trivia Cracker was born! Curious about the exact details of how Trivia Cracker works? Check out the source code on GitHub.
Interested in hearing about other side projects like this one? Subscribe to my blog and follow me on Twitter. I’ll let you know when I think of something fun.