mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/network-services-pentesting/pentesting-web/graphql.md']
This commit is contained in:
parent
78ad6b7afc
commit
4422d1bd19
@ -8,7 +8,7 @@ GraphQL 被 **强调** 为 REST API 的 **高效替代方案**,提供了一种
|
||||
|
||||
## GraphQL 和安全性
|
||||
|
||||
随着包括 GraphQL 在内的新技术的出现,新安全漏洞也随之而来。一个关键点是 **GraphQL 默认不包含身份验证机制**。开发者有责任实施这些安全措施。没有适当的身份验证,GraphQL 端点可能会向未认证的用户暴露敏感信息,构成重大安全风险。
|
||||
随着包括 GraphQL 在内的新技术的出现,新安全漏洞也随之而来。一个关键点是 **GraphQL 默认不包含认证机制**。开发者有责任实施这些安全措施。没有适当的认证,GraphQL 端点可能会将敏感信息暴露给未认证的用户,构成重大安全风险。
|
||||
|
||||
### 目录暴力攻击和 GraphQL
|
||||
|
||||
@ -45,7 +45,7 @@ Graphql 通常支持 **GET**、**POST** (x-www-form-urlencoded) 和 **POST**(jso
|
||||
```bash
|
||||
query={__schema{types{name,fields{name}}}}
|
||||
```
|
||||
使用此查询,您将找到所有正在使用的类型的名称:
|
||||
通过此查询,您将找到所有正在使用的类型的名称:
|
||||
|
||||
.png>)
|
||||
```bash
|
||||
@ -57,7 +57,7 @@ query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofTy
|
||||
|
||||
**错误**
|
||||
|
||||
了解**错误**是否会被**显示**是很有趣的,因为它们将提供有用的**信息。**
|
||||
了解 **错误** 是否会被 **显示** 是很有趣的,因为它们将提供有用的 **信息。**
|
||||
```
|
||||
?query={__schema}
|
||||
?query={}
|
||||
@ -68,7 +68,7 @@ query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofTy
|
||||
**通过自省枚举数据库模式**
|
||||
|
||||
> [!NOTE]
|
||||
> 如果启用了自省但上述查询无法运行,请尝试从查询结构中删除 `onOperation`、`onFragment` 和 `onField` 指令。
|
||||
> 如果启用了自省但上述查询未运行,请尝试从查询结构中删除 `onOperation`、`onFragment` 和 `onField` 指令。
|
||||
```bash
|
||||
#Full introspection query
|
||||
|
||||
@ -172,7 +172,7 @@ name
|
||||
|
||||
现在我们知道数据库中保存了哪种信息,让我们尝试 **提取一些值**。
|
||||
|
||||
在自省中,您可以找到 **可以直接查询的对象**(因为您不能仅仅因为对象存在就查询它)。在下图中,您可以看到 "_queryType_" 被称为 "_Query_",而 "_Query_" 对象的一个字段是 "_flags_",这也是一种对象类型。因此,您可以查询标志对象。
|
||||
在自省中,您可以找到 **可以直接查询的对象**(因为您不能仅仅因为对象存在就查询它)。在下面的图像中,您可以看到 "_queryType_" 被称为 "_Query_",而 "_Query_" 对象的一个字段是 "_flags_",这也是一种对象类型。因此,您可以查询标志对象。
|
||||
|
||||

|
||||
|
||||
@ -202,9 +202,9 @@ query = { hiddenFlags }
|
||||
.png>)
|
||||
|
||||
看起来它会使用类型为 _**Int**_ 的 "_**uid**_" 参数进行搜索。\
|
||||
无论如何,我们已经知道,在 [Basic Enumeration](graphql.md#basic-enumeration) 部分,提出了一个查询,显示了所有所需的信息:`query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}`
|
||||
无论如何,我们已经知道,在 [Basic Enumeration](graphql.md#basic-enumeration) 部分提出了一个查询,显示了所有所需的信息:`query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}`
|
||||
|
||||
如果你阅读提供的图像,当我运行该查询时,你会看到 "_**user**_" 有一个类型为 _Int_ 的 **arg** "_**uid**_"。
|
||||
如果你阅读提供的图像,当我运行那个查询时,你会看到 "_**user**_" 有一个类型为 _Int_ 的 **arg** "_**uid**_"。
|
||||
|
||||
因此,通过一些轻量级的 _**uid**_ 暴力破解,我发现 _**uid**=**1** 时检索到了一个用户名和密码:\
|
||||
`query={user(uid:1){user,password}}`
|
||||
@ -219,11 +219,11 @@ query = { hiddenFlags }
|
||||
|
||||
**查询字符串转储技巧(感谢 @BinaryShadow\_)**
|
||||
|
||||
如果你可以通过字符串类型进行搜索,例如:`query={theusers(description: ""){username,password}}`,并且你**搜索一个空字符串**,它将**转储所有数据**。 (_注意这个例子与教程的例子无关,对于这个例子假设你可以通过一个名为 "**description**" 的字符串字段使用 "**theusers**" 进行搜索_).
|
||||
如果你可以通过字符串类型进行搜索,例如:`query={theusers(description: ""){username,password}}`,并且你**搜索一个空字符串**,它将**转储所有数据**。 (_注意这个例子与教程的例子无关,对于这个例子假设你可以通过一个名为 "**description**" 的字符串字段使用 "**theusers**" 进行搜索_)。
|
||||
|
||||
### 搜索
|
||||
|
||||
在这个设置中,一个**数据库**包含**人员**和**电影**。**人员**通过他们的**电子邮件**和**姓名**进行识别;**电影**通过它们的**名称**和**评分**进行识别。**人员**可以互为朋友,并且也有电影,表示数据库中的关系。
|
||||
在这个设置中,一个**数据库**包含**人员**和**电影**。**人员**通过他们的**电子邮件**和**姓名**进行识别;**电影**通过它们的**名称**和**评分**进行识别。**人员**可以互为朋友,也可以拥有电影,表示数据库中的关系。
|
||||
|
||||
你可以通过**姓名**搜索人员并获取他们的电子邮件:
|
||||
```javascript
|
||||
@ -283,15 +283,15 @@ name
|
||||
```
|
||||
### Mutations
|
||||
|
||||
**变更用于在服务器端进行更改。**
|
||||
**Mutations用于在服务器端进行更改。**
|
||||
|
||||
在 **introspection** 中,您可以找到 **声明的** **变更**。在下图中,"_MutationType_" 被称为 "_Mutation_",而 "_Mutation_" 对象包含变更的名称(在本例中为 "_addPerson_"):
|
||||
在**introspection**中,您可以找到**声明的** **mutations**。在下图中,"_MutationType_"被称为"_Mutation_",而"_Mutation_"对象包含了mutations的名称(在本例中为"_addPerson_"):
|
||||
|
||||
.png>)
|
||||
|
||||
在此设置中,**数据库** 包含 **人员** 和 **电影**。**人员** 通过他们的 **电子邮件** 和 **姓名** 进行识别;**电影** 通过它们的 **名称** 和 **评分** 进行识别。**人员** 可以互为朋友,并且也可以拥有电影,表示数据库中的关系。
|
||||
在此设置中,**数据库**包含**人员**和**电影**。**人员**通过其**电子邮件**和**姓名**进行识别;**电影**通过其**名称**和**评分**进行识别。**人员**可以互为朋友,并且也可以拥有电影,表示数据库中的关系。
|
||||
|
||||
一个 **在数据库中创建新** 电影的变更可以如下所示(在此示例中,变更被称为 `addMovie`):
|
||||
一个**在数据库中创建新**电影的mutation可以如下所示(在此示例中,mutation被称为`addMovie`):
|
||||
```javascript
|
||||
mutation {
|
||||
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
|
||||
@ -334,7 +334,7 @@ releaseYear
|
||||
```
|
||||
### 指令重载
|
||||
|
||||
正如在[**本报告中描述的漏洞之一**](https://www.landh.tech/blog/20240304-google-hack-50000/)中所解释的,指令重载意味着调用指令甚至数百万次,以使服务器浪费操作,直到可能发生DoS攻击。
|
||||
正如在[**本报告中描述的漏洞之一**](https://www.landh.tech/blog/20240304-google-hack-50000/)中所解释的,指令重载意味着调用指令甚至数百万次,以使服务器浪费操作,直到可能导致拒绝服务(DoS)。
|
||||
|
||||
### 在1个API请求中批量暴力破解
|
||||
|
||||
@ -353,13 +353,13 @@ releaseYear
|
||||
|
||||
越来越多的**graphql端点正在禁用自省**。然而,当收到意外请求时,graphql抛出的错误足以让像[**clairvoyance**](https://github.com/nikitastupin/clairvoyance)这样的工具重建大部分架构。
|
||||
|
||||
此外,Burp Suite扩展[**GraphQuail**](https://github.com/forcesunseen/graphquail)扩展**观察通过Burp的GraphQL API请求**并**构建**一个内部GraphQL**架构**,每当它看到新的查询时。它还可以为GraphiQL和Voyager公开架构。当收到自省查询时,该扩展返回一个假响应。因此,GraphQuail显示了API中可用的所有查询、参数和字段。有关更多信息,[**请查看此处**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema)。
|
||||
此外,Burp Suite扩展[**GraphQuail**](https://github.com/forcesunseen/graphquail) **观察通过Burp的GraphQL API请求**并**构建**一个内部GraphQL **架构**,每当它看到新的查询时。它还可以为GraphiQL和Voyager公开架构。当收到自省查询时,该扩展返回一个假响应。因此,GraphQuail显示了API中可用的所有查询、参数和字段。有关更多信息,[**请查看此处**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema)。
|
||||
|
||||
一个很好的**词表**可以在这里发现[**GraphQL实体**](https://github.com/Escape-Technologies/graphql-wordlist?)。
|
||||
|
||||
### 绕过GraphQL自省防御 <a href="#bypassing-graphql-introspection-defences" id="bypassing-graphql-introspection-defences"></a>
|
||||
|
||||
为了绕过API中对自省查询的限制,在`__schema`关键字后插入**特殊字符**被证明是有效的。这种方法利用了开发人员在试图通过关注`__schema`关键字来阻止自省时常见的正则表达式模式的疏忽。通过添加像**空格、换行符和逗号**这样的字符,GraphQL会忽略这些字符,但正则表达式可能没有考虑到,从而可以绕过限制。例如,在`__schema`后面带有换行符的自省查询可能会绕过这样的防御:
|
||||
为了绕过API中对自省查询的限制,在`__schema`关键字后插入**特殊字符**被证明是有效的。这种方法利用了开发人员在试图通过关注`__schema`关键字来阻止自省时在正则表达式模式中的常见疏忽。通过添加像**空格、换行符和逗号**这样的字符,GraphQL会忽略这些字符,但正则表达式可能没有考虑到,从而可以绕过限制。例如,在`__schema`后面带有换行符的自省查询可能会绕过这样的防御:
|
||||
```bash
|
||||
# Example with newline to bypass
|
||||
{
|
||||
@ -413,7 +413,7 @@ file:* query
|
||||
|
||||
在外面,你将能够找到几个 **未配置 CSRF 令牌的** GraphQL 端点。
|
||||
|
||||
请注意,GraphQL 请求通常通过使用内容类型 **`application/json`** 的 POST 请求发送。
|
||||
请注意,GraphQL 请求通常通过使用 Content-Type **`application/json`** 的 POST 请求发送。
|
||||
```javascript
|
||||
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
|
||||
```
|
||||
@ -433,7 +433,7 @@ query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
|
||||
|
||||
## GraphQL 中的跨站 WebSocket 劫持
|
||||
|
||||
类似于利用 GraphQL 的 CRSF 漏洞,也可以执行 **跨站 WebSocket 劫持以利用未保护的 cookie 进行 GraphQL 身份验证**,并使用户在 GraphQL 中执行意外操作。
|
||||
类似于利用 GraphQL 的 CRSF 漏洞,也可以执行 **跨站 WebSocket 劫持以利用未保护 cookie 的 GraphQL 身份验证**,并使用户在 GraphQL 中执行意外操作。
|
||||
|
||||
有关更多信息,请查看:
|
||||
|
||||
@ -459,17 +459,17 @@ query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
|
||||
|
||||
[将查询链接](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln)在一起可以绕过一个弱认证系统。
|
||||
|
||||
在下面的示例中,您可以看到操作是 "forgotPassword",并且它应该只执行与之相关的 forgotPassword 查询。通过在末尾添加一个查询可以绕过这一点,在这种情况下,我们添加 "register" 和一个用户变量,以便系统注册为新用户。
|
||||
在下面的示例中,您可以看到操作是“forgotPassword”,并且它应该只执行与之关联的 forgotPassword 查询。通过在末尾添加一个查询可以绕过这一点,在这种情况下,我们添加“register”和一个用户变量,以便系统注册为新用户。
|
||||
|
||||
<figure><img src="../../images/GraphQLAuthBypassMethod.PNG" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
## 使用 GraphQL 中的别名绕过速率限制
|
||||
|
||||
在 GraphQL 中,别名是一个强大的功能,允许在进行 API 请求时**明确命名属性**。这个功能对于在单个请求中检索**同一类型**对象的**多个实例**特别有用。别名可以用来克服 GraphQL 对象不能有多个同名属性的限制。
|
||||
在 GraphQL 中,别名是一个强大的功能,允许在进行 API 请求时**明确命名属性**。这个功能对于在单个请求中检索**同一类型对象的多个实例**特别有用。别名可以用来克服 GraphQL 对象不能具有多个同名属性的限制。
|
||||
|
||||
要详细了解 GraphQL 别名,推荐以下资源:[Aliases](https://portswigger.net/web-security/graphql/what-is-graphql#aliases)。
|
||||
|
||||
虽然别名的主要目的是减少多个 API 调用的必要性,但已识别出一个意外的用例,其中别名可以被用来对 GraphQL 端点执行暴力攻击。这是可能的,因为某些端点受到速率限制器的保护,旨在通过限制**HTTP 请求的数量**来阻止暴力攻击。然而,这些速率限制器可能没有考虑到每个请求中的操作数量。鉴于别名允许在单个 HTTP 请求中包含多个查询,它们可以绕过此类速率限制措施。
|
||||
虽然别名的主要目的是减少大量 API 调用的必要性,但已识别出一个意外的用例,其中别名可以被利用来对 GraphQL 端点执行暴力攻击。这是可能的,因为某些端点受到速率限制器的保护,旨在通过限制**HTTP 请求的数量**来阻止暴力攻击。然而,这些速率限制器可能没有考虑到每个请求中的操作数量。鉴于别名允许在单个 HTTP 请求中包含多个查询,因此可以绕过此类速率限制措施。
|
||||
|
||||
考虑下面提供的示例,它说明了如何使用别名查询来验证商店折扣代码的有效性。这种方法可以绕过速率限制,因为它将多个查询编译成一个 HTTP 请求,可能允许同时验证多个折扣代码。
|
||||
```bash
|
||||
@ -490,7 +490,7 @@ valid
|
||||
|
||||
### Alias Overloading
|
||||
|
||||
**Alias Overloading** 是一种 GraphQL 漏洞,攻击者通过为同一字段过载查询,使用多个别名,导致后端解析器重复执行该字段。这可能会使服务器资源过载,从而导致 **Denial of Service (DoS)**。例如,在下面的查询中,同一字段 (`expensiveField`) 被请求了 1,000 次,使用别名,迫使后端计算 1,000 次,可能会耗尽 CPU 或内存:
|
||||
**Alias Overloading** 是一种 GraphQL 漏洞,攻击者通过为同一字段重载查询中的多个别名,导致后端解析器重复执行该字段。这可能会使服务器资源过载,从而导致 **Denial of Service (DoS)**。例如,在下面的查询中,同一字段 (`expensiveField`) 被请求了 1,000 次,使用别名强迫后端计算 1,000 次,可能会耗尽 CPU 或内存:
|
||||
```graphql
|
||||
# Test provided by https://github.com/dolevf/graphql-cop
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
@ -509,11 +509,11 @@ curl -X POST -H "User-Agent: graphql-cop/1.13" \
|
||||
-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'
|
||||
```
|
||||
在这个例子中,10个不同的查询被批量处理成一个请求,迫使服务器同时执行所有查询。如果利用更大的批量大小或计算开销大的查询,这可能会使服务器过载。
|
||||
在这个例子中,10个不同的查询被批量处理为一个请求,迫使服务器同时执行所有查询。如果利用更大的批量大小或计算开销大的查询,这可能会使服务器过载。
|
||||
|
||||
### **指令过载漏洞**
|
||||
|
||||
**指令过载**发生在GraphQL服务器允许带有过多重复指令的查询时。这可能会使服务器的解析器和执行器不堪重负,特别是当服务器反复处理相同的指令逻辑时。如果没有适当的验证或限制,攻击者可以通过构造带有大量重复指令的查询来利用这一点,从而触发高计算或内存使用,导致**服务拒绝(DoS)**。
|
||||
**指令过载**发生在GraphQL服务器允许带有过多重复指令的查询时。这可能会使服务器的解析器和执行器不堪重负,特别是当服务器反复处理相同的指令逻辑时。如果没有适当的验证或限制,攻击者可以通过构造一个包含大量重复指令的查询来利用这一点,从而触发高计算或内存使用,导致**服务拒绝(DoS)**。
|
||||
```bash
|
||||
# Test provided by https://github.com/dolevf/graphql-cop
|
||||
curl -X POST -H "User-Agent: graphql-cop/1.13" \
|
||||
@ -521,7 +521,7 @@ curl -X POST -H "User-Agent: graphql-cop/1.13" \
|
||||
-d '{"query": "query cop { __typename @aa@aa@aa@aa@aa@aa@aa@aa@aa@aa }", "operationName": "cop"}' \
|
||||
'https://example.com/graphql'
|
||||
```
|
||||
请注意,在前面的示例中,`@aa` 是一个**可能未声明**的自定义指令。通常存在的一个常见指令是**`@include`**:
|
||||
请注意,在前面的示例中,`@aa` 是一个自定义指令,**可能未被声明**。通常存在的一个常见指令是 **`@include`**:
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
@ -554,13 +554,17 @@ curl -X POST -H "User-Agent: graphql-cop/1.13" -H "Content-Type: application/jso
|
||||
- [https://github.com/assetnote/batchql](https://github.com/assetnote/batchql): 重点进行批量GraphQL查询和变更的GraphQL安全审计脚本。
|
||||
- [https://github.com/dolevf/graphw00f](https://github.com/dolevf/graphw00f): 指纹识别正在使用的graphql
|
||||
- [https://github.com/gsmith257-cyber/GraphCrawler](https://github.com/gsmith257-cyber/GraphCrawler): 可用于抓取模式和搜索敏感数据、测试授权、暴力破解模式以及查找给定类型的路径的工具包。
|
||||
- [https://blog.doyensec.com/2020/03/26/graphql-scanner.html](https://blog.doyensec.com/2020/03/26/graphql-scanner.html): 可作为独立工具使用或[Burp扩展](https://github.com/doyensec/inql)。
|
||||
- [https://blog.doyensec.com/2020/03/26/graphql-scanner.html](https://blog.doyensec.com/2020/03/26/graphql-scanner.html): 可作为独立工具或[Burp扩展](https://github.com/doyensec/inql)使用。
|
||||
- [https://github.com/swisskyrepo/GraphQLmap](https://github.com/swisskyrepo/GraphQLmap): 也可以作为CLI客户端使用以自动化攻击:`python3 graphqlmap.py -u http://example.com/graphql --inject`
|
||||
- [https://gitlab.com/dee-see/graphql-path-enum](https://gitlab.com/dee-see/graphql-path-enum): 列出在GraphQL模式中**到达给定类型的不同方式**的工具。
|
||||
- [https://github.com/doyensec/GQLSpection](https://github.com/doyensec/GQLSpection): Standalone和CLI模式的InQL的继任者
|
||||
- [https://github.com/doyensec/inql](https://github.com/doyensec/inql): 用于高级GraphQL测试的Burp扩展或python脚本。_**扫描器**_是InQL v5.0的核心,您可以分析GraphQL端点或本地自省模式文件。它自动生成所有可能的查询和变更,并将其组织成结构化视图以供分析。_**攻击者**_组件允许您运行批量GraphQL攻击,这对于绕过实现不佳的速率限制非常有用:`python3 inql.py -t http://example.com/graphql -o output.json`
|
||||
- [https://github.com/nikitastupin/clairvoyance](https://github.com/nikitastupin/clairvoyance): 尝试通过使用一些Graphql数据库的帮助,即使在禁用自省的情况下也获取模式,这些数据库将建议变更和参数的名称。
|
||||
|
||||
### 利用常见漏洞的脚本
|
||||
|
||||
- [https://github.com/reycotallo98/pentestScripts/tree/main/GraphQLDoS](https://github.com/reycotallo98/pentestScripts/tree/main/GraphQLDoS): 用于利用脆弱graphql环境中的拒绝服务漏洞的脚本集合。
|
||||
|
||||
### 客户端
|
||||
|
||||
- [https://github.com/graphql/graphiql](https://github.com/graphql/graphiql): GUI客户端
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user