Exposing Users Table From a Leaky GraphQL Query
I am Inderjeet Singh aka encodedguy on HackerOne. In this blog post, I will give a walkthrough of my recent finding in which I got the data from the users table.
Before starting the attack, let's first understand the background of the application. For testing, only the beta environment was in scope, which means I am not dealing with a production environment here and it is out of scope as per the program's policy.
Let's call the target "app.target.com" and the GraphQL API of this target "api.target.com/v1/graphql". For any section that a user visits on the web app, the data for the same is fetched from GraphQL API.
Checking Introspection 0x02:
This is the first step of testing any GraphQL API - Introspection Query. If it's enabled, then an attacker has the whole schema or all the details of the API. It's the same as getting documentation of a REST API. I tried to hit the Introspection Query and got all the queries, mutations, input types, etc. data from the schema.
In the above screenshot, I am not using the complete Introspection Query. You can use that too, but the above request only gives the queries' names, descriptions, and input arguments. If you will change this to mutationType from queryType this will return all the mutations the same way.
From these queries, I got the query "auth_user" and it has an argument "distinct_on". The description in short says: "return auth_user table". Okay, I thought this is too vulnerable because if there is no authorization here then I would get all users in the response.
Making Payload 0x03:
It's time to create a final request or the GraphQL query and check if it's vulnerable or now. So, I have previously tested other queries from the schema and most of the queries have proper authorization checks. In this case, the response could be either 403 with nothing or 200 returning "auth_user" query's response.
The above image shows the query that I crafted. But, I got an error message that says about the possible argument values. The argument is "distinct_on" here. Possible values are id, last_name, first_name, etc.
Final Query: 0x04:
This is the final query that I have crafted and it gave me all user's data. This is a staging environment as I said, so, no production data is present here. But, I got data from all the users that were testing this application.
Error messages are a great source of information in the case of GraphQL APIs. They can give instructions to the tester that this is wrong and this is right. Do the right and test again, again error messages, again modify and again test.
Another thing about GraphQL is Authorization checks. I have tested several GraphQL APIs till now and got improper authorization at many of them that lead to BOLA, BFLA, Privilege Escalation, etc. bugs.
Explained Youtube Video:
Thank you for reading.
Hack the GraphQL