Note for GraphQL

This is a rough translation from one article on my old Chinese blog. The original one was written on Sept. 19th, 2017. Last weekend, when I was playing a CTF game, I got an interesting challenge about GraphQL. That was my first time to see GraphQL. At that time, I spent some time on Google, trying to get more detail about it, but finally found a few things impressive. This time, I took a twice look at it. Although it may lack some depth, it is enough to be a note.

Description About the Challenge

When I just visited the page, signing up and then loging in, I got a view of a online shop. Each user are assigned by 100 credits by default, and the only four products have the prices of 30, 60, 100, and 110. The 110 is the price of the flag you are supposed to buy.

My Thoughts

Was that a Race Condition? Open two sessions, one for purchasing and the other one for selling. Confliction may occur when two sessions tried to update entries in database, leading to a larger amount of credits more than 100. However, it seemed to be no selling function in the system. Obviously, it could not be Race Condition.

Then I looked into HTTP packages, and found things below:

  1. Keyword graphql in URL;
  2. productId and orderID in HTTP body with POST method.

I realized I needed to see what GraphQL is.

Something About GraphQL

What is GraphQL? You can find some details in http://graphql.org/learn/. Since I am not focused on development, I only studied it roughly. GraphQL is a sort of query language focused on APIs and data on web ends. GraphQL itself will not be bound to any DBMS.

Let us see a tiny example here.

It means for type Query, there is a field named me whose type is User. What is type User? It will be defined in the following code. Type User contains two field – id and name.

Here is another example, showing how you need to do if you want to do a query.

In my understanding, it is like SELECT name, height FROM human WHERE id="1000". Or it is a little bit like XPATH. However, since GraphQL will never be bound to any DBMS. That is the fundamental difference.

Back to the Challenge

With burp suite, I got the HTTP body like this.

query fetchOrder($searchTerm: String!) {
      findOrder(orderId: $searchTerm) {
             productId}}

By modifying productId, I could get different response, such as user{id, name, password}. Believe it or not, I prove the existance of these three field by guessing. Is there any way to dump the structure of the data set? Absolutely. Here is the answer. https://gist.github.com/craigbeck/b90915d49fda19d5b2b17ead14dcd6da

Then sell other people’s product with deleteOrder with the parameter of other people’s orderId and userId.

The following detailed steps to the solution can be found here: https://github.com/reznok/CTFWriteUps/tree/master/SEC-T_2017/DarkMarket

Leave a Reply

Your email address will not be published. Required fields are marked *