Aplicación PentQL con GraphQL



Recientemente, GraphQL está ganando cada vez más popularidad, y con ello está creciendo el interés de los expertos en seguridad de la información. La tecnología es utilizada por empresas como: Facebook, Twitter, PayPal, Github y otras, lo que significa que es hora de descubrir cómo probar dicha API. En este artículo, hablaremos sobre los principios de este lenguaje de consulta y las instrucciones para probar la penetración de aplicaciones con GraphQL.

¿Por qué necesitas saber GraphQL? Este lenguaje de consulta se está desarrollando activamente y cada vez más empresas están encontrando un uso práctico para él. En el marco de los programas Bug Bounty, la popularidad de este lenguaje también está creciendo, se pueden ver ejemplos interesantes aquí , aquí y aquí .

Preparación

Un sitio de prueba donde encontrará la mayoría de los ejemplos en este artículo.
Una lista con aplicaciones que también puedes usar para estudiar.

Para interactuar con varias API, es mejor usar GraphQL IDE:


Recomendamos el último IDE: Insomnia tiene una interfaz conveniente y simple, hay muchas configuraciones y autocompletar campos de solicitud.

Antes de pasar directamente a los métodos generales de análisis de seguridad de aplicaciones con GraphQL, recordamos los conceptos básicos.

¿Qué es GraphQL?


GraphQL es un lenguaje de consulta API diseñado para proporcionar una alternativa más eficiente, potente y flexible a REST. Se basa en un muestreo de datos declarativos, es decir, el cliente puede especificar exactamente qué datos necesita de la API. En lugar de múltiples puntos finales API (REST), GraphQL proporciona un punto final único que proporciona al cliente los datos solicitados.

Diferencias clave entre REST y GraphQL


Por lo general, en la API REST necesita obtener información de diferentes puntos finales. En GraphQL, para obtener los mismos datos, debe realizar una consulta que indique los datos que desea recibir.



La API REST proporciona la información que el desarrollador pondrá en la API, es decir, si necesita obtener más o menos información de lo que sugiere la API, se necesitarán acciones adicionales. Nuevamente, GraphQL proporciona exactamente la información solicitada.
Una adición útil es que GraphQL tiene un esquema que describe cómo y qué datos puede recibir el cliente.

Tipos de consultas


Hay 3 tipos principales de consultas en GraphQL:

  • Consulta
  • Mutación
  • Suscripción

Consulta

Las consultas de consulta se utilizan para recuperar / leer datos en un esquema.

Un ejemplo de tal solicitud:

query { allPersons { name } } 

En la solicitud, indicamos que queremos obtener los nombres de todos los usuarios. Además del nombre, podemos especificar otros campos: edad , id , publicaciones , etc. Para averiguar qué campos podemos obtener, debe presionar Ctrl + Espacio. En este ejemplo, pasamos el parámetro con el que la aplicación devolverá los dos primeros registros:

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

Mutación

Si se necesita el tipo de consulta para leer datos, se necesita el tipo de mutación para escribir, eliminar y modificar datos en GraphQL.

Un ejemplo de tal solicitud:

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

En esta solicitud, creamos un usuario con el nombre Bob y edad 37 (estos parámetros se pasan como argumentos), en el archivo adjunto (llaves) indicamos qué datos queremos recibir del servidor después de crear el usuario. Esto es necesario para comprender que la solicitud fue exitosa, así como para obtener datos que el servidor genera de forma independiente, como la identificación .

Suscripción

Otro tipo de consulta en GraphQL es la suscripción. Es necesario notificar a los usuarios sobre cualquier cambio que haya ocurrido en el sistema. Funciona así: el cliente se suscribe a algún evento, después del cual se establece una conexión con el servidor (generalmente a través de WebSocket), y cuando ocurre este evento, el servidor envía una notificación al cliente sobre la conexión establecida.

Un ejemplo:

 subscription { newPerson { name age id } } 

Cuando se crea una nueva Persona, el servidor enviará información al cliente. La presencia de consultas de suscripción en los esquemas es menos común que la consulta y la mutación.

Vale la pena señalar que todas las capacidades de consulta, mutación y suscripción son creadas y configuradas por el desarrollador de una API específica.

Opcional


En la práctica, los desarrolladores suelen utilizar alias y OperationName en las consultas para mayor claridad.

Alias

GraphQL para consultas proporciona la función de alias, que puede facilitar la comprensión de lo que solicita el cliente.

Supongamos que tenemos una consulta de la forma:

 { Person(id: 123) { age } } 

que mostrará el nombre de usuario con ID 123. Deje que este nombre de usuario sea Vasya.

Para que la próxima vez que no sepas qué mostrará esta solicitud, puedes hacerlo así:

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

Nombre de operación

Además del alias, GraphQL usa OperationName:

 query gettingAllPersons { allPersons { name age } } 

OperationName es necesario para explicar exactamente lo que hace la solicitud.

Pentest


Después de descubrir los conceptos básicos, vamos directamente al pentest. ¿Cómo entender que una aplicación usa GraphQL? Aquí hay una consulta de ejemplo que tiene una 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"} 

