GraphQL

O GraphQL não é um banco de dados (apesar do nome lembrar bastante algo como SQL), mas ele nos oferece uma boa maneira de obter metadados sobre as informações disponíveis (semelhante à tabela information_schema do MySQL). Podemos por exemplo, saber o que está disponível. Isso pode causar um risco à segurança, pois invasores podem conseguir acesso a informações que não poderiam ser expostas (segurança por obscuridade).

Localizando o GraphQL

Geralmente o GraphQL está em algum subdomínio, como graphql.site.com, ou em subdiretórios como site.com/graphql, site.com/graphql.php, site.com/graphiql (versão GUI) e site.com/graphql/console.

Instrospection

Ativo

É sempre útil solicitar informações a um esquema GraphQL para saber quais consultas ele suporta e podemos fazer isso através do Introspection. Para a alegria do atacante, o Instrospection já vem habilitado por padrão no GraphQL. Segue abaixo algumas queries possíveis de fazer quando o Instrospect está ativo:

Consultando os tipos de dados disponíveis

{
  __schema {
    types {
      name
    }
  }
}

Descobrindo um bom lugar para começar a explorar quais consultas estão disponíveis. Quando projetamos nosso sistema de tipos, especificamos em que tipo todas as consultas começariam.

{
  __schema {
    queryType {
      name
    }
  }
}

Com a consulta abaixo, podemos extrair todos os tipos, seus campos e seus argumentos (e o tipo dos args). Isso será muito útil para saber como consultar o banco de dados.

{__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}

Uma boa forma também de trazermos todos os dados necessários, é utilizando o payload com URL Encode, da seguinte forma.

fragment+FullType+on+__Type+{++kind++name++description++fields(includeDeprecated%3a+true)+{++++name++++description++++args+{++++++...InputValue++++}++++type+{++++++...TypeRef++++}++++isDeprecated++++deprecationReason++}++inputFields+{++++...InputValue++}++interfaces+{++++...TypeRef++}++enumValues(includeDeprecated%3a+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++++++++++++++}++++++++++++}++++++++++}++++++++}++++++}++++}++}}query+IntrospectionQuery+{++__schema+{++++queryType+{++++++name++++}++++mutationType+{++++++name++++}++++types+{++++++...FullType++++}++++directives+{++++++name++++++description++++++locations++++++args+{++++++++...InputValue++++++}++++}++}}

Inativo

É​ cada vez menos comum acharmos GraphQL com Instrospection ativo, mas isso não nos empede de mapearmos as suas informações. Para isso, podemos contar com o Clairvoyance para nos ajudar nessa missão.

Mutations

As Mutation podem ser utilizadas para inserir dados. Note que abaixo estamos inserindo algumas informações entre parentes e depois estamos passando alguns campos entre chaves, que servem pra informar ao GraphQL o que ele devolver de informação após a inserção. Então inserimos nome e ano, porém só irá ser retornado o nome ao realizar a inserção.

mutation {
  addPerson(name: "Mysther", year: 12) {
    person {
      name
    }
  }
}

Fragments

Os Fragments, são utilizado para evitar que uma query tenha uma escrita repetitiva, servindo assim como uma espécia de função/método. Abaixo um exemplo de utilização de Fragment, para tratar duas chamadas de pesquisas de usuário.

{
  mysther1: searchPerson(name: "Mysther1") {
    ...myCustomFragment
  }
  mysther2: searchPerson(name: "Mysther2") {
    ...myCustomFragment
  }
}

fragment myCustomFragment on Person {
  languages {
    edges {
      node {
        name
      }
    }
  }
}

Mensagens de Erro

Mensagens de erro também podem nos dar boas dicas de uso, entre informações que também podem ser importantes. Abaixo segue algumas queries que podem provocar boas mensagens de erro.

{}
{__schema}
{algoquenaoexiste}

GraphQL Voyager

Ferrementa offline e online (link no final da página) que recebe o resultado de uma query contra um GraphQL com Instrospection ativo e a partir desse resultado, realiza uma demonstação gráfica sobre a estrutura do alvo.

O primeiro passo para isso, é confirmar que o cliente possui o Instrospection ativo e, então, utilizar a seguinte query:

{__schema {queryType { name } mutationType { name } subscriptionType { 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 }}}}}}}}

Copie o resultado da query, vá no GraphQL Voyager, clique em Change Schema, vá na aba Instrospection, cole o resultado e clique em Display.

Graphqlmap

python3 graphqlmap.py -u <https://site.com/graphql>
dump_new

Sites

# GraphQL Voyager
https://apis.guru/graphql-voyager/

# Clairvoyance
https://github.com/nikitastupin/clairvoyance

# Graphqlmap
https://github.com/swisskyrepo/GraphQLmap

Last updated