# GraphQL

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</strong></a><strong>！</strong></summary>

支持 HackTricks 的其他方式：

* 如果您想看到您的**公司在 HackTricks 中做广告**或**下载 PDF 版的 HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 探索[**PEASS 家族**](https://opensea.io/collection/the-peass-family)，我们独家的[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或在 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)\*\* 上关注我们\*\*。
* 通过向 [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享您的黑客技巧。

</details>

## 简介

GraphQL 被**强调**为 REST API 的**高效替代方案**，提供了一种简化的方法来查询后端数据。与 REST 相比，后者通常需要跨多个端点发出多个请求以收集数据，GraphQL 可以通过**单个请求**获取所有所需信息。这种简化显著地**有利于开发人员**，减少了数据获取过程的复杂性。

## GraphQL 和安全性

随着新技术的出现，包括 GraphQL，也出现了新的安全漏洞。需要注意的一个关键点是，**GraphQL 默认不包含身份验证机制**。开发人员有责任实施这些安全措施。没有适当的身份验证，GraphQL 端点可能会向未经身份验证的用户暴露敏感信息，构成重大安全风险。

### 目录暴力攻击和 GraphQL

为了识别暴露的 GraphQL 实例，建议在目录暴力攻击中包含特定路径。这些路径包括：

* `/graphql`
* `/graphiql`
* `/graphql.php`
* `/graphql/console`
* `/api`
* `/api/graphql`
* `/graphql/api`
* `/graphql/graphql`

识别开放的 GraphQL 实例允许检查支持的查询。这对于了解通过端点访问的数据至关重要。GraphQL 的内省系统通过详细说明模式支持的查询来实现这一点。有关更多信息，请参考 GraphQL 关于内省的文档：[**GraphQL：用于 API 的查询语言。**](https://graphql.org/learn/introspection/)

### 指纹

工具 [**graphw00f**](https://github.com/dolevf/graphw00f) 能够检测服务器中使用的 GraphQL 引擎，然后为安全审计人员提供一些有用信息。

#### 通用查询 <a href="#universal-queries" id="universal-queries"></a>

要检查 URL 是否是 GraphQL 服务，可以发送一个**通用查询** `query{__typename}`。如果响应包含 `{"data": {"__typename": "Query"}}`，则确认该 URL 托管了一个 GraphQL 端点。此方法依赖于 GraphQL 的 `__typename` 字段，该字段显示了查询对象的类型。

```javascript
query{__typename}
```

### 基本枚举

GraphQL通常支持**GET**，**POST**（x-www-form-urlencoded）和**POST**（json）。尽管出于安全考虑，建议仅允许json以防止CSRF攻击。

#### 自省

要使用自省来发现模式信息，请查询`__schema`字段。此字段在所有查询的根类型上都可用。

```bash
query={__schema{types{name,fields{name}}}}
```

使用此查询，您将找到正在使用的所有类型的名称：

![](/files/izGoQVqmRTpQOy3hilUm)

{% code overflow="wrap" %}

```bash
query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
```

{% endcode %}

使用此查询，您可以提取所有类型、字段和参数（以及参数的类型）。这将非常有用，以了解如何查询数据库。

![](/files/15q9QhcLJW5XghAkOKj7)

**错误**

了解**错误**是否会被**显示**很有趣，因为它们将提供有用的**信息**。

```
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
```

**通过内省枚举数据库模式**

{% hint style="info" %}
如果启用了内省但上述查询无法运行，请尝试从查询结构中删除`onOperation`、`onFragment`和`onField`指令。
{% endhint %}

```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
}
}
}
}
```

内联反射查询：

```
/?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}+}
```

最后一行代码是一个GraphQL查询，将从GraphQL中转储所有元信息（对象名称、参数、类型...）

![](/files/SrADDErCMrcx5JbmdGWM)

如果启用了内省，您可以使用[**GraphQL Voyager**](https://github.com/APIs-guru/graphql-voyager)在GUI中查看所有选项。

### 查询

现在我们知道数据库中保存了哪种信息，让我们尝试**提取一些值**。

在内省中，您可以找到**可以直接查询的对象**（因为您不能仅仅因为对象存在就查询对象）。在下图中，您可以看到"*queryType*"被称为"*Query*"，而"*Query*"对象的一个字段是"*flags*"，它也是一个对象类型。因此，您可以查询flag对象。

![](/files/L0H74nW8hZvKReis6dt1)

请注意，查询"*flags*"的类型是"*Flags*"，并且此对象定义如下：

![](/files/cPejNopMA0D458epn52C)

您可以看到"*Flags*"对象由**name**和**value**组成，然后您可以使用以下查询获取所有标志的名称和值：

```javascript
query={flags{name, value}}
```

请注意，如果要查询的对象是像以下示例中的字符串这样的**基本类型**

![](/files/PyfxDEHAB8YFhKjf49kM)

您可以使用以下查询：

```javascript
query={hiddenFlags}
```

在另一个示例中，"*Query*" 类型对象内有 2 个对象："*user*" 和 "*users*"。\
如果这些对象不需要任何参数来搜索，只需请求所需的数据即可**检索所有信息**。在这个示例中，你可以提取已保存的用户名和密码：

![](/files/AXr3J7ouXiD5DqmCxPBc)

然而，在这个示例中，如果你尝试这样做，你会收到这个**错误**：

![](/files/eANdUMxI5bBxnNXpLlhv)

看起来它会使用类型为 ***Int*** 的 "***uid***" 参数进行搜索。\
无论如何，我们已经知道，在[基本枚举](#basic-enumeration)部分提出了一个查询，显示了我们所需的所有信息：`query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}`

如果你阅读提供的图像，当我运行该查询时，你会看到 "***user***" 具有类型为 *Int* 的 **arg** "***uid***"。

因此，通过进行一些轻量级 ***uid*** 暴力破解，我发现在 ***uid**=**1*** 时检索到了一个用户名和一个密码：\
`query={user(uid:1){user,password}}`

![](/files/f6Z6KAymFCyor6PLvSlx)

请注意，我**发现**我可以请求参数 "***user***" 和 "***password***"，因为如果我尝试查找不存在的内容 (`query={user(uid:1){noExists}}`)，我会收到这个错误：

![](/files/SlEBaGDjLPzGFAeO8zln)

在**枚举阶段**期间，我发现 "***dbuser***" 对象的字段为 "***user***" 和 "***password***。

**查询字符串转储技巧（感谢 @BinaryShadow\_）**

如果你可以按字符串类型搜索，比如：`query={theusers(description: ""){username,password}}`，并且你**搜索空字符串**，它将**转储所有数据**。(*请注意，此示例与教程示例无关，对于此示例，请假设你可以使用 "**theusers**" 搜索名为 "**description**" 的 String 字段*).

### 搜索

在这个设置中，一个**数据库**包含**人员**和**电影**。**人员**由他们的**电子邮件**和**姓名**标识；**电影**由它们的**名称**和**评分**标识。**人员**可以互相成为朋友，也可以拥有电影，表示数据库内的关系。

你可以通过**姓名**搜索人员并获取他们的电子邮件：

```javascript
{
searchPerson(name: "John Doe") {
email
}
}
```

您可以通过姓名搜索人员并获取他们订阅的电影：

```javascript
{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}
```

注意如何指示检索人的`subscribedMovies`的`name`。

您还可以**同时搜索多个对象**。在这种情况下，搜索了2部电影：

```javascript
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r
```

甚至是使用别名来关联多个不同对象的关系：

```javascript
{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
}
```

### 变异

**变异用于在服务器端进行更改。**

在**内省**中，您可以找到**声明的变异**。在下面的图像中，"*MutationType*"被称为"*Mutation*"，而"*Mutation*"对象包含变异的名称（在本例中为"*addPerson*"）：

![](/files/BIm52hP9ycLuTyB1H2C1)

在这个设置中，一个**数据库**包含**人员**和**电影**。**人员**通过他们的**电子邮件**和**姓名**进行标识；**电影**通过它们的**名称**和**评分**进行标识。**人员**可以互相成为朋友，并且也可以拥有电影，表示数据库内的关系。

在数据库中**创建新的**电影的变异可以如下（在这个例子中，变异被称为`addMovie`）：

```javascript
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}
```

**注意查询中指定了数据的值和类型。**

此外，数据库支持一个名为 `addPerson` 的 **mutation** 操作，允许创建 **persons** 并将它们与现有的 **friends** 和 **movies** 关联起来。重要的是要注意，必须在将它们链接到新创建的人之前，friends 和 movies 必须在数据库中预先存在。

```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
}
}
}
}
}
}
```

### 指令过载

如[**报告中描述的一个漏洞**](https://www.landh.tech/blog/20240304-google-hack-50000/)所述，指令过载意味着调用一个指令甚至数百万次，使服务器浪费操作，直到可能对其进行拒绝服务攻击。

### 在1个API请求中批量暴力破解

这些信息来自<https://lab.wallarm.com/graphql-batching-attack/>。\
通过GraphQL API进行身份验证，**同时发送许多带有不同凭据的查询**以进行检查。这是一种经典的暴力破解攻击，但现在由于GraphQL批处理功能，可以在一个HTTP请求中发送多个登录/密码对。这种方法会欺骗外部速率监控应用程序，让其认为一切正常，没有暴力破解机器人试图猜测密码。

下面是一个应用程序身份验证请求的最简单演示，**每次同时发送3对不同的电子邮件/密码**。显然，可以以相同的方式在单个请求中发送数千个：

![](/files/CLPAAGkuHALs6QvIQnTj)

从响应截图中可以看到，第一个和第三个请求返回了 *null* 并在 *error* 部分反映了相应的信息。**第二个变异具有正确的身份验证**数据，响应具有正确的身份验证会话令牌。

![](/files/j3Y4t9Qu1xTvKLtvvLc6)

## 无需内省的GraphQL

越来越多的**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)。

一个不错的**单词列表**，用于发现[**GraphQL实体可以在这里找到**](https://github.com/Escape-Technologies/graphql-wordlist?)。

### 绕过GraphQL内省防御 <a href="#bypassing-graphql-introspection-defences" id="bypassing-graphql-introspection-defences"></a>

### **绕过GraphQL内省防御**

为了绕过API中内省查询的限制，在`__schema`关键字后插入一个**特殊字符**是有效的。这种方法利用了常见的开发人员在正则表达式模式中的疏忽，这些模式旨在通过关注`__schema`关键字来阻止内省。通过添加像**空格、换行和逗号**这样的字符，GraphQL会忽略但可能没有在正则表达式中考虑到的字符，可以规避限制。例如，一个在`__schema`后面有一个换行符的内省查询可能会绕过这种防御：

```bash
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
```

如果不成功，考虑使用**GET请求**或**带有`x-www-form-urlencoded`的POST**等替代请求方法，因为限制可能仅适用于POST请求。

### **发现暴露的GraphQL结构**

当禁用内省时，检查网站源代码中JavaScript库中预加载的查询是一种有用的策略。可以使用开发者工具中的`Sources`选项卡找到这些查询，从而深入了解API的模式并揭示可能**暴露的敏感查询**。在开发者工具中搜索的命令为：

```javascript
Inspect/Sources/"Search all files"
file:* mutation
file:* query
```

## GraphQL中的CSRF

如果你不知道什么是CSRF，请阅读以下页面：

{% content-ref url="/pages/iwet6oCz6HrmzdGbLIEn" %}
[CSRF (Cross Site Request Forgery)](/pentesting-web/csrf-cross-site-request-forgery.md)
{% endcontent-ref %}

在这里，你将能够找到一些GraphQL端点**配置没有CSRF令牌**。

请注意，GraphQL请求通常通过使用Content-Type \*\*`application/json`\*\*的POST请求发送。

```javascript
{"operationName":null,"variables":{},"query":"{\n  user {\n    firstName\n    __typename\n  }\n}\n"}
```

然而，大多数 GraphQL 端点也支持 **`form-urlencoded` POST 请求：**

```javascript
query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
```

因此，由于类似之前的 CSRF 请求是**无需预检请求**发送的，因此可能利用 CSRF 在 GraphQL 中**执行** **更改**。

但是，请注意 Chrome 的 `samesite` 标志的新默认 cookie 值为 `Lax`。这意味着该 cookie 仅在第三方网站的 GET 请求中发送。

请注意，通常也可以将**查询请求**作为**GET**请求发送，而在 GET 请求中可能不会验证 CSRF 令牌。

此外，可能利用 [**XS-Search**](/pentesting-web/xs-search.md) **攻击**从 GraphQL 端点中滥用用户凭据窃取内容。

有关更多信息，请查看[**此处的原始帖子**](https://blog.doyensec.com/2021/05/20/graphql-csrf.html)。

## GraphQL 中的授权

端点上定义的许多 GraphQL 函数可能仅检查请求者的身份验证而不检查授权。

修改查询输入变量可能导致泄露敏感帐户详细信息[leaked](https://hackerone.com/reports/792927)。

甚至可能通过修改其他帐户数据尝试接管帐户来导致变异。

```javascript
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}
```

### 绕过GraphQL授权

[链接查询](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln) 可以绕过弱授权系统。

在下面的示例中，您可以看到操作是“forgotPassword”，它应该只执行与之关联的forgotPassword查询。这可以通过在末尾添加一个查询来绕过，本例中我们添加了“register”和一个用户变量，系统将其注册为新用户。

<figure><img src="/files/dQNqvMLmN0xzhnGqSBp5" alt=""><figcaption></figcaption></figure>

## 使用GraphQL中的别名绕过速率限制

在GraphQL中，别名是一个强大的功能，允许在进行API请求时**明确命名属性**。这种能力特别适用于在单个请求中检索**同一类型的多个实例**。别名可用于克服阻止GraphQL对象具有相同名称的多个属性的限制。

建议查看有关GraphQL别名的详细理解的资源：[别名](https://portswigger.net/web-security/graphql/what-is-graphql#aliases)。

虽然别名的主要目的是减少大量API调用的必要性，但已经发现了一个意外的用例，即可以利用别名来对GraphQL端点执行暴力攻击。这是可能的，因为一些端点受到速率限制器的保护，这些限制器旨在通过限制**HTTP请求的数量**来阻止暴力攻击。然而，这些速率限制器可能不考虑每个请求中的操作数量。鉴于别名允许在单个HTTP请求中包含多个查询，它们可以规避此类速率限制措施。

考虑下面提供的示例，说明了如何使用别名查询来验证商店折扣代码的有效性。这种方法可以绕过速率限制，因为它将多个查询编译到一个HTTP请求中，从而可能允许同时验证多个折扣代码。

```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
}
}
```

## 工具

### 漏洞扫描器

* <https://github.com/gsmith257-cyber/GraphCrawler>：工具包，可用于抓取模式并搜索敏感数据，测试授权，暴力破解模式，并找到到给定类型的路径。
* <https://blog.doyensec.com/2020/03/26/graphql-scanner.html>：可作为独立工具或[Burp扩展](https://github.com/doyensec/inql)使用。
* <https://github.com/swisskyrepo/GraphQLmap>：也可作为CLI客户端用于自动化攻击。
* <https://gitlab.com/dee-see/graphql-path-enum>：列出在GraphQL模式中到达给定类型的不同方式的工具。
* <https://github.com/doyensec/inql>：用于高级GraphQL测试的Burp扩展。\_**Scanner***是InQL v5.0的核心，您可以分析GraphQL端点或本地内省模式文件。它会自动生成所有可能的查询和变更，并将它们组织成结构化视图供您分析。***Attacker**\_组件可让您运行批量GraphQL攻击，这对规避实施不当的速率限制很有用。

### 客户端

* <https://github.com/graphql/graphiql>：GUI客户端
* <https://altair.sirmuel.design/>：GUI客户端

### 自动化测试

{% embed url="<https://graphql-dashboard.herokuapp.com/>" %}

* 解释AutoGraphQL的视频：<https://www.youtube.com/watch?v=JJmufWfVvyU>

## 参考资料

* [**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)
* [**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)

<details>

<summary><strong>从零开始学习AWS黑客技术</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</strong></a><strong>！</strong></summary>

支持HackTricks的其他方式：

* 如果您想在HackTricks中看到您的**公司广告**或**下载PDF版本的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 发现[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们的独家[NFTs](https://opensea.io/collection/the-peass-family)收藏品
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**上关注**我们。
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hacktricks.xsx.tw/network-services-pentesting/pentesting-web/graphql.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