Algunos parámetros por los cuales puedes entender que esto es GraphQL, y no otra cosa:

  • en el cuerpo de la solicitud hay palabras: __esquema, campos, nombre de operación, mutación, etc.
  • en el cuerpo de la solicitud hay muchos caracteres "\ n". Como muestra la práctica, se pueden eliminar para que sea más conveniente leer la solicitud;
  • a menudo la forma de enviar una solicitud al servidor: ⁄graphql

Genial, encontrado e identificado. Pero, ¿ dónde insertar la comilla cómo averiguar con qué necesitamos trabajar? La introspección vendrá al rescate.

Introspección


GraphQL proporciona un esquema de introspección, es decir Un esquema que describe los datos que podemos obtener. Gracias a esto, podemos averiguar qué solicitudes existen, qué argumentos pueden / deben pasarles, y mucho más. Tenga en cuenta que en algunos casos, los desarrolladores intencionalmente no permiten la posibilidad de introspección de su aplicación. Sin embargo, la gran mayoría todavía deja esta posibilidad.

Considere los ejemplos básicos de consultas.

Ejemplo 1. Obtener todo tipo de solicitudes

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

Formamos una consulta de consulta, indicamos que deseamos recibir datos sobre __schema y, en él, sus nombres y campos. En GraphQL, hay nombres de variables de servicio: __schema, __typename, __type.

En la respuesta, recibiremos todo tipo de solicitudes, sus nombres y campos que existen en el esquema.

Ejemplo 2. Obtención de campos para un tipo específico de solicitud (consulta, mutación, descripción)

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

La respuesta a esta solicitud será todas las solicitudes posibles que podemos ejecutar en el esquema para recibir datos (tipo de consulta), y los argumentos posibles / necesarios para ellos. Para algunas consultas, se requiere especificar los argumentos. Si ejecuta dicha solicitud sin especificar un argumento requerido, el servidor debe mostrar un mensaje de error que debe especificar. En lugar de queryType, podemos sustituir mutationType y SubscribeType para obtener todas las solicitudes posibles de mutaciones y suscripciones, respectivamente.

Ejemplo 3. Obtener información sobre un tipo específico de solicitud

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

Gracias a esta consulta, obtenemos todos los campos para el tipo Persona. Como argumento, en lugar de Persona, podemos pasar cualquier otro nombre de solicitud.

Ahora que podemos descubrir la estructura general de la aplicación bajo prueba, determinemos lo que estamos buscando.

Divulgación de información

Con mayor frecuencia, una aplicación que usa GraphQL consta de muchos campos y tipos de consultas y, como mucha gente sabe, cuanto más compleja y grande es la aplicación, más difícil es configurar y monitorear su seguridad. Es por eso que con una introspección cuidadosa puede encontrar algo interesante, por ejemplo: nombres completos de los usuarios, sus números de teléfono y otros datos críticos. Por lo tanto, si desea encontrar algo como esto, le recomendamos que verifique todos los campos y argumentos posibles de la aplicación. Entonces, como parte del pentest en una de las aplicaciones, se encontraron datos del usuario: nombre, número de teléfono, fecha de nacimiento, algunos datos de la tarjeta, etc.

Un ejemplo:

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

Al revisar los valores de id, podemos obtener información sobre otros usuarios (o tal vez no, si todo está configurado correctamente).

Inyecciones

Huelga decir que, en casi todas partes donde hay trabajo con una gran cantidad de datos, ¿hay bases de datos? Y donde hay una base de datos, puede haber inyecciones SQL, inyecciones NoSQL y otros tipos de inyecciones.

Un ejemplo:

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

Aquí hay una inyección primaria de SQL en el argumento de consulta.

Bypass de autorización
Digamos que podemos crear usuarios:

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

Suponiendo que hay un cierto parámetro isAdmin en el controlador del servidor, podemos enviar una solicitud del formulario:

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

Y haga al usuario Vasya un administrador.

Dos


Además de la conveniencia declarada, GraphQL tiene sus propios defectos de seguridad.

Considere un ejemplo:

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

Como puede ver, creamos una subconsulta en bucle. Con una gran cantidad de tales inversiones, por ejemplo, 50 mil, podemos enviar una solicitud que será procesada por el servidor durante mucho tiempo o "descartarla" por completo. En lugar de procesar solicitudes válidas, el servidor estará ocupado desempacando la anidación gigante de la solicitud ficticia.

Además de la anidación grande, las consultas en sí pueden ser "pesadas", esto es cuando una consulta tiene muchos campos y archivos adjuntos internos. Tal solicitud también puede causar dificultades en el procesamiento en el servidor.

Conclusión


Entonces, examinamos los principios básicos de las pruebas de penetración de aplicaciones con GraphQL. Esperamos que hayas aprendido algo nuevo y útil para ti. Si está interesado en este tema y desea estudiarlo más a fondo, le recomendamos los siguientes recursos:


Y no lo olvides: la práctica hace la perfección. Buena suerte

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


All Articles