Aplicativo PentQL com GraphQL



Recentemente, o GraphQL está ganhando cada vez mais popularidade, e com isso cresce o interesse de especialistas em segurança da informação. A tecnologia é usada por empresas como: Facebook, Twitter, PayPal, Github e outras, o que significa que é hora de descobrir como testar essa API. Neste artigo, falaremos sobre os princípios dessa linguagem de consulta e instruções para testar a penetração de aplicativos com o GraphQL.

Por que você precisa conhecer o GraphQL? Essa linguagem de consulta está se desenvolvendo ativamente e mais e mais empresas estão encontrando uso prático para ela. Dentro da estrutura dos programas Bug Bounty, a popularidade dessa linguagem também está crescendo, exemplos interessantes podem ser vistos aqui , aqui e aqui .

Preparação

Um site de teste onde você encontrará a maioria dos exemplos deste artigo.
Uma lista com aplicativos que você também pode usar para estudar.

Para interagir com várias APIs, é melhor usar o GraphQL IDE:


Recomendamos o último IDE: o Insomnia possui uma interface simples e conveniente, existem muitas configurações e preenchimento automático dos campos de solicitação.

Antes de prosseguir diretamente para os métodos gerais de análise de segurança de aplicativos com o GraphQL, lembramos dos conceitos básicos.

O que é o GraphQL?


O GraphQL é uma linguagem de consulta da API projetada para fornecer uma alternativa mais eficiente, poderosa e flexível ao REST. Ele é baseado na amostragem declarativa de dados, ou seja, o cliente pode especificar exatamente quais dados ele precisa da API. Em vez de vários pontos de extremidade da API (REST), o GraphQL fornece um único ponto de extremidade que fornece ao cliente os dados solicitados.

Principais diferenças entre REST e GraphQL


Normalmente, na API REST, você precisa obter informações de diferentes pontos de extremidade. No GraphQL, para obter os mesmos dados, você precisa fazer uma consulta indicando os dados que deseja receber.



A API REST fornece as informações que o desenvolvedor colocará na API, ou seja, se você precisar obter mais ou menos informações do que a API sugere, serão necessárias ações adicionais. Novamente, o GraphQL fornece exatamente as informações solicitadas.
Uma adição útil é que o GraphQL possui um esquema que descreve como e quais dados o cliente pode receber.

Tipos de consultas


Existem 3 tipos principais de consultas no GraphQL:

  • Consulta
  • Mutação
  • Assinatura

Consulta

As consultas de consulta são usadas para recuperar / ler dados em um esquema.

Um exemplo dessa solicitação:

query { allPersons { name } } 

Na solicitação, indicamos que queremos obter os nomes de todos os usuários. Além do nome, podemos especificar outros campos: idade , ID , postagens , etc. Para descobrir quais campos podemos obter, você precisa pressionar Ctrl + Espaço. Neste exemplo, passamos o parâmetro com o qual o aplicativo retornará os dois primeiros registros:

 query { allPersons(first: 2) { name } } 

Mutação

Se o tipo de consulta for necessário para ler dados, o tipo de mutação será necessário para gravar, excluir e modificar dados no GraphQL.

Um exemplo dessa solicitação:

 mutation { createPerson(name:"Bob", age: 37) { id name age } } 

Nesta solicitação, criamos um usuário com o nome Bob e 37 anos (esses parâmetros são passados ​​como argumentos). No anexo (colchetes), indicamos quais dados queremos receber do servidor após a criação do usuário. Isso é necessário para entender que a solicitação foi bem-sucedida e para obter dados que o servidor gera independentemente, como id .

Assinatura

Outro tipo de consulta no GraphQL é a assinatura. É necessário notificar os usuários sobre quaisquer alterações que ocorreram no sistema. Funciona assim: o cliente se inscreve em algum evento, após o qual uma conexão é estabelecida com o servidor (geralmente via WebSocket) e, quando esse evento ocorre, o servidor envia uma notificação ao cliente sobre a conexão estabelecida.

Um exemplo:

 subscription { newPerson { name age id } } 

Quando uma nova pessoa é criada, o servidor envia informações ao cliente. A presença de consultas de assinatura nos esquemas é menos comum que a consulta e a mutação.

Vale ressaltar que todos os recursos para consulta, mutação e assinatura são criados e configurados pelo desenvolvedor de uma API específica.

Opcional


Na prática, os desenvolvedores costumam usar alias e OperationName em consultas para maior clareza.

Alias

O GraphQL para consultas fornece o recurso de alias, que pode facilitar a compreensão do que o cliente está solicitando.

Suponha que tenhamos uma consulta do formulário:

 { Person(id: 123) { age } } 

que exibirá o nome de usuário com o ID 123. Seja Vasya.

Para que da próxima vez que você não decifre o que essa solicitação será exibida, faça o seguinte:

 { Vasya: Person(id: 123) { age } } 

Nome da operação

Além do alias, o GraphQL usa OperationName:

 query gettingAllPersons { allPersons { name age } } 

OperationName é necessário para explicar exatamente o que a solicitação faz.

Pentest


