# GraphQL
Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)! Outras formas de apoiar o HackTricks: * Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)! * Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com) * Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos * **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo [**telegram**](https://t.me/peass) ou **siga**-me no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.** * **Compartilhe suas técnicas de hacking enviando PRs para os repositórios github** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
## Introdução GraphQL atua como uma alternativa à API REST. APIs REST exigem que o cliente envie múltiplas requisições para diferentes endpoints na API para consultar dados do banco de dados backend. Com GraphQL, você só precisa enviar uma requisição para consultar o backend. Isso é muito mais simples porque você não precisa enviar múltiplas requisições para a API, uma única requisição pode ser usada para reunir todas as informações necessárias. ## GraphQL À medida que novas tecnologias surgem, novas vulnerabilidades também aparecem. Por **padrão**, o GraphQL **não** implementa **autenticação**, isso fica a cargo do desenvolvedor implementar. Isso significa que, por padrão, o GraphQL permite que qualquer um o consulte, e qualquer informação sensível estará disponível para atacantes não autenticados. Ao realizar seus ataques de força bruta em diretórios, certifique-se de adicionar os seguintes caminhos para verificar a existência de instâncias GraphQL. * `/graphql` * `/graphiql` * `/graphql.php` * `/graphql/console` * `/api` * `/api/graphql` * `/graphql/api` * `/graphql/graphql`
Uma vez que você encontre uma instância aberta de GraphQL, você precisa saber **quais consultas ela suporta**. Isso pode ser feito usando o sistema de introspecção, mais detalhes podem ser encontrados aqui: [**GraphQL: Uma linguagem de consulta para APIs.**\ É frequentemente útil pedir a um esquema GraphQL informações sobre quais consultas ele suporta. GraphQL nos permite fazer isso…](https://graphql.org/learn/introspection/) ### Identificação A ferramenta [**graphw00f**](https://github.com/dolevf/graphw00f) é capaz de detectar qual motor GraphQL é usado em um servidor e, em seguida, imprime algumas informações úteis para o auditor de segurança. #### Consultas universais Se você enviar `query{__typename}` para qualquer endpoint GraphQL, ele incluirá a string `{"data": {"__typename": "query"}}` em algum lugar em sua resposta. Isso é conhecido como uma consulta universal e é uma ferramenta útil para sondar se uma URL corresponde a um serviço GraphQL. A consulta funciona porque todo endpoint GraphQL tem um campo reservado chamado `__typename` que retorna o tipo do objeto consultado como uma string. ### Enumeração Básica GraphQL geralmente suporta **GET**, **POST** (x-www-form-urlencoded) e **POST**(json). Embora, por segurança, seja recomendado permitir apenas json para prevenir ataques CSRF. #### Introspecção Para usar a introspecção para descobrir informações do esquema, consulte o campo `__schema`. Este campo está disponível no tipo raiz de todas as consultas. ```bash query={__schema{types{name,fields{name}}}} ``` ```graphql { __schema { types { name } } ``` {% endcode %} Com esta consulta, você encontrará o nome de todos os tipos em uso: ![](<../../.gitbook/assets/image (202).png>) ```bash query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}} ``` {% endcode %} Com esta consulta, você pode extrair todos os tipos, seus campos e seus argumentos (e o tipo dos argumentos). Isso será muito útil para saber como consultar o banco de dados. ![](<../../.gitbook/assets/image (207) (3).png>) **Erros** É interessante saber se os **erros** serão **exibidos**, pois eles contribuirão com informações úteis. ``` ?query={__schema} ?query={} ?query={thisdefinitelydoesnotexist} ``` ![](<../../.gitbook/assets/image (205) (1).png>) **Enumeração do Esquema de Banco de Dados via Introspecção** {% hint style="info" %} Se a introspecção estiver ativada, mas a consulta acima não funcionar, tente remover as diretivas `onOperation`, `onFragment` e `onField` da estrutura da consulta. {% endhint %} ```bash #Full introspection query query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description args { ...InputValue } onOperation #Often needs to be deleted to run query onFragment #Often needs to be deleted to run query onField #Often needs to be deleted to run query } } } 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 } } } } ``` Consulta de introspecção inline: ``` /?query=fragment%20FullType%20on%20Type%20{+%20%20kind+%20%20name+%20%20description+%20%20fields%20{+%20%20%20%20name+%20%20%20%20description+%20%20%20%20args%20{+%20%20%20%20%20%20...InputValue+%20%20%20%20}+%20%20%20%20type%20{+%20%20%20%20%20%20...TypeRef+%20%20%20%20}+%20%20}+%20%20inputFields%20{+%20%20%20%20...InputValue+%20%20}+%20%20interfaces%20{+%20%20%20%20...TypeRef+%20%20}+%20%20enumValues%20{+%20%20%20%20name+%20%20%20%20description+%20%20}+%20%20possibleTypes%20{+%20%20%20%20...TypeRef+%20%20}+}++fragment%20InputValue%20on%20InputValue%20{+%20%20name+%20%20description+%20%20type%20{+%20%20%20%20...TypeRef+%20%20}+%20%20defaultValue+}++fragment%20TypeRef%20on%20Type%20{+%20%20kind+%20%20name+%20%20ofType%20{+%20%20%20%20kind+%20%20%20%20name+%20%20%20%20ofType%20{+%20%20%20%20%20%20kind+%20%20%20%20%20%20name+%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+}++query%20IntrospectionQuery%20{+%20%20schema%20{+%20%20%20%20queryType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20mutationType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20types%20{+%20%20%20%20%20%20...FullType+%20%20%20%20}+%20%20%20%20directives%20{+%20%20%20%20%20%20name+%20%20%20%20%20%20description+%20%20%20%20%20%20locations+%20%20%20%20%20%20args%20{+%20%20%20%20%20%20%20%20...InputValue+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+} ``` A última linha de código é uma consulta graphql que irá despejar todas as meta-informações do graphql (nomes de objetos, parâmetros, tipos...) ![](<../../.gitbook/assets/image (206).png>) Se a introspecção estiver habilitada, você pode usar o [**GraphQL Voyager**](https://github.com/APIs-guru/graphql-voyager) para visualizar em uma GUI todas as opções. ### Consultando Agora que sabemos que tipo de informação está salva dentro do banco de dados, vamos tentar **extrair alguns valores**. Na introspecção, você pode encontrar **qual objeto você pode consultar diretamente** (porque você não pode consultar um objeto apenas porque ele existe). Na imagem a seguir, você pode ver que o "_queryType_" é chamado "_Query_" e que um dos campos do objeto "_Query_" é "_flags_", que também é um tipo de objeto. Portanto, você pode consultar o objeto flag. ![](../../.gitbook/assets/screenshot-from-2021-03-13-18-17-48.png) Note que o tipo da consulta "_flags_" é "_Flags_", e este objeto é definido como abaixo: ![](../../.gitbook/assets/screenshot-from-2021-03-13-18-22-57.png) Você pode ver que os objetos "_Flags_" são compostos por **name** e **value**. Então você pode obter todos os nomes e valores das flags com a consulta: ```javascript query={flags{name, value}} ``` Observe que, caso o **objeto a consultar** seja um **tipo primitivo** como **string**, como no exemplo a seguir ![](<../../.gitbook/assets/image (441).png>) Você pode simplesmente consultá-lo com: ```javascript query={hiddenFlags} ``` Em outro exemplo onde havia 2 objetos dentro do objeto "_Query_": "_user_" e "_users_".\ Se esses objetos não precisarem de nenhum argumento para buscar, poderiam **recuperar todas as informações deles** apenas **solicitando** os dados que você quer. Neste exemplo da Internet, você poderia extrair os nomes de usuário e senhas salvos: ![](<../../.gitbook/assets/image (208).png>) No entanto, neste exemplo, se você tentar fazer isso, você recebe este **erro**: ![](<../../.gitbook/assets/image (210).png>) Parece que de alguma forma ele vai buscar usando o argumento "_**uid**_" do tipo _**Int**_.\ De qualquer forma, já sabíamos disso, na seção [Enumeração Básica](graphql.md#basic-enumeration) uma consulta foi proposta que estava nos mostrando todas as informações necessárias: `query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}` Se você ler a imagem fornecida quando eu executo essa consulta, você verá que "_**user**_" tinha o **arg** "_**uid**_" do tipo _Int_. Então, realizando um leve bruteforce em _**uid**_, descobri que em _**uid**=**1**_ um nome de usuário e uma senha foram recuperados:\ `query={user(uid:1){user,password}}` ![](<../../.gitbook/assets/image (211).png>) Note que eu **descobri** que eu poderia pedir pelos **parâmetros** "_**user**_" e "_**password**_" porque se eu tentar procurar por algo que não existe (`query={user(uid:1){noExists}}`) eu recebo este erro: ![](<../../.gitbook/assets/image (213).png>) E durante a **fase de enumeração** eu descobri que o objeto "_**dbuser**_" tinha como campos "_**user**_" e "_**password**_". **Truque de despejo de string de consulta (agradecimentos a @BinaryShadow\_)** Se você pode buscar por um tipo de string, como: `query={theusers(description: ""){username,password}}` e você **procura por uma string vazia** isso irá **despejar todos os dados**. (_Note que este exemplo não está relacionado com o exemplo dos tutoriais, para este exemplo suponha que você pode buscar usando "**theusers**" por um campo String chamado "**description**"_). GraphQL é uma tecnologia relativamente nova que está começando a ganhar alguma tração entre startups e grandes corporações. Além da falta de autenticação por padrão, endpoints GraphQL podem ser vulneráveis a outros bugs, como IDOR. ### Pesquisando Para este exemplo, imagine um banco de dados com **pessoas** identificadas pelo email e pelo nome e **filmes** identificados pelo nome e classificação. Uma **pessoa** pode ser **amiga** de outras **pessoas** e uma pessoa pode **ter filmes**. Você pode **pesquisar** pessoas **pelo** **nome** e obter seus emails: ```javascript { searchPerson(name: "John Doe") { email } } ``` Você pode **procurar** pessoas **pelo** **nome** e obter os **filmes** aos quais estão **inscritas**: ```javascript { searchPerson(name: "John Doe") { email subscribedMovies { edges { node { name } } } } } ``` Observe como é indicado para recuperar o `name` dos `subscribedMovies` da pessoa. Você também pode **pesquisar vários objetos ao mesmo tempo**. Neste caso, é feita uma busca de 2 filmes: ```javascript { searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) { name } }r ``` Ou até mesmo **relações de vários objetos diferentes usando aliases**: ```javascript { johnsMovieList: searchPerson(name: "John Doe") { subscribedMovies { edges { node { name } } } } davidsMovieList: searchPerson(name: "David Smith") { subscribedMovies { edges { node { name } } } } } ``` ### Mutations **Mutations são usadas para fazer alterações no lado do servidor.** Na **introspecção**, você pode encontrar as **mutations** **declaradas**. Na imagem a seguir, o "_MutationType_" é chamado de "_Mutation_" e o objeto "_Mutation_" contém os nomes das mutations (como "_addPerson_" neste caso): ![](../../.gitbook/assets/screenshot-from-2021-03-13-18-26-27.png) Para este exemplo, imagine um banco de dados com **pessoas** identificadas pelo email e nome e **filmes** identificados pelo nome e classificação. Uma **pessoa** pode ser **amiga** de outras **pessoas** e uma pessoa pode **ter filmes**. Uma mutation para **criar novos** filmes dentro do banco de dados pode ser como a seguinte (neste exemplo, a mutation é chamada `addMovie`): ```javascript mutation { addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) { movies { name rating } } } ``` **Observe como os valores e o tipo de dados são indicados na consulta.** Também pode haver uma **mutation** para **criar** **pessoas** (chamada `addPerson` neste exemplo) com amigos e filmes (note que os amigos e filmes devem existir antes de criar uma pessoa relacionada a eles): ```javascript mutation { addPerson(name: "James Yoe", email: "jy@example.com", friends: [{name: "John Doe"}, {email: "jd@example.com"}], subscribedMovies: [{name: "Rocky"}, {name: "Interstellar"}, {name: "Harry Potter and the Sorcerer's Stone"}]) { person { name email friends { edges { node { name email } } } subscribedMovies { edges { node { name rating releaseYear } } } } } } ``` ### Força bruta em lote em 1 requisição API Esta informação foi retirada de [https://lab.wallarm.com/graphql-batching-attack/](https://lab.wallarm.com/graphql-batching-attack/).\ Autenticação através da API GraphQL com **envio simultâneo de muitas consultas com credenciais diferentes** para verificação. É um ataque de força bruta clássico, mas agora é possível enviar mais de um par de login/senha por requisição HTTP devido ao recurso de lote do GraphQL. Esta abordagem enganaria aplicativos de monitoramento de taxa externa, fazendo-os pensar que está tudo bem e que não há um bot tentando adivinhar senhas. Abaixo, você pode encontrar a demonstração mais simples de uma solicitação de autenticação de aplicativo, com **3 pares de email/senha diferentes de cada vez**. Obviamente, é possível enviar milhares em uma única solicitação da mesma maneira: ![](<../../.gitbook/assets/image (182) (1).png>) Como podemos ver na captura de tela da resposta, as primeiras e terceiras solicitações retornaram _null_ e refletiram a informação correspondente na seção _error_. A **segunda mutação tinha os dados de autenticação corretos** e a resposta tem o token de sessão de autenticação correto. ![](<../../.gitbook/assets/image (119) (1).png>) ## GraphQL Sem Introspecção Cada vez mais **endpoints graphql estão desativando a introspecção**. No entanto, os erros que o graphql gera quando recebe uma solicitação inesperada são suficientes para ferramentas como [**clairvoyance**](https://github.com/nikitastupin/clairvoyance) recriarem a maior parte do esquema. Além disso, a extensão Burp Suite [**GraphQuail**](https://github.com/forcesunseen/graphquail) **observa as solicitações da API GraphQL passando pelo Burp** e **constrói** um esquema GraphQL interno com cada nova consulta que vê. Também pode expor o esquema para GraphiQL e Voyager. A extensão retorna uma resposta falsa quando recebe uma consulta de introspecção. Como resultado, o GraphQuail mostra todas as consultas, argumentos e campos disponíveis para uso dentro da API. Para mais informações [**verifique isto**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema). Uma boa **lista de palavras** para descobrir [**entidades GraphQL pode ser encontrada aqui**](https://github.com/Escape-Technologies/graphql-wordlist?). ### Contornando defesas de introspecção GraphQL Se você não conseguir executar consultas de introspecção para a API que está testando, tente inserir um **caractere especial após a palavra-chave `__schema`**. Quando os desenvolvedores desativam a introspecção, eles podem usar uma regex para excluir a palavra-chave `__schema` nas consultas. Você deve tentar caracteres como **espaços**, **novas linhas** e **vírgulas**, pois são **ignorados** pelo GraphQL, mas não por regex com falhas. Assim, se o desenvolvedor excluiu apenas `__schema{`, então a consulta de introspecção abaixo não seria excluída. ```bash #Introspection query with newline { "query": "query{__schema {queryType{name}}}" } ``` Se isso não funcionar, tente executar a sonda usando um método de solicitação alternativo, pois a introspecção pode estar desativada apenas para POST. Tente uma solicitação GET ou uma solicitação POST com um content-type de `x-www-form-urlencoded`. ### Estruturas GraphQL Vazadas Se a introspecção estiver desativada, tente olhar o código-fonte do site. As consultas geralmente são pré-carregadas no navegador como bibliotecas javascript. Essas consultas pré-escritas podem revelar informações valiosas sobre o esquema e o uso de cada objeto e função. A aba `Sources` das ferramentas de desenvolvedor pode pesquisar todos os arquivos para enumerar onde as consultas estão salvas. Às vezes, até as consultas protegidas pelo administrador já estão expostas. ```javascript Inspect/Sources/"Search all files" file:* mutation file:* query ``` ## CSRF em GraphQL Se você não sabe o que é CSRF, leia a seguinte página: {% content-ref url="../../pentesting-web/csrf-cross-site-request-forgery.md" %} [csrf-cross-site-request-forgery.md](../../pentesting-web/csrf-cross-site-request-forgery.md) {% endcontent-ref %} Lá fora, você vai poder encontrar vários endpoints GraphQL **configurados sem tokens CSRF.** Note que as requisições GraphQL são geralmente enviadas via requisições POST usando o Content-Type **`application/json`**. ```javascript {"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"} ``` No entanto, a maioria dos endpoints GraphQL também suporta **`form-urlencoded` POST requests:** ```javascript query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A ``` Portanto, como as solicitações CSRF, como as anteriores, são enviadas **sem solicitações de preflight**, é possível **realizar** **alterações** no GraphQL abusando de um CSRF. No entanto, observe que o novo valor padrão do cookie para a flag `samesite` do Chrome é `Lax`. Isso significa que o cookie só será enviado de um site terceiro em solicitações GET. Note que geralmente é possível enviar a **solicitação de consulta** também como uma **solicitação GET e o token CSRF pode não ser validado em uma solicitação GET.** Além disso, abusar de um **ataque** [**XS-Search**](../../pentesting-web/xs-search.md) pode ser possível exfiltrar conteúdo do endpoint GraphQL abusando das credenciais do usuário. Para mais informações, **consulte o** [**post original aqui**](https://blog.doyensec.com/2021/05/20/graphql-csrf.html). ## Autorização no GraphQL Muitas funções do GraphQL definidas no endpoint podem apenas verificar a autenticação do solicitante, mas não a autorização. Modificar variáveis de entrada da consulta pode levar ao vazamento de detalhes sensíveis da conta [vazados](https://hackerone.com/reports/792927). A mutação até poderia levar à tomada de controle da conta, tentando modificar outros dados da conta. ```javascript { "operationName":"updateProfile", "variables":{"username":INJECT,"data":INJECT}, "query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}" } ``` ### Bypass de autorização no GraphQL [Encadeamento de consultas](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln) pode contornar um sistema de autenticação fraco. No exemplo abaixo, você pode ver que a operação é "forgotPassword" e que ela deveria executar apenas a consulta forgotPassword associada a ela. Isso pode ser contornado adicionando uma consulta ao final, neste caso adicionamos "register" e uma variável de usuário para o sistema registrar como um novo usuário.
## Bypass de limite de taxa usando aliases Normalmente, objetos GraphQL não podem conter múltiplas propriedades com o mesmo nome. Aliases permitem que você contorne essa restrição **nomeando explicitamente as propriedades que deseja** que a API retorne. Você pode usar aliases para retornar **múltiplas instâncias do mesmo** tipo de objeto em uma única solicitação. Para mais informações sobre aliases no GraphQL, veja [Aliases](https://portswigger.net/web-security/graphql/what-is-graphql#aliases). Embora os aliases sejam destinados a limitar o número de chamadas de API que você precisa fazer, eles também podem ser usados para força bruta em um endpoint GraphQL. Muitos endpoints terão algum tipo de **limitador de taxa para prevenir ataques de força bruta**. Alguns limitadores de taxa funcionam com base no **número de solicitações HTTP** recebidas em vez do número de operações realizadas no endpoint. Como aliases efetivamente permitem enviar múltiplas consultas em uma única mensagem HTTP, eles podem contornar essa restrição. O exemplo simplificado abaixo mostra uma série de **consultas com aliases verificando se códigos de desconto de lojas são válidos**. Esta operação poderia potencialmente contornar o limite de taxa, pois é uma única solicitação HTTP, mesmo que possa ser usada para verificar um grande número de códigos de desconto de uma só vez. ```bash #Request with aliased queries query isValidDiscount($code: Int) { isvalidDiscount(code:$code){ valid } isValidDiscount2:isValidDiscount(code:$code){ valid } isValidDiscount3:isValidDiscount(code:$code){ valid } } ``` ## Ferramentas ### Scanners de Vulnerabilidade * [https://github.com/gsmith257-cyber/GraphCrawler](https://github.com/gsmith257-cyber/GraphCrawler): Toolkit que pode ser usado para capturar esquemas e procurar por dados sensíveis, testar autorização, força bruta em esquemas e encontrar caminhos para um determinado tipo. * [https://blog.doyensec.com/2020/03/26/graphql-scanner.html](https://blog.doyensec.com/2020/03/26/graphql-scanner.html): Pode ser usado como standalone ou [extensão Burp](https://github.com/doyensec/inql). * [https://github.com/swisskyrepo/GraphQLmap](https://github.com/swisskyrepo/GraphQLmap): Pode ser usado como um cliente CLI também para automatizar ataques. * [https://gitlab.com/dee-see/graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum): Ferramenta que lista as diferentes maneiras de alcançar um determinado tipo em um esquema GraphQL. * [https://github.com/doyensec/inql](https://github.com/doyensec/inql): Extensão Burp para testes avançados em GraphQL. O _**Scanner**_ é o núcleo do InQL v5.0, onde você pode analisar um endpoint GraphQL ou um arquivo de esquema de introspecção local. Ele gera automaticamente todas as possíveis queries e mutations, organizando-as em uma visão estruturada para sua análise. O componente _**Attacker**_ permite executar ataques GraphQL em lote, o que pode ser útil para contornar limites de taxa mal implementados. ### Clientes * [https://github.com/graphql/graphiql](https://github.com/graphql/graphiql): Cliente GUI * [https://altair.sirmuel.design/](https://altair.sirmuel.design/): Cliente GUI ### Testes Automáticos {% embed url="https://graphql-dashboard.herokuapp.com/" %} * Vídeo explicando AutoGraphQL: [https://www.youtube.com/watch?v=JJmufWfVvyU](https://www.youtube.com/watch?v=JJmufWfVvyU) ## Referências * [**https://jondow.eu/practical-graphql-attack-vectors/**](https://jondow.eu/practical-graphql-attack-vectors/) * [**https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696**](https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696) * [**https://medium.com/@apkash8/graphql-vs-rest-api-model-common-security-test-cases-for-graphql-endpoints-5b723b1468b4**](https://medium.com/@apkash8/graphql-vs-rest-api-model-common-security-test-cases-for-graphql-endpoints-5b723b1468b4) * [**http://ghostlulz.com/api-hacking-graphql/**](http://ghostlulz.com/api-hacking-graphql/) * [**https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/GraphQL%20Injection/README.md**](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/GraphQL%20Injection/README.md) * [**https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696**](https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696) * [**https://portswigger.net/web-security/graphql**](https://portswigger.net/web-security/graphql)
Aprenda AWS hacking do zero ao herói com htARTE (HackTricks AWS Red Team Expert)! Outras maneiras de apoiar o HackTricks: * Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)! * Adquira o [**merchandising oficial PEASS & HackTricks**](https://peass.creator-spring.com) * Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos * **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga**-me no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.** * **Compartilhe suas dicas de hacking enviando PRs para os repositórios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) no github.