Depois que descobrimos o básico, vamos diretamente ao pentest. Como entender que um aplicativo usa o GraphQL? Aqui está um exemplo de consulta que possui uma consulta GraphQL:

 POST /simple/v1/cjp70ml3o9tpa0184rtqs8tmu/ HTTP/1.1 Host: api.graph.cool User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0 Accept: */* Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: https://api.graph.cool/simple/v1/cjp70ml3o9tpa0184rtqs8tmu/ content-type: application/json Origin: https://api.graph.cool Content-Length: 139 Connection: close {"operationName":null,"variables":{},"query":"{\n __schema {\n mutationType {\n fields {\n name\n }\n }\n }\n}\n"} 

Alguns parâmetros pelos quais você pode entender que esse é o GraphQL, e não outra coisa:

  • no corpo da solicitação, existem palavras: __schema, fields, operationName, mutation, etc;
  • no corpo da solicitação há muitos caracteres "\ n". Como mostra a prática, eles podem ser removidos para facilitar a leitura da solicitação;
  • geralmente a maneira de enviar uma solicitação ao servidor: ⁄graphql

Ótimo, encontrado e identificado. Mas onde inserir as aspas, como descobrir com o que precisamos trabalhar? A introspecção virá em socorro.

Introspecção


O GraphQL fornece um esquema de introspecção, ou seja, um esquema que descreve os dados que podemos obter. Graças a isso, podemos descobrir quais solicitações existem, quais argumentos podem / devem ser transmitidos a elas e muito mais. Observe que, em alguns casos, os desenvolvedores intencionalmente não permitem a possibilidade de introspecção de seus aplicativos. No entanto, a grande maioria ainda deixa essa possibilidade.

Considere os exemplos básicos de consultas.

Exemplo 1. Obtendo todos os tipos de solicitações

 query { __schema { types { name fields { name } } } } 

Formamos uma consulta de consulta, indicamos que queremos receber dados sobre o __schema e nele digita seus nomes e campos. No GraphQL, existem nomes de variáveis ​​de serviço: __schema, __typename, __type.

Na resposta, receberemos todos os tipos de solicitações, seus nomes e campos que existem no esquema.

Exemplo 2. Obtendo campos para um tipo específico de solicitação (consulta, mutação, descrição)

 query { __schema { queryType { fields { name args { name } } } } } 

A resposta a esta solicitação será todas as solicitações possíveis que podemos executar no esquema para recebimento de dados (tipo de consulta) e argumentos possíveis / necessários para eles. Para algumas consultas, é necessário especificar o (s) argumento (s). Se você executar tal solicitação sem especificar um argumento necessário, o servidor deverá exibir uma mensagem de erro que você deve especificar. Em vez de queryType, podemos substituir mutationType e subscriptionType para obter todos os pedidos possíveis de mutações e assinaturas, respectivamente.

Exemplo 3. Obtendo informações sobre um tipo específico de solicitação

 query { __type(name: "Person") { fields { name } } } 

Graças a esta consulta, obtemos todos os campos para o tipo Pessoa. Como argumento, em vez de Person, podemos passar qualquer outro nome de solicitação.

Agora que podemos descobrir a estrutura geral do aplicativo em teste, vamos determinar o que estamos procurando.

Divulgação de informações

Na maioria das vezes, um aplicativo que usa o GraphQL consiste em muitos campos e tipos de consultas e, como muitas pessoas sabem, quanto mais complexa e maior o aplicativo, mais difícil é configurar e monitorar sua segurança. É por isso que, com uma introspecção cuidadosa, você pode encontrar algo interessante, por exemplo: nomes completos dos usuários, seus números de telefone e outros dados críticos. Portanto, se você deseja encontrar algo assim, recomendamos que você verifique todos os campos e argumentos possíveis do aplicativo. Portanto, como parte do teste em um dos aplicativos, foram encontrados dados do usuário: nome, número de telefone, data de nascimento, alguns dados do cartão etc.

Um exemplo:

 query { User(id: 1) { name birth phone email password } } 

Examinando os valores de id, podemos obter informações sobre outros usuários (e talvez não, se tudo estiver configurado corretamente).

Injeções

Escusado será dizer que, em quase todos os lugares onde há trabalho com uma grande quantidade de dados, existem bancos de dados? E onde existe um banco de dados - pode haver injeções de SQL, injeções de NoSQL e outros tipos de injeções.

Um exemplo:

 mutation { createPerson(name:"Vasya'--+") { name } } 

Aqui está uma injeção SQL elementar no argumento de consulta.

Bypass de autorização
Digamos que possamos criar usuários:

 mutation { createPerson(username:"Vasya", password: "Qwerty1") { } } 

Supondo que exista um determinado parâmetro isAdmin no manipulador no servidor, podemos enviar uma solicitação do formulário:

 mutation { createPerson(username:"Vasya", password: "Qwerty1", isAdmin: True) { } } 

E torne o usuário Vasya um administrador.

Dos


Além da conveniência declarada, o GraphQL possui suas próprias falhas de segurança.

Considere um exemplo:

 query { Person { posts { author { posts { author { posts { author ... } } } } } } } 

Como você pode ver, criamos uma subconsulta em loop. Com um grande número desses investimentos, por exemplo, 50 mil, podemos enviar uma solicitação que será processada pelo servidor por um período muito longo ou "descartá-la" completamente. Em vez de processar solicitações válidas, o servidor estará ocupado descompactando o aninhamento gigante da solicitação fictícia.

Além do aninhamento grande, as próprias consultas podem ser "pesadas" - é quando uma consulta possui muitos campos e anexos internos. Essa solicitação também pode causar dificuldades no processamento no servidor.

Conclusão


Portanto, examinamos os princípios básicos do teste de penetração de aplicativos com o GraphQL. Esperamos que você tenha aprendido algo novo e útil para si mesmo. Se você está interessado neste tópico e deseja estudá-lo mais profundamente, recomendamos os seguintes recursos:


E não se esqueça: a prática leva à perfeição. Boa sorte

Source: https://habr.com/ru/post/pt444708/


All Articles