A Primer for Testing the Security of GraphQL APIs

Whether you’re a penetration tester, security engineer, or bug bounty hunter, it can be incredibly helpful to know how to find vulnerabilities in a GraphQL API. This post will introduce you to GraphQL and its functionality from the perspective of someone performing a security assessment.

无论你是渗透测试人员、安全工程师还是 bug 赏金猎人,了解如何在 GraphQL API 中找到漏洞都是非常有帮助的。本文将从执行安全评估的角度向您介绍 GraphQL 及其功能。

The post will not focus on how to securely implement a GraphQL API, although you can extrapolate details that’ll help you in doing so. Additionally, although I will draw parallels to familiar topics like REST and SQL, other concepts may be new.

这篇文章不会关注如何安全地实现 GraphQL API,尽管您可以推断出有助于实现这一点的细节。此外,尽管我将把它与熟悉的主题(如 REST 和 SQL)进行对比,但其他概念可能是新的。

A Brief Introduction to GraphQL

GraphQL 简介

GraphQL is a specification that was developed by Facebook and later moved to the GraphQL Foundation. The high-level description from the GraphQL Foundation is:

GraphQL 是 Facebook 开发的一个规范,后来移植到 GraphQL 基金会。GraphQL 基金会的高级描述是:

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

GraphQL 是用于 api 的查询语言,也是用于使用现有数据完成这些查询的运行时。提供了 API 中数据的完整且易于理解的描述,让客户能够精确地询问他们需要什么,仅此而已,让 API 随着时间的推移更容易发展,并支持强大的开发工具。

Here is our security-relevant, high-level overview of GraphQL:

下面是我们对 GraphQL 的安全相关的高级概述:

  • Instead of multiple HTTP requests, a single HTTP request can request all the resources that are needed.
  • 单个 HTTP 请求可以请求所有需要的资源,而不是多个 HTTP 请求。
  • The query language is heavily inspired by JSON.
  • 查询语言深受 JSON 的启发。
  • The responses returned from a GraphQL API are valid JSON and can be parsed as such.
  • 从 GraphQL API 返回的响应是有效的 JSON,因此可以进行解析。
  • GraphQL is strongly typed, which reduces the attack surface from user input. However, it’s still not foolproof.
  • GraphQL 是强类型的,这减少了用户输入的攻击面,但仍然不是万无一失的。
  • GraphQL is database agnostic and can even be backed by other APIs, including other GraphQL APIs.
  • GraphQL 与数据库无关,甚至可以由其他 api (包括其他 GraphQL api)支持。
  • GraphQL APIs can be used to retrieve data (query) and modify data (mutation).
  • GraphQL api 可用于检索数据(查询)和修改数据(变异)。

GraphQL is regarded by some as an alternative to REST. There are many implementations of GraphQL engines and clients. Because the reference implementation is written in JavaScript, much of the ecosystem is also written in JavaScript, although other languages are supported as well. Most GraphQL engines do the bare minimum required by the spec and aren’t a “batteries-included” solution in the way Python’s Django may be considered. Much is left up to the developer, sort of like Python’s Flask. And just like how there are a lot of third-party addons for Flask, there’s a similar ecosystem around GraphQL. The ecosystem has much more tooling support for JavaScript GraphQL engines; if you’re testing a GraphQL API not written in JavaScript, you will need to review much more hand-crafted custom code.

一些人认为 GraphQL 是 REST 的替代品。有许多 GraphQL 引擎和客户机的实现。因为引用实现是用 JavaScript 编写的,所以很多生态系统也是用 JavaScript 编写的,尽管其他语言也受到支持。大多数 GraphQL 引擎完成了规范要求的最低要求,并且不像 Python 的 Django 那样是“包含电池”的解决方案。很多东西留给了开发者,有点像 Python 的 Flask。就像 Flask 有很多第三方插件一样,围绕 GraphQL 也有一个类似的生态系统。生态系统对 JavaScript GraphQL 引擎有更多的工具支持; 如果您正在测试一个不是用 JavaScript 编写的 GraphQL API,那么您将需要查看更多手工定制的代码。

It’s a good idea to review the Introduction to GraphQL to create familiarity. Additionally, there are public GraphQL APIs like SpaceXLand where you can get the hang of how queries work. We’ll just scratch the surface enough to get you going here.

回顾一下 GraphQL 介绍,以便熟悉它,这是一个好主意。此外,还有像 SpaceXLand 这样的公共 GraphQL api,您可以在这些 api 中了解查询的工作方式。我们只是触及表面,足以让你到这里来。

Types

类型

As mentioned earlier, GraphQL uses static types. An object type is made up of fields along with types defining what is accepted by each field.

如前所述,GraphQL 使用静态类型。对象类型由字段和定义每个字段接受内容的类型组成。

Below is an example object type called Character:

下面是一个叫做字符的对象类型的例子:

type Character {
  name: String!
  appearsIn: [Episode!]!
}
  • The field name has a type of String, and the ! following it means that it is non-nullable. It is not an optional parameter and must be a non-zero value for the structure to be valid.
  • 字段名具有 String 类型,而!跟随它意味着它不可为空。它不是一个可选参数,并且必须是一个非零值才能使结构有效。
  • The appearsIn field has an array type [] that is non-nullable and is made up of objects with the Episode type, which is also non-nullable.
  • appearsIn 字段有一个数组类型[] ,它是不可为空的,并且由使用 Episode 类型的对象组成,后者也是不可为空的。
  • Episode is a type that was defined just like Character. In this case, it is used within another type.
  • Episode 是一个类型,它的定义类似于 Character。在这种情况下,它用在另一个类型中。

In the example above, String is considered a scalar type. Eventually a field will have to resolve actual data. Scalar types represent the actual data that will be resolved, such as a string or integer. Unlike other types, like Episode, these do not have subfields. There are built-in scalar types for the most common use-cases, although custom scalar types can also be created by developers. Pay close attention to any scalar type that is custom, since custom types are more likely to have issues.

在上面的示例中,String 被认为是一种标量类型。最终,字段将不得不解析实际数据。标量类型表示将被解析的实际数据,如字符串或整数。不像其他类型,比如 Episode,它们没有子字段。尽管开发人员也可以创建自定义标量类型,但对于最常见的用例,还是有内置标量类型。密切关注自定义的任何标量类型,因为自定义类型更有可能出现问题。

Feel free to also look into enumeration types as well, just so you know that they exist.

也可以随意查看枚举类型,这样您就知道它们的存在。

Operations Types

操作类型

There are three operation types, but the first two are the ones you’ll see most often:

有三种操作类型,但前两种是你最常见的:

  • Query – operations that fetch data (analogous to REST API’s GET request)
  • 获取数据的查询操作(类似于 restapi 的 GET 请求)
  • Mutation – operations that modify data (like a POST request)
  • 变异-修改数据的操作(如 POST 请求)
  • Subscription – operations that wait for the server to update the client with data, usually over WebSockets (PubSub)
  • 等待服务器用数据更新客户端的订阅操作,通常是通过 websocket (PubSub)

Even though query is an operation type, we also refer to all requests as queries no matter what the operation type is.

即使查询是一种操作类型,我们也将所有请求称为查询,不管操作类型是什么。

Queries

查询

All GraphQL queries must include fields that you want to be returned in the response. Fields are specific pieces of data within an object like an ID, name, or address. In the following example, we are using the users query to request the name of all users:

所有 GraphQL 查询必须包含您希望在响应中返回的字段。字段是对象中的特定数据片段,如 ID、名称或地址。在下面的例子中,我们使用用户查询来请求所有用户的名字:

Request

请求

{
  users {
    name
  }
}

Response

回应

{
  "data": {
     "users": [
      {
        "name": "Carmen"
      },
      {
        "name": "Nathan"
      }
     ]
  }
}

Some queries may also accept arguments. A query similar to the one above is the singular version user, which accepts the argument id among others. As a result, we get the name of the user with a particular ID:

有些查询还可能接受参数。与上面类似的一个查询是单一版本用户,它接受参数 id 和其他用户。因此,我们得到了一个特定 ID 的用户名:

{
  user(id: "1000") {
    name
  }
}

For mutations, you might see a field like add_user, where you can pass an argument to create a new user. In this case, we wanted to return the id of the newly created user after completion:

对于变异,您可能会看到像 add _ user 这样的字段,在这里您可以传递一个参数来创建新用户。在本例中,我们希望在完成后返回新创建用户的 id:

mutation {
  add_user(name: "Palo") {
    id
  }
}

Variables

变量

So far, we’ve been passing values as arguments directly in the query, but it’s also possible to set up a query in a way similar to a prepared statement in SQL. This method allows sending the values separately.

到目前为止,我们一直直接在查询中传递值作为参数,但是也可以以类似于 SQL 中的预处理语句的方式设置查询。此方法允许分别发送值。

Let’s take the previous example and pass the name “Palo” as a variable.

让我们以前面的例子为例,将名称“ Palo”作为变量传递。

Query

查询

mutation anything($name: String!){
  add_user(name: $name) {
    id
  }
}

Variables

变量

{"name": "Palo"}

The query and variables will be submitted to the GraphQL API in the same request, but are sent as separate parameters.

查询和变量将在同一个请求中提交给 GraphQL API,但是作为单独的参数发送。

Fragments

碎片

You will probably see queries that contain ... in them. Those are fragments. Fragments are used to simplify the reuse of a set of fields. You can define the set of fields and use them as a fragment throughout your queries. Although fragments are good to understand, queries can always be created without them.

您可能会看到查询中包含… … 。那些都是碎片。使用片段可以简化一组字段的重用。您可以定义字段集,并在整个查询中将它们作为片段使用。尽管片段很容易理解,但是查询总是可以在没有片段的情况下创建。

GraphQL API Interaction

相互作用

So how do we talk to a GraphQL API? Well, it happens over HTTP, and all interactions are done through POST requests against a single endpoint like https://example.com/graphql. What changes between requests is the query and variables parameters sent in the request. The endpoint remains the same; only the request body changes.

那么我们如何与 GraphQL API 对话呢?这是通过 HTTP 发生的,所有的交互都是通过 POST 请求来完成的,对象是一个单一的端点,比如 https://example.com/graphql。请求之间的更改是请求中发送的查询和变量参数。端点保持不变; 只有请求正文发生变化。

Here is an example of a GraphQL API HTTP request and response:

下面是一个 GraphQL API HTTP 请求和响应的例子:

Request

请求

POST /graphql HTTP/1.1
Host: example.com
...
Content-Type: application/json
Connection: close

{"query":"{\n  capsules {\n    id\n  }\n}\n","variables":null}

Response

回应

HTTP/1.1 200 OK
...
Content-Type: application/json

{"data":{"capsules":[{"id":"C105"},{"id":"C101"},{"id":"C109"},{"id":"C110"},{"id":"C106"},{"id":"C102"},{"id":"C205"},{"id":"C103"},{"id":"C201"},{"id":"C104"},{"id":"C111"},{"id":"C113"},{"id":"C108"},{"id":"C107"},{"id":"C112"},{"id":"C206"},{"id":"C203"},{"id":"C202"},{"id":"C204"}]}}

This is a pretty basic query, but as the queries and responses get larger it becomes a pain to work with manually. When it comes time to constructing queries, you are going to want to use a tool like GraphiQL or Altair. It’s similar to working with Postman for REST APIs (which also now has GraphQL support!). Be sure to also check if the API is already hosting a GraphQL console/explorer, which means you don’t even have to bring your own tools (we’ll talk more about this later).

这是一个非常基本的查询,但是随着查询和响应的增加,手动处理变得非常痛苦。当需要构造查询时,您需要使用一个工具,比如 GraphiQL 或 Altair。它类似于使用 Postman for REST api (它现在也支持 GraphQL!).确保还要检查 API 是否已经托管了 GraphQL 控制台/资源管理器,这意味着您甚至不必带上自己的工具(稍后将详细讨论)。

As a note, API requests are not limited to POST requests or even required to be JSON encoded. The query can be passed as parameters in a GET request or even as URL-encoded form data in a POST request. All of this depends on the implementation, and you should definitely explore to see what is available. The following requests are some examples of what the GraphQL API may accept:

注意,API 请求不仅限于 POST 请求,甚至也不需要 JSON 编码。查询可以在 GET 请求中作为参数传递,甚至可以在 POST 请求中作为 url 编码的表单数据传递。所有这些都取决于实现,您肯定应该探索看看有什么是可用的。下面的请求是 GraphQL API 可能接受的一些例子:

GET (query parameters)

GET (查询参数)

GET /graphql?query=%7B%0A++capsules+%7B%0A++++id%0A++%7D%0A%7D%0A&variables%5Bvariable1%5D=example HTTP/1.1
...
Connection: close

POST (URL encoded body)

POST (URL 编码体)

POST /graphql HTTP/1.1
...
Content-Type: application/x-www-form-urlencoded
Connection: close

query=%7B%0A++capsules+%7B%0A++++id%0A++%7D%0A%7D%0A&variables%5Bvariable1%5D=example

POST (form data)

POST (表格数据)

POST /graphql HTTP/1.1
...
Content-Type: multipart/form-data, boundary=---------------------------kanbvfbnmt
Connection: close

-----------------------------kanbvfbnmt
Content-Disposition: form-data; name="query"

{
  capsules {
    id
  }
}

-----------------------------kanbvfbnmt
Content-Disposition: form-data; name="variables[variable1]"

example
-----------------------------kanbvfbnmt--

Discovery

发现

A GraphQL schema or a working client is important to have. Think of a schema as API documentation generated and used by tools like Swagger or Postman; it provides type definitions, and GraphQL is statically typed, remember? Without this, you won’t know which queries you can make (unless you observe client-generated traffic).

一个 GraphQL 模式或一个正在工作的客户机非常重要。可以将模式看作是由 Swagger 或 Postman 等工具生成和使用的 API 文档; 它提供类型定义,而 GraphQL 是静态类型的,记得吗?否则,您将不知道可以进行哪些查询(除非您观察到客户端生成的流量)。

Introspection is Enabled

启用自省

An introspection query is a special query you can make against a GraphQL API that returns information about which queries it supports. A very basic introspection query is shown below:

自省查询是一种特殊的查询,您可以对返回关于它支持哪些查询的信息的 GraphQL API 进行查询。下面是一个非常基本的自省查询:

Request

请求

{
  __schema {
    types {
      name
    }
  }
}

Response

回应

{
  "data": {
    "__schema": {
      "types": [
        ...
        {
          "name": "Location"
        },
        {
          "name": "LaunchFind"
        },
        {
          "name": "LaunchesPastResult"
        },
        {
          "name": "Launchpad"
        },
        {
          "name": "MissionsFind"
        },
        {
          "name": "Mission"
        },
        {
          "name": "MissionResult"
        },
        {
          "name": "PayloadsFind"
        },
        {
          "name": "Roadster"
        },
        ...
      ]
    }
  }
}

However, you probably want to know more than just the names of the types available. The full query below can be used to get a lot more details:

但是,您可能想知道的不仅仅是可用类型的名称。下面的完整查询可以用来获得更多的细节:

query IntrospectionQuery {
      __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
                  }
                }
              }
            }
          }
        }
      }
    }

If you get a response to an introspection query, you are halfway there. You will have the schema and can learn what is possible to do with the GraphQL API. This is usually enabled by default in most GraphQL implementations, and it often stays enabled for APIs intended for public consumption. An introspection query is sent automatically by GraphQL tools (like GraphiQL) to have the documented API ready for you.

如果您得到了对自省查询的响应,那么您已经完成了一半。您将拥有这个模式,并且可以了解使用 GraphQL API 可以做什么。在大多数 GraphQL 实现中,这通常是默认启用的,并且对于公共使用的 api,它通常保持启用状态。自省查询是由 GraphQL 工具(如 grahiql)自动发送的,以便为您准备好文档化的 API。

Introspection is Disabled

自省是残疾的

If introspection is disabled, you are not at the end of the road! You still have options. Let’s talk about what you can do:

如果内省是残疾的,你不是在路的尽头!你还有选择。让我们来谈谈你能做什么:

  1. If you have access to source code, you may have access to a file that contains a schema defined using schema definition language (SDL). With this file, you have the entire schema in human-readable form, which can easily be processed by other tools. On the other hand, a schema that is defined programmatically is not easily consumable by other tools and can be more difficult to use.

    如果可以访问源代码,则可以访问包含使用模式定义语言(SDL)定义的模式的文件。有了这个文件,您就拥有了人类可读形式的整个模式,可以很容易地被其他工具处理。另一方面,以编程方式定义的模式不容易被其他工具使用,而且可能更难使用。

  2. If you have access to the client-side source code (like a mobile app or JavaScript), then you can learn a lot about the queries implemented there as well. This requires more manual work and can be tedious. How long it will take to get useful information depends on whether the source code has been compiled, transpiled, obfuscated, and/or minified.

    如果您可以访问客户端的源代码(比如移动应用程序或 JavaScript) ,那么您也可以了解很多关于在其中实现的查询的信息。这需要更多的体力劳动,并且可能是乏味的。需要多长时间才能获得有用的信息取决于源代码是否已经编译、透露、混淆和/或缩小。

  3. Reversing client-side code doesn’t sound like fun? Well, just like when you don’t have API documentation, you could still observe traffic from the client and see which queries are made. However, this process makes it hard to see the big picture of what is available to you since you have to go through every request to understand how everything is connected.

    反向客户端代码听起来不好玩吗?就像没有 API 文档一样,您仍然可以观察来自客户端的流量,并查看发出了哪些查询。然而,这个过程使你很难看到什么是可用的,因为你必须通过每一个请求来理解所有的事情是如何连接的。

  4. If you don’t have access to a client or maybe you think there are additional queries that were not sent by the client, the last resort is brute-forcing. This is made much more effective through tools like clairvoyance or clairvoyancex, which use information leakage and helpful autocomplete features from GraphQL APIs to help build a schema. Although you may not build the complete schema through this method, you will have much more than you did before.

    如果您没有访问客户机的权限,或者您认为还有其他查询没有被客户机发送,那么最后的办法就是强制执行。通过诸如千里眼或千里眼之类的工具,这种方法变得更加有效,这些工具使用信息泄露和 GraphQL api 中有用的自动完成特性来帮助构建模式。尽管您可能无法通过此方法构建完整的模式,但您将拥有比以前更多的内容。

Visualization

可视化

Once you have the schema, you can really start digging into the API. Tools like Voyager are great for visualizing the schema and give you an idea of what you can do:

一旦有了模式,就可以开始深入研究 API 了。像 Voyager 这样的工具非常适合可视化模式,并且能让你知道你能做什么:

With this visualization, you can start coming up with a plan of attack to make sure you get coverage of everything as different roles, users, or organizations. Unfortunately, there isn’t much automation for this at the moment except for tools that already exist like AuthMatrix. Although they are not intended specifically for GraphQL, they can still be set up with HTTP requests containing a GraphQL query.

通过这个可视化,您可以开始制定一个攻击计划,以确保能够覆盖不同角色、用户或组织的所有内容。不幸的是,除了像 AuthMatrix 这样已经存在的工具之外,目前还没有多少自动化的工具。尽管它们并不是专门针对 GraphQL 的,但是仍然可以使用包含 GraphQL 查询的 HTTP 请求来设置它们。

Vulnerabilities

漏洞

As with every new technology, a lot of vulnerabilities that affect GraphQL are reincarnations of known issue types. This list is not exhaustive, but it includes things you should definitely look for:

与每一项新技术一样,许多影响 GraphQL 的漏洞都是已知问题类型的化身。这个列表并不是详尽无遗的,但是它包含了一些你绝对应该去寻找的东西:

Authentication and Authorization

认证和授权

  • In GraphQL there is a concept of a query context, which can be populated with user data for that request and then used for authorization checks. Depending on anything outside of this query context is asking for trouble. Determine how the GraphQL API is authenticating you as a user and whether details about you and your level of access are based on a session.

    在 GraphQL 中有一个查询上下文的概念,它可以用该请求的用户数据填充,然后用于授权检查。根据这个查询上下文之外的任何东西都是自找麻烦。确定 GraphQL API 如何对您进行用户身份验证,以及关于您和您的访问级别的详细信息是否基于会话。

  • Authorization controls should be placed in the business logic layer (although many times it just gets tacked on somewhere else). Many GraphQL APIs aren’t built from the ground up, but instead ported from existing APIs. This causes developers to get “creative” when adding or migrating authorization controls to a GraphQL API.

    授权控制应该放在业务逻辑层(尽管很多时候它只是在其他地方附加)。许多 GraphQL api 不是从头开始构建的,而是从现有的 api 中移植的。这使得开发人员在向 GraphQL API 添加或迁移授权控件时获得“创造性”。

  • Authorization should be handled by nodes and not as part of accessing an edge. The figure below shows a simple graph with user nodes and a post node, which is something you may see in a very basic social media site. The lines between the nodes represent relationships and are called edges. In GraphQL, when a field within a node references another node, that relationship is called an edge.

    授权应该由节点处理,而不是作为访问边缘的一部分。下面的图显示了一个简单的用户节点图和一个 post 节点图,这是你可以在一个非常基本的社交媒体网站上看到的。节点之间的线表示关系,称为边。在 GraphQL 中,当一个节点中的字段引用另一个节点时,这种关系称为边。

A user may have a field called AuthoredPosts, which represents all the different post nodes that the author created. Each of those post nodes would have an author field that represents the author that created that post.

用户可能有一个名为 authorredposts 的字段,该字段表示作者创建的所有不同的发布节点。每个帖子节点都有一个 author 字段,代表创建帖子的作者。

If a post is intended to be available only to friends of the author, the API might have an authorization check in the post node. The API can validate that the user trying to interact with the post is a friend of the author. But what if the check is instead performed upon accessing the author edge from a user node? This would prevent a user from accessing the post, but the user may still be able to like the post even if they are not a friend. Since the authorization check isn’t performed in the post node, an additional check for liking the post may have been forgotten. It gets tricky trying to track all the different authorization checks when performing them on edges.

如果一篇文章仅对作者的朋友可用,那么 API 可能在文章节点中有一个授权检查。该 API 可以验证试图与帖子交互的用户是作者的朋友。但是如果检查是在从用户节点访问作者边缘时执行的呢?这样可以防止用户访问帖子,但是即使他们不是好友,用户仍然可以喜欢这篇帖子。由于授权检查没有在 post 节点中执行,因此可能会忘记对 post 进行额外的点赞检查。在边缘上执行所有不同的授权检查时,跟踪这些检查是很棘手的。

Because there are usually different paths to getting to a node, you (as the tester) should check all the paths to a node in the case that authorization checks are performed on an edge and the check is missing. Voyager, a tool mentioned earlier, will help with figuring out those paths in a visual manner.

因为到达一个节点通常有不同的路径,所以您(作为测试人员)应该检查到达一个节点的所有路径,以防在边上执行授权检查而检查不到。“旅行者”是前面提到的一个工具,它将以可视化的方式帮助确定这些路径。

  • Not all fields may be intended to be accessible, even if it’s for your own user object. You don’t want users to be able to suddenly change their user role to become a super admin of the entire application. Try adding fields to a query or mutation and see if you are able to do something unintended. Also, compare fields between different roles to find new fields you didn’t know existed.

    并不是所有的字段都可以被访问,即使是针对您自己的用户对象。您不希望用户能够突然改变他们的用户角色,成为整个应用程序的超级管理员。尝试向查询或变异添加字段,看看是否能够做一些无意识的操作。此外,比较不同角色之间的字段,找到你不知道存在的新字段。

  • When integrating a GraphQL API with systems that implement their own authorization (another REST API), mistakes can be made when translating this access between services. Caching may also reveal data from other users.

    当将 GraphQL API 与实现自己授权的系统(另一个 REST API)集成时,在服务之间转换这种访问时可能会出错。缓存还可以显示来自其他用户的数据。

  • Some GraphQL engines will include a node or nodes field automatically. If these are present, be sure to check whether you can access something you’re not meant to have access to.

    一些 GraphQL 引擎将自动包含一个节点或节点字段。如果这些都存在,一定要检查你是否可以访问一些你不想访问的东西。

Mislabeled Operation Type

标记错误的操作类型

When compared to a REST API, a query operation type is like a GET request and a mutation operation type is like a POST request. We should expect that a query will not be used for state changes and will only be done as a mutation and vice-versa. This may not always be the case, and you may see operation types misused. The operation name will often be a dead giveaway as to whether it’s a state-changing query. Why is it an issue to misuse operation types? It causes confusion, and it also improves an attacker’s chances of achieving cross-site request forgery, which is mentioned later.

与 REST API 相比,查询操作类型类似于 GET 请求,而变异操作类型类似于 POST 请求。我们应该预期查询不会用于状态更改,只会作为变异进行,反之亦然。并非总是如此,您可能会看到操作类型被滥用。操作名称通常会暴露出它是否是一个状态更改的查询。为什么误用操作类型是一个问题?它会引起混淆,同时也提高了攻击者实现跨站请求伪造攻击的几率,这一点后面会提到。

Input Validation

输入验证

In addition to the built-in scalar types, custom scalars can be created and used in GraphQL. These custom scalars may not have had as many eyes on them, so hit these extra hard with some fuzzing. Make sure that they do the following:

除了内置标量类型之外,还可以在 GraphQL 中创建和使用自定义标量。这些定制标量可能没有那么多的眼睛看着他们,所以这些额外的努力与一些模糊。确保他们做到以下几点:

  • Restrict the input to proper character sets
  • 将输入限制为适当的字符集
  • Enforce integer ranges 实施整数范围
  • Handle null values, etc. 处理空值等等

If a custom scalar type is being used to encapsulate other complicated types like JSON or XML, this is an area you should focus on. It’s very likely that the contents in the encapsulated type are not being validated, which could lead to vulnerabilities.

如果使用自定义标量类型封装其他复杂类型(如 JSON 或 XML) ,则应该关注这一领域。很可能没有对封装类型中的内容进行验证,这可能会导致漏洞。

GraphQL is database agnostic and can be backed by a NoSQL database (MongoDB, Couchbase), relational database (MySQL, PostgreSQL), or even another API. Injections in these back-end systems can still occur whether it’s through type juggling or lax scalar types. Be sure to look for server-side errors when injecting (no)SQL or JSON syntax within queries. The more knowledge you have on the back ends behind a GraphQL API, the better. For example, if you have REST API calls made in the background with data you send to a GraphQL API, then you can try to inject extra parameters, get path traversal, or even perform server-side request forgery. There’s a lot of funky stuff that could be happening behind the scenes.

GraphQL 与数据库无关,可以由 NoSQL 数据库(MongoDB、 Couchbase)、关系数据库数据库(MySQL、 PostgreSQL)甚至另一个 API 进行支持。无论是通过类型变换还是 lax 标量类型,这些后端系统中的注入仍然可能发生。在查询中注入(不) SQL 或 JSON 语法时,一定要查找服务器端错误。您对 GraphQL API 的后端了解得越多越好。例如,如果在后台使用发送到 GraphQL API 的数据进行 REST API 调用,那么您可以尝试注入额外的参数,遍历路径,甚至执行服务器端请求伪造。有很多时髦的东西可能会发生在幕后。

GraphQL Batching

GraphQL 批处理

Remember how we said you can request multiple resources within one request? Well, that feature can also backfire if you start making too many queries in a single HTTP request; brute-force attacks, race conditions, and other unexpected behaviors can occur.

还记得我们说过您可以在一个请求中请求多个资源吗?如果您开始在单个 HTTP 请求中进行过多的查询,那么这个特性也可能会适得其反; 暴力破解攻击、竞争条件和其他意外行为可能会发生。

If API rate limiting is in place and enforced only at the HTTP level, a single HTTP request with many queries won’t be throttled. Brute-force attacks may suddenly become very easy! Interesting endpoints may be login or authentication-related (2FA), IDOR/enumerable objects, or other functionality specific to your application. A tool that can help with this is BatchQL, created by Assetnote. Otherwise, pull out your favorite scripting language and script an attack yourself.

如果 API 速率限制已经到位并且只在 HTTP 级别强制执行,那么一个带有多个查询的 HTTP 请求将不会被限制。暴力攻击可能突然变得非常容易!有趣的端点可能是登录或与身份验证相关的(2FA)、 IDOR/可枚举对象,或应用程序特有的其他功能。一个可以帮助解决这个问题的工具是 BatchQL,由 Assetnote 创建。否则,拿出你最喜欢的脚本语言,自己编写一个攻击脚本。

Race conditions can occur if mutations within the same HTTP request are performed in parallel instead of sequentially. This behavior will depend on the GraphQL engine that is being used. Of course, race conditions across multiple HTTP requests would also still apply. Because many applications are not built with atomic operations in mind, these vulnerabilities are very common.

如果同一 HTTP 请求中的变异是以并行方式而不是顺序方式执行的,则可能会出现竞争条件。这种行为将取决于所使用的 GraphQL 引擎。当然,跨多个 HTTP 请求的竞争条件仍然适用。由于许多应用程序在构建时没有考虑到原子操作,因此这些漏洞非常常见。

Denial of Service

分布式拒绝服务攻击

Complex queries can lead to denial of service (DoS) by making the GraphQL API take a long time to return the response to your query. This is not so different from regular expression DoS, although it’s trickier to prevent. Requesting a lot of data at once (or having a query that nests many other queries) could overload something in the chain, be it the application server, database, or other APIs behind the scene.

复杂的查询可能会导致分布式拒绝服务攻击查询(DoS) ,因为 GraphQL API 需要很长时间才能返回查询的响应。这与正则表达式 DoS 没有太大的不同,尽管要防止这种情况发生会更加困难。一次请求大量数据(或者拥有嵌套许多其他查询的查询)可能会使链中的某些内容超载,无论是应用程序服务器、数据库还是背后的其他 api。

Techniques that developers use to mitigate DoS in GraphQL include limiting the depth, size, or cost of a query.

开发人员用来减轻 GraphQL 中 DoS 的技术包括限制查询的深度、大小或成本。

For additional reading, Apollo wrote a blog post that reviews the thought process of trying to protect a GraphQL API from expensive queries.

为了进一步阅读,Apollo 写了一篇博客文章,回顾了试图保护 GraphQL API 免受昂贵查询的思维过程。

Cross-site Request Forgery (CSRF)

跨站请求伪造

Don’t skip checking for CSRF just because you see all of this JSON in requests. The GraphQL API may accept data in other forms besides plain JSON in a body.

不要仅仅因为在请求中看到了所有这些 JSON,就跳过对 CSRF 的检查。GraphQL API 可以在主体中接受普通 JSON 以外的其他形式的数据。

Ask yourself these questions:

问问你自己这些问题:

  1. Is the GraphQL API being used from a browser that performs cookie authentication and/or doesn’t require special headers?
  2. GraphQL API 是从执行 cookie 身份验证和/或不需要特殊头的浏览器中使用的吗?
  3. Are you able to perform mutations using GET parameters, POST body with URL encoded data, or POST body with form data?
  4. 您能够使用 GET 参数、使用 URL 编码数据的 POST 主体或使用表单数据的 POST 主体执行变异吗?

If you meet the conditions above and the stars align with SameSite, then you’re in luck!

如果你符合上面的条件,而且星星排列在同一个星座上,那么你就是幸运的!

For additional reading, Doyensec wrote a great blog post about CSRF issues in GraphQL, and they also released a tool that can help with generating various GET and POST requests.

为了进一步阅读,Doyensec 用 GraphQL 写了一篇很棒的关于 CSRF 问题的博文,他们还发布了一个工具,可以帮助生成各种 GET 和 POST 请求。

Introspection Enabled

启用自省

As someone testing a GraphQL API, you’ll definitely want introspection enabled. However, just as introspection is useful to you, an attacker is also going to get value out of it. Make it a bit harder for attackers by disabling introspection on production APIs, unless of course public API documentation is required. This is basically an information disclosure feature/misconfiguration. Additionally, once introspection is disabled, ensure that hinting is also disabled, as that type of information disclosure leads to schema discovery. For example, you may issue a query with a partial word like caps, which doesn’t exist:

作为测试 GraphQL API 的人,您肯定希望启用自省。然而,正如自省对您有用一样,攻击者也将从中获得价值。当然,除非需要公共 API 文档,否则通过禁用生产 API 的自省会让攻击者更加困难。这基本上是一个信息披露特性/错误配置。此外,一旦禁用了自省,请确保也禁用了暗示,因为这种类型的信息公开会导致模式发现。例如,你可能会发出一个查询,其中包含一个不存在的部分单词,比如 caps:

{
  caps {
    id
  }
}

The server may respond with an error message like the following:

服务器可能会响应如下的错误消息:

{
  "errors": [
    {
      "message": "Cannot query field \"caps\" on type \"Query\". Did you mean \"capsule\" or \"capsules\"?",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "extensions": {
        "code": "GRAPHQL_VALIDATION_FAILED"
      }
    }
  ]
}

This behavior can be used to more efficiently brute-force a schema. The tool clairvoyance, mentioned earlier, utilizes this functionality to enumerate the schema.

这种行为可以用来更有效地强制某个模式。前面提到的工具千里眼利用这个功能来枚举模式。

Console/Explorer Enabled

启用控制台/资源管理器

Depending on the GraphQL engine used, it may come packaged with a console for developers that isn’t disabled in production.

根据所使用的 GraphQL 引擎,它可能会为开发人员打包一个控制台,而不是在生产中禁用。

The following is GraphiQL, which is a common console you will see:

下面是 GraphiQL,这是一个常见的控制台,你会看到:

Here are some ideas for paths to look for: SecLists – GraphQL. You don’t want to have consoles like this enabled unless they are on a public GraphQL API, as this exposes an additional attack surface.

下面是一些查找路径的想法: SecLists-GraphQL。您不希望启用这样的控制台,除非它们使用的是公共 GraphQL API,因为这会暴露额外的攻击面。

Error Information Disclosure

错误信息披露

Error messages are helpful to any attacker. In the context of GraphQL, pay attention to error messages that leak names of fields. If you don’t have a schema, this can help reveal some of the inner workings of the GraphQL API.

错误消息对任何攻击者都有帮助。在 GraphQL 上下文中,请注意泄露字段名称的错误消息。如果没有模式,这可以帮助揭示 GraphQL API 的一些内部工作原理。

Conclusions

结论

Hopefully this post was a good springboard for you to use to jump into the waters of GraphQL! If you are looking to take things to the next level, be sure to go through Introduction to GraphQL. After that, go ahead and build a GraphQL API yourself and get into the same mindset as developers utilizing this new technology.

希望这篇文章是一个很好的跳板,你可以用它跳进 GraphQL 的水里!如果您希望进入下一个层次,请务必阅读 GraphQL 介绍。在此之后,继续自己构建一个 GraphQL API,并像使用这项新技术的开发人员一样进入相同的思维模式。


Forces Unseen is an independent security consulting firm with a focus on application and infrastructure security.

是一家专注于应用程序和基础设施安全的独立安全咨询公司。

Some ways to find more IDOR

Hello friend!

你好,朋友!

I had learnt a lot of knowledges from others’ s blogs, write-ups, so I think I should give back to the community. 🙂 I hope this blog will be useful for someone.

我从别人的博客、文章中学到了很多知识,所以我认为我应该回馈社会。:)我希望这个博客对某些人有用。

This post is about some methodologies I had used to find IDOR vulnerability and some my findings relate to IDOR bugs.

这篇文章是关于我用来发现 IDOR 漏洞的一些方法,以及我的一些发现与 IDOR 漏洞有关。

  1. No ID, No Worry 

This is an bug that I had found in the past. It’s a site-wide IDOR allow me to read/modify/delete any information of other users, and yes, sure, I could takeover all accounts.

这是我过去发现的一个错误。它是一个站点范围的 IDOR,允许我读取/修改/删除其他用户的任何信息,是的,当然,我可以接管所有帐户。

After playing with functions of main website, I took a look back on my Burp History

玩过主网站的功能后,我回顾了我的Burp历史

Do you notice that? There is no parameter or URL path contains ID, but there is one thing causes my eyes. These API had a common pattern

你注意到了吗?没有参数或 URL 路径包含 ID,但有一件事导致我的眼睛。这些 API 有一个共同的模式

/something/something/self/something

These APIs return my information or doing some actions on behalf of me. I ask myself what if I replace that self word with my user ID ( user ID could be found on JWT token). For example, /ngprofile/aggregate/31337/fullProfile .

这些 api 返回我的信息或者代表我做一些动作。我问自己,如果用我的用户 ID 替换那个自我词(用户 ID 可以在 JWT 标记上找到)会怎样。例如,/ngprofile/aggregate/31337/fullProfile。

And BOOM! The response return my full profile information.

然后,BOOM! 回复会返回我的完整个人信息。

I tried to replace my user ID with other user ID ( the user ID is increment). So I could read other users’ s profile information.

我试图用其他用户 ID 替换我的用户 ID (用户 ID 是递增)。所以我可以阅读其他用户的个人资料信息。

I observed that all API contain self word is vulnerable to that IDOR, even the Change Email API.

我注意到所有包含 self word 的 API 都很容易受到 IDOR 的攻击,甚至连 Change Email API 也是如此。

So I could change email of any user. I could chain this bug with “Forgot password” function to send the reset passsword link of victim to my control emails and use that link to reset password of victim. So I could login to any account in the system.

所以我可以改变任何用户的电子邮件。我可以链接这个漏洞与“忘记密码”功能发送重置密码链接受害者到我的控制电子邮件和使用该链接重置密码的受害者。这样我就可以登录系统中的任何账户。

Key Takeaways

Try to understand applications ( how could this API/request authorize users, why there is no parameter, etc.), analyze carefully requests/responses. You could find more IDORs.

尝试理解应用程序(这个 API/请求如何授权用户,为什么没有参数等等) ,仔细分析请求/响应。你可以找到更多的身份证。

2. Don’t just replace ID

2. 不要只是替换 ID

When testing IDOR vulnerability, don’t just replace our own ID with others user/object ID. Sometimes one character could made a different.

在测试 IDOR 漏洞时,不要只是用其他用户/对象 ID 替换我们自己的 ID。有时候一个角色可以创造出不同的角色。

Scenario 1:

情景1:

The screenshot below shows when I replace my user ID with other user ID in API /accounts/0001176361, the server’s response “Invalid account number”

下面的屏幕截图显示了当我用 API/accounts/0001176361中的其他用户 ID 替换我的用户 ID 时,服务器的响应“ Invalid account number”

The screenshot below shows when I add “/” character append to this user ID, the server’s response return all information about this user. Maybe the “/” character breaks logic of the regex or pattern that server used to restrict access.

下面的屏幕截图显示,当我向这个用户 ID 添加“/”字符时,服务器的响应将返回关于这个用户的所有信息。也许“/”字符破坏了服务器用于限制访问的正则表达式或模式的逻辑。

Scenario 2:

情景2:

The screenshot below shows when I replace my application ID with other’s application ID (18385027) in API api/applications/18385027, the server’s response “access_denied” with HTTP code 401

下面的屏幕截图显示了当我在 API/applications/18385027中用他人的应用程序 ID (18385027)替换我的应用程序 ID 时,服务器的响应“ access _ denied”使用 HTTP 代码401

The screenshot below shows after fuzzing all character, I could bypass authorization control by appending %20, %09, %0b, %0c, %1c, %1d, %1e, %1f to application ID in this API. The server would return full information of that application.

下面的屏幕截图显示,在模糊所有字符之后,我可以通过在这个 API 中的应用程序 ID 中附加% 20,% 09,% 0b,% 0c,% 1c,% 1d,% 1e,% 1f 来绕过授权控制。服务器将返回该应用程序的全部信息。

Key Takeaways

(Old but gold): Don’t just replace IDs and wait for luck. Try to fuzz all possible character ( my list is %00 -> %ff) to break the logic of the regex or pattern that server used to restrict access. The more you fuzz, the more you luck.

(古老但是金子) : 不要只是更换身份证,等待运气。尝试模糊所有可能的字符(我的列表是% 00->% ff) ,以破坏服务器用于限制访问的正则表达式或模式的逻辑。你的毛越多,你的运气就越好。

3. Don’t Ignore IDOR in GraphQL applications.

3. 不要在 GraphQL 应用程序中忽略 IDOR。

A long time ago, I was very noob in testing GraphQL applications ( still the same now).

很久以前,我在测试 GraphQL 应用程序时非常菜(现在仍然是这样)。

When playing bug bounty in a private program, I observed this application using GraphQL. Immediately I remove all endpoints /graphql from scope =)).

在私有程序中播放 bug 赏金时,我使用 GraphQL 观察了这个应用程序。立即从 scope =)中删除所有端点/graphql)。

After playing with some functions, I gave a look at Burp History again and there is no request is found😐. So all APIs of this application used GraphQL.

在使用了一些函数之后,我再次查看了一下 Burp History,没有发现任何请求。所以这个应用程序的所有 api 都使用了 GraphQL。

I had wanted to know what does these requests look likes. So I add again this /graphql endpoints to my scope. 😶

我一直想知道这些请求看起来像什么。因此我再次将这个/graphql 端点添加到我的作用域中。

And luckily, I found 2 IDOR in that application ( just replace IDs).

幸运的是,我在那个应用程序中找到了2个 IDOR (只需替换 id)。

After that, I realize that there is a quite hard to implement security in GraphQL, even Facebook and Google have many bugs in GraphQL endpoints.

在那之后,我意识到要在 GraphQL 中实现安全是相当困难的,甚至 Facebook 和 Google 在 GraphQL 端点中也有很多 bug。

Key Takeaways

Don’t ignore anything. 😜

不要忽视任何事情。

I hope this blog can help someone find more IDOR vulnerability. This community help me so much so I want to give back my experience to community. 😄

我希望这个博客可以帮助人们找到更多的 IDOR 漏洞。这个社区对我帮助很大,所以我想把我的经验还给社区。

You can contact me via https://twitter.com/thaivd98 .

你可以通过 https://twitter.com/thaivd98联系我。

Thanks for reading! Happy Hacking!

感谢阅读! 黑客快乐!

2021 API安全渗透

原文链接:https://labs.detectify.com/2021/08/10/how-to-hack-apis-in-2021/
中文翻译:https://mp.weixin.qq.com/s/gwW0ZDJoTx6WgAtwKaCv1w

Detectify Crowdsource is not your average bug bounty platform. It’s an invite-only community of the best ethical hackers who are passionate about securing modern technologies and end users. Crowdsource hackers Hakluke and Farah Hawa have joined forces on this guest blog on how hackers and defenders can (safely) hack APIs to help make the Internet safer.

不是一个普通的 bug 赏金平台。这是一个只有受邀才能参加的社区,里面有最有道德的黑客,他们热衷于保护现代技术和最终用户。Crowdsource 黑客 Hakluke 和 Farah Hawa 已经在这个客座博客上联合起来,讨论黑客和防御者如何(安全地)破解 api 来帮助互联网更安全。

Baaackkk iiin myyy dayyyyy APIs were not nearly as common as they are now. This is due to the explosion in the popularity of Single Page Applications (SPAs). 10 years ago, web applications tended to follow a pattern where most of the application was generated on the server-side before being presented to the user. Any data that was needed would be gathered directly from a database by the same server that generates the UI. It might look something like this:

当时的蜜蜂并不像现在这么普遍。这是由于单页应用程序(Single Page Applications,简称 SPAs)的爆炸式增长。10年前,web 应用程序趋向于遵循一种模式,即大部分应用程序在呈现给用户之前都是在服务器端生成的。生成 UI 的同一台服务器将直接从数据库收集所需的任何数据。它可能看起来像这样:

most of the application was generated on the server-side before being presented to the user

Chart: Web application model 10 years ago

图表: 10年前的 Web 应用程序模型

Many modern web applications tend to follow a different model often referred to as an SPA (Single Page Application). In this model there is typically an API backend, a JavaScript UI, and database. The API simply serves as an interface between the webapp and the database. All requests to the API are made directly from the web browser.

许多现代 web 应用程序趋向于遵循一种不同的模式,通常被称为 SPA (单页应用程序)。在这个模型中,通常有一个 API 后端、一个 JavaScript UI 和一个数据库。这个 API 只是作为 webapp 和数据库之间的一个接口。所有对 API 的请求都是直接从 web 浏览器发出的。

Detectify product update: the fuzzing engine will cover public-facing APIs

产品更新: 模糊引擎将覆盖面向公众的 api

All requests to the API are made directly from the web browser.

Chart: Modern web applications tend to follow a different model often referred to as an SPA

图表: 现代网络应用程序趋向于遵循一种通常被称为 SPA 的不同模式

This is often a better solution because it is easier to scale and allows more specialised developers to work on the project, i.e. frontend developers can work on the frontend while backend developers work on the API. These apps also tend to feel snappier because page loads are not required for every request.

这通常是一个更好的解决方案,因为它更容易扩展,并允许更专业的开发人员在项目上工作,也就是说,前端开发人员可以在前端工作,而后端开发人员在 API 上工作。这些应用程序也往往感觉更加流畅,因为并不是每个请求都需要页面加载。

Instead, different components of the same page will update magically, giving it a similar feel to a native application. This model has also become more popular because ten billion ⁽ᶜᶦᵗᵃᵗᶦᵒⁿ ⁿᵉᵉᵈᵉᵈ⁾ different frontend JavaScript frameworks (React, Vue and Angular, etc.) have come into existence. Suspicious minded folk might conclude that the ridiculous amount of JavaScript frameworks available today is a co-ordinated attempt to slow the progress of webapp development, instigated by the Illuminati. That’s probably not true though .

相反,同一页面的不同组件会神奇地更新,给人一种与本地应用程序相似的感觉。这个模型也变得更加流行,因为已经出现了100亿个不同的前端 JavaScript 框架(React、 Vue 和 Angular 等)。持怀疑态度的人们可能会得出结论,今天可用的大量 JavaScript 框架是一个协调一致的尝试,目的是放慢网络应用开发的进度,这是由光明会发起的。不过这可能不是真的。

All this to say – there are APIs everywhere now, so we should know how to hack and secure them. If you’re still reading – your fingers are probably hovering over ctrl+w. Your brain is thinking “this article title promised to teach me to hack, not what a SPA is. I am an intellectual individual and the author’s attempts at humour are futile, life is short and I am wasting my time reading this stupi….” HOLD IT! We’re getting there. I promise. Cool your jets. Goooooosfraba.

所有这些都是为了说明,现在到处都有 api,所以我们应该知道如何破解和保护它们。如果你还在读书,你的手指可能正在 ctrl + w 键上徘徊,你的大脑正在思考“这篇文章的标题承诺教我如何破解,而不是 SPA 是什么。我是一个知识分子,作者的幽默尝试是徒劳的,生命是短暂的,我正在浪费我的时间阅读这个愚蠢的… …”等等!我们快到了。我保证。冷静一下。Goooooosfraba.

Setting up for testing APIs

设置 api 测试

Postman is a handy application that makes API security testing a breeze. You can download Postman from its official website. In essence, Postman is just another HTTP client which can be used to easily modify and send requests to APIs.

Postman 是一个方便的应用程序,使 API 安全性测试轻而易举。你可以从邮差的官方网站下载。实际上,Postman 只是另一个 HTTP 客户端,可以用它轻松地修改和向 api 发送请求。

If you’ve got a collection of API requests in a file, you can start by importing them into Postman by clicking on the Import button on the top-left corner of the app:

如果你在一个文件中收集了一些 API 请求,你可以通过点击应用程序左上角的导入按钮将它们导入到 Postman 中:

postman API calls

After importing the collection, you will see the API calls loaded in Postman like so:

导入集合后,您将看到在 Postman 中加载 API 调用,如下所示:

API calls in Postman

By clicking on an individual API call, the full API request will be seen on the right. Moreover, different parts of the request will be broken down into sections like Params, Authorization, Headers, Request Body, etc. This will allow you to easily play around with each part.

通过单击一个单独的 API 调用,完整的 API 请求将显示在右侧。此外,请求的不同部分将被分解为像 Params、 Authorization、 header、 Request Body 等部分。这样你就可以很容易地处理每个部分。

parameters of API call requests in postman

You can modify the request headers and body in the same manner as you would in BurpSuite. To analyze the responses to your test cases, you can simply hit the Send button on the top right.

您可以像在 BurpSuite 中一样修改请求标头和正文。要分析测试用例的响应,只需点击右上角的 Send 按钮即可。

how to modify in postman

The response view in Postman looks like this and the response is also bifurcated into different sections like Body, Cookies, Headers, etc. so you can analyze each part carefully.

Postman 中的响应视图看起来像这样,响应也被分成不同的部分,比如 Body、 Cookies、 Headers 等,因此您可以仔细分析每个部分。

response view in postman

Since Postman is meant for APIs specifically, you have a lot of in-built options to test for functions that are mostly present in APIs. For example, by clicking on this drop-down arrow next to the request method, you can see tons of different request verbs to test with:

由于 Postman 是专门用于 api 的,因此您有许多内置的选项可以测试 api 中大多数出现的函数。例如,单击 request 方法旁边的下拉箭头,您可以看到大量不同的请求动词来进行测试:

GET in postman

For GET requests, you can add/remove as well as edit parameters via the Params tab. When you check/uncheck parameters, you can see them appear accordingly in the URI field.

对于 GET 请求,您可以通过 Params 选项卡添加/删除以及编辑参数。在检查/取消检查参数时,可以看到它们相应地出现在 URI 字段中。

get postman 2

When it comes to adding Authorization values, Postman gives you a number of options to choose from and you can choose one depending on how the target API handles authorization.

在添加授权值时,Postman 提供了许多选项供您选择,您可以根据目标 API 处理授权的方式选择一个。

authorization of values in postman

You can also add Authorization values to the entire collection or sub-collection by following these steps:

还可以通过以下步骤向整个集合或子集合添加 Authorization 值:

  1. Click the three dots on the side of the collection/sub-collection name and choose the 单击集合/子集合名称侧面的三个点,然后选择Edit 编辑 option 选择
    authorization step 1
  2. Go to the 你可以去Authorization 授权 tab, select the type of auth and add its value. 选项卡中,选择 auth 类型并添加其值
    authorization step 2
  3. Lastly, go to an individual API request and select the 最后,转到一个单独的 API 请求并选择Inherit auth from parent 从父节点继承授权option 选择
    authorization step 3

This will save you the trouble of setting Authorization values for every single request.

这将为您省去为每个请求设置 Authorization 值的麻烦。

Another handy feature of Postman is that it allows users to proxy API requests with BurpSuite. In order to set that up, you need to follow these steps:

Postman 的另一个方便的特性是,它允许用户使用 BurpSuite 代理 API 请求。为了达到这个目的,你需要遵循以下步骤:

  1. Click on the Settings option from the drop-down menu on the top-right corner 点击右上角下拉菜单中的设置选项
    settings
  2. Go to the 你可以去Proxy 代理人 tab and do this: 然后这样做:
    • Switch Off 关掉Use the system proxy 使用系统代理
    • Switch On 打开开关Add a custom proxy configuration 添加自定义代理配置
    • Set 预备the 的 Proxy Server IP address 代理服务器 IP 地址 & port 港口 to match your Burp Suite proxy settings. The default values are 127.0.0.1 and 8080. 默认值是127.0.0.1和8080
      Your final settings should look like this: 你的最终设置应该是这样的:
      Final settings
  3. To proxy HTTPS requests without any errors, you can switch off 对于没有任何错误的代理 HTTPS 请求,您可以关闭SSL certificate validation SSL 证书验证 under the 在… 之下General 将军 tab. 标签
    toggle ssl certs

Detectify product update: the fuzzing engine will cover public-facing APIs

产品更新: 模糊引擎将覆盖面向公众的 api

Types of API Vulnerabilities

API 漏洞的类型

APIs come in many shapes and sizes, the methods of attacking an API will vary greatly depending on these shapes, and sizes. It would be impossible to cover every attack type in a single blog, but we’re going to go through a bunch of them!

API 有许多形状和大小,攻击 API 的方法将根据这些形状和大小有很大的不同。在一个博客中覆盖所有的攻击类型是不可能的,但是我们将经历一系列的攻击!

API Exposure

空气污染指数

Much like web applications, APIs can have different levels of visibility. Some may be accessible to the internet while others are only available internally. One of the more rudimentary API hacks is simply gaining access to an API which should be inaccessible to you. This may be achieved through a variety of methods, including:

就像 web 应用程序一样,api 可以有不同程度的可见性。有些可以通过互联网访问,而有些则只能在内部访问。最基本的 API 技巧之一就是获得对 API 的访问权,而这些 API 对您来说应该是不可访问的。这可以通过多种方法实现,包括:

  • Forced browsing: 强制浏览: If you are lucky, an API that is intended for internal use may be accidentally exposed to the internet, either through a misconfiguration or just because it was assumed that nobody would be able to find it. API locations may be discovered through many means including analysing JavaScript files, analysing exposed source code, observing host names (e.g. 如果幸运的话,一个用于内部使用的 API 可能会意外地暴露在互联网上,要么是由于配置不当,要么仅仅是因为人们认为没有人能够找到它。通过分析 JavaScript 文件、分析公开的源代码、观察主机名(例如:api 美国石油学会.internal 内部的.example 例子.com) and Google dorking. )和 Google dorking
  • Pivoting: 转轴: Discovering an exploit like SSRF on an external host may allow you to pivot into an internal API. 在外部主机上发现类似 SSRF 的漏洞可能允许您转向内部 API

Mitigation

缓解措施

There are many best practices that can help mitigate against unintentionally exposing APIs including the implementation of strict deployment practices, enforced principle of least privilege through IAM and network segmentation.

有许多最佳实践可以帮助减少无意中暴露的 api,包括实现严格的部署实践、通过 IAM 强制执行最小特权原则以及网络分割。

Misconfigured Caching

错误配置的缓存

For APIs that require authentication, the data being returned is often dynamic and is scoped to each API key. For example, accessing /api/v1/userdetails as Bob should return Bob’s details, while accessing the same endpoint as Jane should return Jane’s details.

对于需要身份验证的 API,返回的数据通常是动态的,其作用域为每个 API 密钥。例如,作为 Bob 访问/api/v1/userdetails 时应该返回 Bob 的详细信息,而作为 Jane 访问相同的端点时应该返回 Jane 的详细信息。

A common misconfiguration occurs when an API does not use the standard Authorization header, instead using a custom header such as X-API-Key. Caching servers may not recognise this as an authenticated request, and may cache it.

当 API 没有使用标准的 Authorization 头,而是使用自定义头(如 x-API-key)时,常见的错误配置会发生。缓存服务器可能不认可这是一个经过身份验证的请求,并可能缓存它。

If this is the case, and there are no Cache-Control or Pragma headers, simply accessing /api/v1/userdetails may reveal the information of another user.

如果是这种情况,而且没有 Cache-Control 或 Pragma 头,那么只需访问/api/v1/userdetails 就可以显示其他用户的信息。

Mitigation

缓解措施

The fix for this is to implement Cache-Control or Pragma headers and utilise the standard Authorization header.

解决这个问题的方法是实现 Cache-Control 或杂注头,并使用标准的 Authorization 头。

Exposed tokens 暴露的代币

We shouldn’t discount the most rudimentary authentication hack. Discovering an API key through any means may provide you with access to the API. To make matters worse, APIs that are meant for internal use often have no need to implement complex authentication flows and thus may implement a static token as their authentication. Secret tokens may be discovered in code repositories, client-side JavaScript, intercepting traffic, etc.

我们不应该忽视最基本的身份验证黑客。通过任何方式发现一个 API 密钥可以为您提供对 API 的访问。更糟糕的是,用于内部使用的 api 通常不需要实现复杂的身份验证流,因此可以实现静态令牌作为其身份验证。可以在代码库、客户端 JavaScript、拦截流量等中发现秘密令牌。

Mitigation 缓解措施

Implementing code scanning into your devops pipeline will often catch API keys before they are deployed somewhere they shouldn’t be. Some code repository providers (including GitHub) also have the ability to detect API keys before they are pushed.

在 devops 管道中实现代码扫描通常会在 API 密钥被部署到不该部署的地方之前捕获它们。一些代码存储库提供程序(包括 GitHub)也能够在 API 键被推出之前检测到它们。

JWT Weaknesses JWT 的弱点

If your API token is three base64 blobs separated by two dots (.), it’s probably a JSON Web Token (JWT). Like many things, these tokens are secure in theory, but there are many ways to mess up the implementation in a way that introduces security issues. Before we delve into JWT attacks we’ll go through a very quick JWT primer.

如果您的 API 令牌是由两个点(.)分隔的三个 base64 blob它可能是一个 JSON Web 令牌(JWT)。像许多事情一样,这些令牌在理论上是安全的,但是有许多方法会以引入安全性问题的方式搞乱实现。在深入探讨 JWT 的攻击之前,我们先来了解一下 JWT 的基本知识。

Here’s an example JWT token, colorized for your aesthetic appreciation:

下面是一个示例 JWT 令牌,为了你的审美欣赏而着色:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Eyjhbgcioijiuzi1niisinr5cci6ikpxvcj9.eyjzdwiiiixmjm0nty3odkwiibmftzsi6ikvvag4grg9liiwiawf0ijoxnte2mjm5mdiyfq.sflkxwrjsmekkf2qt4fwpmejf36pok6yqadqsw5c

There are three base64 encoded strings separated by dots, the first section (colored in red) is the header. The second (colored in purple) is the payload, and the third (colored in blue) is the signature.

有三个用点分隔的 base64编码的字符串,第一部分(红色)是标题。第二个(紫色)是有效载荷,第三个(蓝色)是签名。

If we decode the first section, also known as the header, we will see the following:

如果我们对第一部分进行解码,我们会看到如下内容:

{
"alg": "HS256",
"typ": "JWT"
}

{“ alg”: “ HS256”,“ typ”: “ JWT”}

This outlines the algorithm that we’re using (HS256) and the type of token (JWT). If you’ve not worked with JWTs before you might be thinking “why do we need an algorithm?”. We will get there soon!

这概述了我们正在使用的算法(HS256)和令牌类型(JWT)。如果您以前没有使用过 JWTs,那么您可能会想: “为什么我们需要一个算法?”.我们很快就会到那儿的!

If we decode the second section, also known as the payload, we will see the following:

如果我们解码第二部分,也就是有效载荷,我们将看到如下内容:

{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

{“ sub”: “1234567890”,“ name”: “ John Doe”,“ iat”: 1516239022}

This section could contain anything, but at minimum it needs to contain some kind of user identifier and a timeout (iat).

这个部分可以包含任何内容,但至少需要包含某种用户标识符和超时(iat)。

The third section (also known as the signature) signs the first two sections with a secret key. In this case it is signed with the HS256 algorithm, which can be determined by looking at the “alg” value in the header. The idea is that the secret key should only be known to the owner of the application. When the application receives a JWT token, it can verify that the token is legitimate by decrypting the signature and comparing it to the data in the header and payload. If the data matches up then the data is verified, otherwise it is invalid.

第三部分(也称为签名)用密钥对前两部分进行签名。在这种情况下,它使用 HS256算法进行签名,这可以通过查看头部的“ alg”值来确定。其思想是,只有应用程序的所有者才应该知道秘钥。当应用程序接收到 JWT 令牌时,它可以通过解密签名并将其与头部和有效负载中的数据进行比较来验证该令牌是否合法。如果数据匹配,则验证数据,否则数据无效。

So why would anyone use JWT? It is because it negates the need for server-side session management. Traditionally when a user logs in, an application would assign a secret token to the user and store that same token in a database. Whenever the user makes a request with their token, the application needs to check if the token is in the database. If it is, the user is allowed to continue, otherwise they are not. When we use JWTs, we introduce a method of trusting data that is sent from the client instead of solely trusting information that is stored in the database. If the application receives a JWT token that can be verified using the secret key, then the application has no reason to distrust it.

那么为什么会有人使用 JWT 呢?这是因为它否定了对服务器端会话管理的需求。传统上,当用户登录时,应用程序将向用户分配一个秘密令牌,并将该令牌存储在数据库中。每当用户使用他们的令牌发出请求时,应用程序需要检查该令牌是否在数据库中。如果是,则允许用户继续,否则不允许继续。当我们使用 JWTs 时,我们引入了一种从客户机发送的信任数据的方法,而不是仅仅信任存储在数据库中的信息。如果应用程序收到可以使用秘密密钥验证的 JWT 令牌,那么应用程序没有理由怀疑它。

As we touched on earlier, in theory JWT tokens are totally secure. The problem is that they are often implemented in a way that is insecure. Here are some examples:

正如我们在前面提到的,理论上 JWT 令牌是完全安全的。问题在于,它们的实现方式往往是不安全的。以下是一些例子:

  • The None algorithm: Some implementations of JWT will allow you to specify “None” as the algorithm. If the algorithm is “None”, the application will not check the validity with the signature, so you can simply update the payload to whatever you want. The most obvious exploitation of this would be to update the user id to another user to take control of their account. None 算法: JWT 的一些实现允许您指定“ None”作为算法。如果算法是“ None”,应用程序将不会用签名检查有效性,因此您可以简单地将有效负载更新为您想要的任何内容。最明显的利用方式是将用户 id 更新为另一个用户,以控制他们的帐户
  • Brute forcing: It is possible to brute force the secret key of JWT tokens. The feasibility of this attack will depend on the strength of the key. You can attempt to crack JWT tokens using 蛮力破解: 蛮力破解 JWT 令牌的密钥是可能的。这次攻击的可行性将取决于钥匙的强度。您可以使用以下命令尝试破解 JWT 令牌this tool 这个工具. A full write-up on the method can be found on 。有关此方法的详细资料,可浏览Auth0’s blog 0的博客.
  • Simply changing the payload: In some rare cases, the server may simply skip the token verification entirely and trust the data in the payload. While I have not seen this personally, I have read about it occuring in the wild! 只需更改有效负载: 在某些罕见的情况下,服务器可能完全跳过令牌验证,并信任有效负载中的数据。虽然我没有亲眼见过这种情况,但我读到过它发生在野外
  • Switching RS to HS: There’s a defect with some older JWT libraries where you can trick an application that is expecting tokens signed using asymmetric cryptography into accepting a symmetrically signed token. The symmetrically signed token that ends up being used is actually a public key which is often somehow obtainable, or reused from their HTTPS key. There is a great writeup of this method 将 RS 切换到 HS: 在一些较老的 JWT 库中存在一个缺陷,您可以使用非对称加密技术欺骗期望使用已签名令牌的应用程序接受对称签名令牌。最终被使用的对称签名令牌实际上是一个公钥,通常可以以某种方式获得,或者从它们的 HTTPS 密钥中重用。关于这个方法有一篇很棒的文章here 这里.
  • The 这个iat timeout is not honoured, so JWT tokens remain valid forever. 不支持超时,因此 JWT 标记将永远有效

Mitigation 缓解措施

The best mitigation for JWT weaknesses is to utilise a widely-used, reputable JWT library for all JWT operations.

对于 JWT 的弱点,最好的缓解方法是在所有 JWT 操作中使用广泛使用的、有信誉的 JWT 库。

Authorization Issues / IDOR 授权事项/IDOR

Authorization is the process of checking whether an authenticated user has access to a specific user. A common authorization-related vulnerability is known as an Insecure Direct Object Reference (IDOR). For example, in an API for an invoicing application, we may have an endpoint that is used to get the details of an invoice:

/api/v1/invoices/?id=1234

授权是检查经过身份验证的用户是否有权访问特定用户的过程。一个常见的与授权相关的漏洞称为不安全的直接对象引用(Insecure Direct Object Reference,IDOR)。例如,在一个发票应用程序的 API 中,我们可能有一个用于获取发票详细信息的端点:/API/v1/invoices/?1234

The id parameter is the identifier for the invoice that should be returned. If this endpoint is secured, I should only be able to get the details of invoices that belong to me. For example if I created an invoice with an ID of 1234 then it should return the details. If I try to access an invoice that I did not create by browsing to /api/v1/invoices/?id=1233, it should return an error.

Id 参数是应该返回的发票的标识符。如果这个端点是安全的,我应该只能得到属于我的发票的细节。例如,如果我创建了一个 ID 为1234的发票,那么它应该返回详细信息。如果我试图访问一个没有通过浏览/api/v1/invoices/来创建的发票,那么我会怎么做?1233,它应该返回一个错误。

If I am able to change the identifier to view the invoice details of other users, this is a vulnerability known as an IDOR.

如果我能够更改标识符以查看其他用户的发票详细信息,这是一个称为 IDOR 的漏洞。

To counter IDOR issues, many APIs today are utilising UUIDs as object identifiers. A UUID looks like this:

为了解决 IDOR 问题,现在很多 api 都使用 UUID 作为对象标识符:

f1af4910-e82f-11eb-beb2-0242ac130002

It’s important to note that utilising UUIDs as identifiers is not a valid method of mitigating IDOR issues. In fact, the UUID RFC specifically calls this out:

需要注意的是,使用 uuid 作为标识符并不是减轻 IDOR 问题的有效方法。事实上,UUID RFC 特别指出了这一点:

Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example.  A predictable random number source will exacerbate the situation.

不要假定 uuid 很难猜测; 例如,它们不应该用作安全性能(仅仅拥有授予访问权的标识符)。一个可预测的随机数源会使情况恶化。

While it is good practice to utilise UUIDs as object IDs instead of integers, they should never be used as the sole protection against IDOR attacks.

虽然使用 uuid 而不是整数作为对象 id 是一种良好的实践,但是它们永远不应该作为防止 IDOR 攻击的唯一保护。

Mitigation 缓解措施

Authorization issues are typically difficult to detect in an automated fashion. The structure of the codebase should be set up in a way that it is difficult to make authorization errors on specific endpoints. To achieve this, authorization measures should be implemented as far up the stack as possible. Potentially at a class level, or using middleware.

授权问题通常难以自动检测。代码库的结构设置方式应该使得很难在特定端点上发生授权错误。为了实现这一点,授权措施应该尽可能地在堆栈上实现。可能在类级别,或者使用中间件。

Undocumented Endpoints 没有文档的端点

It is common to encounter situations where the API you are attacking has no documentation (or at least none that is accessible to you). It is also fairly common that an API with documentation will have endpoints beyond what is documented. Sometimes the very existence of these endpoints may be a security issue – for example, the endpoint may be designed for administrative purposes, and allow you to perform administrative tasks as an underprivileged user. Other times, these endpoints may present vulnerabilities simply because they have not been tested as thoroughly as the ones that are easy to discover.

遇到您要攻击的 API 没有文档(或者至少没有您可以访问的文档)的情况是很常见的。带有文档的 API 具有文档之外的端点也是相当常见的。有时,这些端点的存在本身可能是一个安全问题——例如,端点可能是为管理目的而设计的,并允许您作为弱势用户执行管理任务。在其他情况下,这些端点可能仅仅因为它们没有像容易发现的端点那样被彻底测试而显示漏洞。

Here are a few methods that we can utilise to uncover undocumented endpoints:

以下是我们可以利用的一些方法,来发现未登记的端点:

  • Use an application that interfaces with the API, and capture traffic. Perhaps the most commonly used tool for this today is Burp Suite.  使用与 API 接口的应用程序,并捕获流量。也许今天最常用的工具是 Burp Suite
    • Set up Burp Suite to proxy the application traffic 设置 Burp Suite 来代理应用程序流量
    • Use all the application features 使用所有的应用程序功能
    • Check the endpoints that were used by viewing the Target tab. 检查通过查看 Target 选项卡使用的端点
  • Observe errors. Many APIs will give errors that are verbose enough to enumerate undocumented endpoints and parameters. For example, sending a blank POST request to 观察错误。许多 api 提供的错误非常冗长,足以枚举无文档记录的端点和参数。例如,将空白 POST 请求发送到/api/v1/randomstring may result in an error that says something along the lines of 可能会导致一个错误,说一些类似于Invalid route, valid routes are [/users,/invoices,/customers].
  • Analyse client-side JavaScript. If you know of an application that interacts with the API, you can analyse the JavaScript within that application to gather a list of API endpoints that may be accessible. 分析客户端的 JavaScript。如果您知道有一个应用程序与 API 交互,那么您可以分析该应用程序中的 JavaScript,以收集可访问的 API 端点列表
  • Use 使用Kiterunner 科特伦纳, a tool by Assetnote that is designed for content discovery on APIs 是由 Assetnote 设计的一个工具,用于在 api 上发现内容
  • Brute force endpoints, there are some 暴力破解端点,有一些excellent 好极了 API wordlists on API 文字列表Assetnote’s website 的网站

Mitigation 缓解措施

Having a strong, structured method and process for documenting API functionality can save a lot of headaches down the road. Swagger is an excellent standard for exactly this. Additionally, it’s best to plan out the API functionality with documentation before coding it instead of the other way around.

拥有一个强大的、结构化的方法和过程来记录 API 功能可以避免很多麻烦。昂首阔步正是这一优秀的标准。此外,最好在编码 API 功能之前就用文档来规划 API 功能,而不是相反。

Different Versions 不同版本

When an organisation releases an API, it may interface with many different applications. If the API is updated at any point, it may introduce breaking changes for one or more of those applications. For that reason, multiple API versions are often implemented as a means of supporting older API schemas while also upgrading the API over time for new users.

当一个组织发布一个 API 时,它可能与许多不同的应用程序接口。如果 API 在任何时候被更新,它可能会引入一个或多个这些应用程序的突变更改。出于这个原因,多个 API 版本通常作为一种支持旧的 API 模式的方法来实现,同时随着时间的推移为新用户升级 API。

It is worth testing all versions of the API. Older versions may still have security issues that have since been fixed in the new version, and newer / bleeding edge / beta versions may have introduced new security issues.

测试所有版本的 API 是值得的。旧版本可能仍然存在安全问题,新版本已经解决了这些问题,而新版本/前沿/beta 版本可能引入了新的安全问题。

A common schema for api versioning is:

Api 版本控制的一个常见模式是:

/api/v1/
/api/v2/
/api/beta/

/api/v1/api/v2/api/beta/

It’s always worth checking for non-production route names such as:

qa
devenv
devenv1
devenv2
preprod
pre-prod
test
testing
staging
stage
dev
development
deploy
slave
master
review
prod
uat
prep
Version2

检查非生产路由的名称总是值得的,例如: qa devev devenv1 devenv2 preprod pre-prod test test staging stage dev development deploy slave master review prod uat prep Version2

This wordlist was taken from an example set in DNSCewl.

这个单词列表来自于 DNSCewl 中的一个例子。

Mitigation 缓解措施

API versions can be supported with defined lifecycles. For example, when you release version 2 of the API, you may notify your users that version 1 will reach End of Life (EoL) and be deprecated at a specific date in the future. Pre-production/beta versions should only be publicly accessible if they have been thoroughly tested for security issues.

API 版本可以支持定义的生命周期。例如,当您发布 API 的版本2时,您可能会通知您的用户版本1将到达生命终结(EoL) ,并在未来的某个特定日期被弃用。预生产/测试版本只有在经过安全问题的彻底测试后才能公开访问。

Rate Limiting 速率限制

Most of the time, APIs do not have any protection on the number of times a user can request them. This is termed as “lack of rate limiting” and it occurs when an attacker can call the API thousands of times to cause some unintended behaviour. The server will attempt to fulfill each of these requests and this can potentially:

在大多数情况下,api 对用户请求它们的次数没有任何保护。这被称为“缺乏速率限制”,当攻击者可以数千次调用 API 导致一些无意识的行为时,就会发生这种情况。服务器将尝试满足每个请求,这可能会:

  • DOS the server by overloading it with requests 通过过载请求来对服务器进行 DOS 操作
  • Allow the attacker to quickly exfiltrate sensitive user information such as: user IDs, usernames, emails etc. 允许攻击者快速过滤敏感的用户信息,如: 用户 id、用户名、电子邮件等
  • Bypass authentication by brute-forcing a login API 通过强制登录 API 绕过身份验证
  • Flood the victim’s inbox by brute-forcing a functionality which sends an email/SMS to the victim 洪水的受害者的收件箱强制一个功能,发送电子邮件/短信给受害者

Let’s look at an attack scenario where there is no rate limiting on an API endpoint that checks credentials:

让我们来看一个攻击场景,在这个场景中,对检查凭证的 API 端点没有速率限制:

GET /api/v1/user/1234/login/?password=mypassword

GET/api/v1/user/1234/login/? password = mypassword

Normally you would not see a password sent in a GET request like this, but for the purposes of this demonstration, let’s say that you do. To brute force the password in the endpoint above, an attacker can use BurpSuite’s Intruder tool. This tool allows us to customize different kinds of brute-force attacks but for this example, we will be feeding it a simple list of passwords.

通常情况下,您不会在这样的 GET 请求中看到密码发送,但是为了演示的目的,假设您看到了。为了暴力破解端点上的密码,攻击者可以使用 BurpSuite 的侵入工具。这个工具允许我们定制不同类型的暴力破解,但是在这个例子中,我们将提供一个简单的密码列表。

In the span of a few seconds, Intruder will make hundreds of API requests, attempting a different password on each request.

在几秒钟的时间内,入侵者将发出数百个 API 请求,尝试在每个请求上使用不同的密码。

GET /api/v1/user/1234/login/?password=notmypassword1
GET /api/v1/user/1234/login/?password=notmypassword2
GET /api/v1/user/1234/login/?password=notmypassword3
.
.
.
GET /api/v1/user/1234/login/?password=correctpassword!

Since there is no rate limit, the server will happily serve the responses to all these requests and the attacker can continue to brute-force different passwords as quickly as possible until the correct one is found.

由于没有速率限制,服务器将很乐意为所有这些请求提供响应,攻击者可以继续尽快暴力破解不同的密码,直到找到正确的密码。

To protect against rate limiting bugs, the application should implement a limit on how often a user can request an API within a certain timeframe. The exact limit that is set will depend on the use case for that API or endpoint.

为了防止速率限制错误,应用程序应该对用户在某个时间段内请求 API 的频率实施限制。设置的确切限制将取决于该 API 或端点的用例。

Mitigation 缓解措施

Rate-limiting can be implemented in many different ways. Per account, per IP address, per endpoint, for the entire API, etc. Some reverse proxies can also be used to implement application-wide throttling without additional development. The exact implementation that you use will depend on the requirements of your specific application.

速率限制可以用许多不同的方法实现。每个帐户,每个 IP 地址,每个端点,整个 API 等等。还可以使用一些反向代理来实现应用程序范围的节流,而无需进行额外的开发。您所使用的具体实现将取决于特定应用程序的需求。

Race Conditions 竞赛条件

A race condition is when two or more requests are sent at the same millisecond to an API. When an API does not have a mechanism to handle this scenario, it can lead to the API processing the requests in an unintended manner.

竞争条件是以相同的毫秒向 API 发送两个或多个请求。当一个 API 没有处理这个场景的机制时,它可能导致 API 以意想不到的方式处理请求。

A potential attack scenario for a race condition could arise while redeeming discounts or promo codes on a vulnerable e-commerce application.

在为易受攻击的电子商务应用程序赎回折扣或优惠代码时,可能会出现针对竞争条件的潜在攻击场景。

POST /api/v1/discount
Target: www.ecommerce.com
Connection: close

{
"code","first10",
"amount":"10"
}

BurpSuite has an extension called Turbo Intruder which allows users to test for race conditions using the in-built race.py script.

BurpSuite 有一个名为 Turbo Intruder 的扩展,允许用户使用内置 race.py 脚本测试竞态条件。

After configuring the attack in Turbo Intruder, an attacker can send multiple concurrent requests to the API for redeeming this promo code.

在 Turbo Intruder 中配置攻击后,攻击者可以向 API 发送多个并发请求,以赎回这个 promo 代码。

POST /api/v1/discount		200 OK
POST /api/v1/discount		200 OK
POST /api/v1/discount		200 OK
POST /api/v1/discount		404 Not Found
POST /api/v1/discount		404 Not Found

If the API does not invalidate the promo code immediately after receiving the first concurrent request, the discount amount could be doubled, tripled, etc.

如果 API 在接收到第一个并发请求后没有立即使促销代码失效,折扣金额可能会增加一倍,三倍,等等。

This attack is named “Race Condition” because it is a race between how fast an attacker sends requests to modify a resource and how fast the application updates that particular resource.

这种攻击被称为“竞争条件”,因为它是一场竞赛,一方面攻击者发送修改资源的请求的速度,另一方面应用程序更新特定资源的速度。

Mitigation 缓解措施

Unfortunately, mitigating race condition issues often means sacrificing performance. Methods to mitigate race conditions include utilizing locks and other thread-safe functionality. Most programming languages will have thread-safe functionality built in, but it usually needs to be manually specified.

不幸的是,缓解竞争条件问题通常意味着牺牲性能。减轻竞争条件的方法包括使用锁和其他线程安全功能。大多数编程语言都有内置的线程安全功能,但通常需要手动指定。

XXE injection XXE 注射剂

XXE stands for XML External Entity and this injection vulnerability can be tested anywhere an API is used to process XML data. SOAP APIs could also be vulnerable to XXE injection because they are based in XML.

XXE 代表 XML 外部实体,这个注入漏洞可以在使用 API 处理 XML 数据的任何地方进行测试。SOAP api 也可能容易受到 XXE 注入的影响,因为它们基于 XML。

An API endpoint that uses XML looks something like this:

使用 XML 的 API 端点如下所示:

POST /soap/v2/user HTTP/1.1
Host: example.com
Content-Type: text/xml


 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dtd[<!ENTITY username SYSTEM "https://example.com/?username">]>
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<getUser>
<id>&username;</id>
</getUser>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

An XML document uses entities to represent a single object of data and an XML document type definition (DTD) is used to define the entities to be used, structure of the document, etc.

XML 文档使用实体表示单个数据对象,XML 文档类型定义(DTD)用于定义要使用的实体、文档结构等。

XXE injection refers to when an attacker injects custom external entities that are outside of the specified DTD. Once these external entities are parsed by the API, it can allow an attacker to access the application’s internal files, escalate to SSRF, leak sensitive data to an attacker-controlled domain or DOS the server.

XXE 注入是指当攻击者注入指定 DTD 之外的自定义外部实体时。一旦这些外部实体被 API 解析,它可以允许攻击者访问应用程序的内部文件,升级到 SSRF,泄漏敏感数据到攻击者控制的域或 DOS 服务器。

This is an example of a request where an attacker has injected an external custom entity called xxe and the purpose of this entity is to retrieve an internal file:

这是一个例子,攻击者注入了一个名为 xxe 的外部定制实体,这个实体的目的是检索一个内部文件:

POST /soap/v2/user HTTP/1.1
Host: example.com
Content-Type: text/xml

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE aa [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<getUser>
<id>&xxe;</id>
</getUser>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

If the API allows the usage of a standard XML parser to process the data, then this injected external entity will be processed by the application and will return the content of /etc/passwd to the attacker.

如果 API 允许使用标准 XML 解析器处理数据,那么应用程序将处理这个注入的外部实体,并将/etc/passwd 的内容返回给攻击者。

Mitigation 缓解措施

Ensure that the XML parser being utilised is set up to not parse XML entities.

确保所使用的 XML 解析器设置为不解析 XML 实体。

Switching Content Type 转换内容类型

Even though an API may use JSON as a data format to communicate, the underlying server/framework may still accept other data formats like XML. Therefore, when you see an API with a content-Type of application/json, you can still try testing for XXE by switching its value to Content-Type: text/xml

即使 API 可以使用 JSON 作为数据格式进行通信,底层服务器/框架仍然可以接受 XML 等其他数据格式。因此,当您看到一个包含 content-Type of application/json 的 API 时,仍然可以通过将其值切换为 content-Type: text/xml 来尝试对 XXE 进行测试

For example, if an API uses JSON:

例如,如果一个 API 使用 JSON:

POST /api/v1/user HTTP/1.1
Host: example.com
Content-Type: application/json

It can be modified to send XML data in this manner:

它可以修改为以这种方式发送 XML 数据:

POST /soap/v2/user HTTP/1.1
Host: example.com
Content-Type: text/xml

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE aa [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>

Mitigation 缓解措施

This bug only really exists on frameworks that are designed to accept multiple formats, where each format corresponds to a type of object. In these cases, the frameworks would normally have an option to whitelist available formats. It should be noted that this is quite rare in 2021.

这个缺陷只存在于设计用于接受多种格式的框架中,其中每种格式对应于一种对象类型。在这种情况下,框架通常可以选择白名单可用格式。值得注意的是,这在2021年是相当罕见的。

HTTP Methods

HTTP 方法

APIs usually support various types of HTTP methods. Some of the common ones are GET, POST, PATCH, DELETE and OPTIONS.If a GET request is sent at a point where an application expects a POST request, then this can lead to the application responding in unexpected ways.

Api 通常支持各种类型的 HTTP 方法。常见的有 GET、 POST、 PATCH、 DELETE 和 options.如果 GET 请求发送在应用程序需要 POST 请求的地方,那么这可能导致应用程序以意想不到的方式响应。

Let’s take CSRF as an example. CSRF (Cross-Site Request Forgery) is when an attacker tricks the victim into submitting a request which can cause state-changing actions to occur on the victim’s account. These changes can be anything from changing the victim’s personal details and in some cases, even changing the victim’s password leading to a full account takeover.

让我们以 CSRF 为例。CSRF (跨站请求伪造)是攻击者欺骗受害者提交一个请求,这可能导致受害者帐户上发生状态改变动作。这些改变可以是任何事情,从改变受害者的个人信息,在某些情况下,甚至改变受害者的密码,导致一个完整的帐户接管。

A normal request to change the victim’s personal details may look something like this:

一个改变受害者个人信息的正常请求可能看起来像这样:

POST /api/v1/user
Target: www.example.com
Content-Type: application/json

{
  "name","victim", 
  "email":"victim@example.com", 
  "location":"AU", 
  "csrftoken":"76hhs683bki0"
}

After observing the above request, we might conclude that a CSRF attack will not be possible since the csrftoken value is being sent in the request body. However, if an API does not restrict the HTTP methods which can be used for this request, then it may be possible for an attacker to bypass this protection by sending this request using the GET method.

在观察了上面的请求之后,我们可能会得出结论,CSRF 攻击是不可能的,因为 csrftoken 值是在请求主体中发送的。但是,如果 API 不限制可用于此请求的 HTTP 方法,那么攻击者可以通过使用 GET 方法发送此请求来绕过此保护。

GET /api/v1/user?name=hacked&email=attacker@example.com&location=FR
Target: www.example.com
Connection: close

Additionally, sometimes the server simply does not validate the CSRF token, or accepts the request if no CSRF token parameter exists at all in the request.

此外,有时服务器根本不验证 CSRF 令牌,或者在请求中根本不存在 CSRF 令牌参数时接受请求。

Another common vulnerability in REST APIs is when permissions have been correctly applied on an endpoint, but only for one HTTP verb. For example, you may not be able to GET other people’s records, but you may be able to edit their records by utilizing the PATCH verb.

REST api 中的另一个常见漏洞是,在端点上正确应用了权限,但只针对一个 HTTP 谓词。例如,您可能无法获取其他人的记录,但是您可以利用 PATCH 动词编辑他们的记录。

Mitigation 缓解措施

Manually specify HTTP verbs in your routes. Do not utilize verbs unnecessarily, and ensure that any endpoints that are specified do have the same controls applied against all verbs. Some frameworks will do this automatically, others will not.

在路由中手动指定 HTTP 谓词。不要不必要地使用动词,并确保指定的任何端点对所有动词都应用相同的控件。有些框架会自动完成这个任务,有些则不会。

Injection Vulnerabilities 注入漏洞

Server-side injection flaws like SQL injection, RCE, command injection and SSRF can exist on APIs in the same way they exist on regular web applications. Whenever any injected data is directly passed to the interpreter on the backend, it leaves room for an attacker to send targeted queries and commands to access internal data or execute arbitrary code.

服务器端注入缺陷,如 SQL 注入、 RCE、命令注入和 SSRF 等,可以像普通 web 应用程序一样存在于 api 上。每当任何注入的数据被直接传递给后端的解释器时,攻击者就有空间发送目标查询和命令来访问内部数据或执行任意代码。

For example, let’s test SSRF on the following API request:

例如,让我们在下面的 API 请求上测试 SSRF:

POST /api/v1/user
Target: www.example.com
Content-Type: application/json

{
  "name","victim", 
  "email":"victim@example.com", 
  "profile_pic_url":"https://www.example.com/me.jpg"
}

An attacker can attempt SSRF on the website field by sending a request like this:

攻击者可以在网站字段上尝试 SSRF,发送如下请求:

POST /api/v1/user
Target: www.example.com
Content-Type: application/json

{
  "name","victim", 
  "email":"victim@example.com", 
  "profile_pic_url":"http://localhost/admin"
}

If the backend interpreter does not validate the profile_pic_url value properly, then this can lead to an attacker exploiting SSRF and successfully accessing internal data.

如果后端解释器没有正确验证 profile _ pic _ url 值,那么这可能导致攻击者利用 SSRF 成功访问内部数据。

Similarly, an attacker can also attempt SQL injection if the data on this request is improperly validated:

类似地,如果该请求上的数据被不正确地验证,攻击者也可以尝试 SQL 注入:

POST /api/v1/orders
Target: www.example.com
Content-Type: application/json

{
  "offset":0,
  "limit":10,
  "scope":"orders_all",
}

By looking at the request body, we may get a hint that the values of these parameters are being sent to a backend database interpreter. Therefore, we can attempt SQL injection by modifying these values to targeted queries:

通过查看请求主体,我们可能会得到一个提示,即这些参数的值正在被发送到后端数据库解释器。因此,我们可以通过修改这些值来尝试 SQL 注入:

POST /api/v1/orders
Target: www.example.com
Content-Type: application/json

{
  "offset":0,
  "limit":10,
  "scope":"SELECT sleep(10)",
}

Once again, if the interpreter does not validate these values properly, then this can lead to a SQL injection where an attacker can cause a time delay in the database and even exfiltrate sensitive data.

再一次,如果解释器没有正确验证这些值,那么这可能导致 SQL 注入,攻击者可能在数据库中造成时间延迟,甚至可能将敏感数据转移出去。

Mitigation 缓解措施

Mitigating injection vulnerabilities in APIs is essentially the same as mitigating injection vulnerabilities in web applications. SAST/DAST scanners can help with this, but secure development practices are the best mitigation. Parameterize SQL queries, utilise ORMs and reputable libraries where possible, don’t trust user input!

缓解 api 中的注入漏洞与缓解 web 应用中的注入漏洞基本上是一样的。SAST/DAST 扫描器可以帮助解决这个问题,但是安全开发实践是最好的缓解方法。参数化 SQL 查询,尽可能使用 orm 和可信的库,不要相信用户输入!


Written by:
Hakluke and Farah Hawa
Detectify Crowdsource community members

作者: Hakluke 和 Farah Hawa Detectify Crowdsource 社区成员

Hakluke
A photo of Hakluke

My name is Luke Stephens but most know me as hakluke. I am currently living on the Sunshine Coast, in Australia. I recently resigned from my role as the Manager of Training and Quality Assurance for Bugcrowd to start my own consultancy, Haksec. I do a lot of penetration testing and bug bounties and create content for hackers. Check out my Youtube channel.

我的名字是卢克 · 斯蒂芬斯,但大多数人都知道我是哈克 · 卢克。我现在住在澳大利亚的阳光海岸。我最近辞去了培训和质量保证经理的职位,开始了我自己的咨询公司 Haksec。我做了很多渗透测试和 bug 赏金,并为黑客创建内容。看看我的 Youtube 频道。

Farah Hawa
Photo of Farah Hawa

法拉赫 · 哈瓦

Farah Hawa is from Mumbai, India. She works as an Application Security Engineer at Bugcrowd. She’s a part-time bug bounty hunter and also creates technical content for bug bounty hunters & web application pentesters for her YouTube channel with more than 30000 subscribers. You can also find her on LinkedIn.

来自印度孟买。她是 Bugcrowd 的应用安全工程师。她是一个兼职的 bug 赏金猎人,同时也为她拥有超过30000订阅者的 YouTube 频道的 bug 赏金猎人和 web 应用程序五角星创建技术内容。你也可以在 LinkedIn 上找到她。

Read More »

【转载】【漏洞分析】Critical Valve Bug Lets Gamers Add Unlimited Funds to Steam Wallets

A security researcher helped Valve, the makers of the gaming platform Steam, plug an easy-to-exploit hole that allowed users to add unlimited funds to their digital wallet. Simply by changing the account’s email address, the exploit allowed anyone to artificially boost their digital billfold to anything they wanted.

一位安全研究人员帮助游戏平台 Steam 的制造商 Valve 堵住了一个容易被利用的漏洞,这个漏洞允许用户向他们的数字钱包中添加无限的资金。仅仅通过改变账户的电子邮件地址,这个漏洞就可以让任何人人为地把他们的数字钱包提高到他们想要的任何东西。

Steam Wallet funds are exclusive to the Steam platform and are used to purchase in-game merchandise, subscriptions and Steam-related content. Valve restricts Steam credits (or money) from being transferred outside its network for purchase or trading. However, there are several unsanctioned ways to convert wallet funds into actual dollars.

Steam Wallet 基金是 Steam 平台的专用资金,用于购买游戏中的商品、订阅和 Steam 相关内容。Valve 限制 Steam 信贷(或货币)在其网络之外进行购买或交易。然而,有几种未经批准的方式将钱包基金转换成实际的美元。

Working for the HackerOne bug-bounty program, security researcher DrBrix, reported the bug last Monday. By Wednesday, Valve plugged the hole and paid DrBrix $7,500 for identifying the bug.

安全研究员 DrBrix 上周一报告了这个漏洞。到了周三,Valve 堵住了漏洞,并支付给 DrBrix 7500美元来识别漏洞。

The Hack: Turning $1 into $100 or $1M

黑客: 把1美元变成100美元或100万美元

The bug, which has since been patched, was exploited by abusing Valve’s own application programming interface (API) used to communicate with the third-party web payment firm Smart2Pay, owned by Nuvei.

这个漏洞后来得到了修补,但它被用来滥用 Valve 自己的应用程序编程接口(API)来与 Nuvei 旗下的第三方网络支付公司 Smart2Pay 进行通信的做法所利用。

According to DrBrix, the hack allowed an attacker to intercept the POST request sent from Valve to Smart2Pay. This was done via modifying the Steam user’s email address used by Smart2Pay as it passed through the Valve API.

根据 DrBrix 的说法,黑客可以拦截 Valve 发送给 Smart2Pay 的 POST 请求。这是通过修改 Steam 用户在通过 Valve API 时使用的电子邮件地址完成的。

“Firstly you will have to change yours steam account email to something like (I will explain why in next steps, amount100 is the important part): brixamount100abc@█████,” the researcher wrote.

研究人员写道: “首先,你必须把你的邮箱改成类似于(我会解释为什么接下来的步骤中 amount100是最重要的部分) : brixamount100abc@gmail。

This allows the attacker to manipulate communications between Valve and Smart2Pay, circumventing the cryptographic hash used to protect transaction data.

这允许攻击者操作 Valve 和 Smart2Pay 之间的通信,绕过用于保护交易数据的加密散列。

“We can’t change parameters as there is Hash field with signature, however signature is generated like that hash (ALL_FIELDS_NAMES_VALUES_CONTACTED),” DrBrix wrote. “So with our special email we can move parameters in a way that will change amount for us.”

DrBrix 写道: “我们不能改变参数,因为存在带签名的 Hash 字段,但是生成的签名类似于 Hash (ALL _ fields _ names _ values _ contacted)。”。“因此,通过我们的特殊电子邮件,我们可以移动参数,这将改变我们的数量。”

Where the Valve parameters might be,

阀门参数可能在哪里,

“hash(MerchantID1102MerchantTransactionID█████Amount2000…..)” the attacker can turn $1 into $100 simply by changing the format of the email request.

攻击者只需改变电子邮件请求的格式,就可以将 $1变成 $100。

“So with our special email we can move parameters in a way that will change amount for us. For example, we can change original Amount=2000 to Amount2=000 and after contacting it still will be Amount2000. Then we can change email from CustomerEmail=brixamount100abc%40████ to CustomerEmail=brix&amount=100&ab=c%40█████████ by this we are adding new field amount with our value,” DrBrix wrote.

Valve first rated the bug as of moderate importance. However, after investigating, it escalated the bug to critical in nature, scoring it “9-10”, with the highest possible rating 10.

阀门首先将这个漏洞评定为中等重要。然而,在调查之后,这个漏洞升级为本质上的严重漏洞,得到了“9-10”的评分,最高可能的评分为10。

Valve did not return a Threatpost press request for comment.

Valve 没有回复威胁邮报的置评请求。

【转载】【漏洞分析】Facebook Email/phone disclosure using Binary search


So in December I decided to hunt on Facebook, and chose to go with the Facebook Android App

所以在12月,我决定在 Facebook 上搜索,并选择了 Facebook Android 应用

I was analyzing the Facebook app’s password recovery flow.

我正在分析 Facebook 应用的密码恢复流程。

I noticed that the following endpoint was being used.

我注意到正在使用以下端点。

When a user enters his email/phone number his email is supplied in the following manner using parameter `q`

当用户输入他的电子邮件/电话号码时,他的电子邮件以下面的方式使用参数‘ q’提供

The endpoint contained manyyyyy parameters, more than it required.

端点包含许多 yyy 参数,超过了所需的参数。

So I was eager to test what those parameters did.

所以我急于测试这些参数的作用。

I quickly noticed that although the user’s email is being carried by `q` parameter, it also contains a `qs` parameter.

我很快注意到,虽然用户的电子邮件是通过‘ q’参数进行的,但它也包含一个‘ qs’参数。

Now, incase you don’t know;
In Facebook the character `s` behind a parameter means plural.

现在,以防你不知道; 在 Facebook 中,隐藏在参数后面的字符是复数的意思。

Example:
invite_id, Plural= invite_ids
user_id, Plural=user_ids

例如: invite _ id,Plural = invite _ ids user _ id,Plural = user _ ids

I knew that in plural parameters you can supply array of data
like:
user_ids=[“UserID1”,”UserID2″]

我知道可以使用复数参数提供数据数组,比如: user _ ids = [“ UserID1”,“ UserID2”]

so I supplied data in following manner:

因此,我以下列方式提供数据:

qs=[“vicitmemail1@gmail.com”,”victimemail2@gmail.com”]

[ vicitmemail1@gmail. com,vicemail2@gmail. com ]

But it gave an error stating the array key are invalid.

但是它给出了一个错误,说明数组键是无效的。

So this wasn’t a normal array, it had its own keys.

所以这不是一个普通的数组,它有自己的键。

So after some fuzzing I finally figured out that the parameter `qs` takes the value in json wrapped format along with the keys “phone” and “email” and the values of email/phone are the ones that will be supplied as an array

所以经过一些模糊处理之后,我最终发现参数‘ qs’将以 json 包装格式获取值,同时键“ phone”和“ email”以及 email/phone 的值将作为数组提供

Example:
q=victim@gmail.com
qs={“email”:[“
victim@gmail.com”],”phone”:[“981234567890”]}

例如: q = victim@gmail. com qs = {“ email”: [“ victim@gmail. com”] ,“ phone”: [“981234567890”]}

Now,
When you supply an email in the forget password endpoint, the data belonging to you is given in the response in encrypted format.

现在,当您在忘记密码端点中提供电子邮件时,属于您的数据将以加密格式在响应中给出。

The response will contain:
your encrypted userID ,contact points etc

响应将包含: 您的加密用户标识、联系人等

Along with the data there was a value `summary` and it was set to `1`.

除了数据之外,还有一个值“汇总”,它被设置为“1”。

Initially I thought it to be a Boolean.
But turns out:

起初我以为它是一个布尔值,但结果发现:

When we supply one email in `qs`
qs={“email”:[“user1@gmail.com”]}
Data of one user is obtained in response.
hence: summary=1

当我们提供‘ qs’= {“ email”: [“ user1@gmail. com”]}一个用户的数据作为响应获得,因此: summary = 1

When we supply two emails in `qs`
qs={“email”:[“user1@gmail.com”,”user2@gmail.com”]}
Data of two users is obtained in response.
Hence: summary=2

当我们提供“ qs”= {“ email”: [“ user1@gmail. com”,“ user2@gmail. com”]中的两封电子邮件时,会得到两个用户的回复数据,因此: summary = 2

But here comes the final part:

但是最后一部分来了:

Lets say I supply:
qs={“email”:[“victim1@gmail.com”,”victim2@gmail.com]}
Data of only 1 user is obtained.

比如说我提供: qs = {”email”: [“ victimit1@gmail. com”,“ victimit2@gmail. com ]}仅获得一个用户的数据。

What does that mean?
Both the emails belong to the same user and both emails pointed to same user resulting in the response “summary”:1

这是什么意思?两封电子邮件都属于同一个用户,而且两封电子邮件都指向同一个用户,结果得到的回复是“摘要”: 1

Now, basically it was bruteforce attack scenario.

现在,基本上这是一个残暴的攻击场景。

I supply victim’s username along with a email and if the email belonged to victim the response is “summary:1”

我提供受害者的用户名和电子邮件一起,如果电子邮件属于受害者的回复是“摘要: 1”

qs={“email”:[“victimUserName”,”Email”]}

Qs = {“ Email”: [“ victimUserName”,“ Email”]}

//Yup, We can supply username in email parameter

//是的,我们可以在 email 参数中提供用户名

 

BinarySearch to the rescue

搜索救援

Bruteforce attacks are noisyyy.
But using binary search, this attack became much easier.

野蛮部队的攻击是噪音的。但是使用二进制搜索,这种攻击变得容易得多。

Refer to this video to learn about BinarySearch:

参考这个视频来了解 BinarySearch:

Since, the endpoint was accepting an array of data:
I wasn’t forced to only submit
1 username+1 email

因为,端点是接受一系列的数据: 我没有被迫只提交1个用户名 + 1个电子邮件

I could supply
1username+ 100s of email.

我可以提供1个用户名 + 100个电子邮件。

Example;

例子;

qs={“email”:[“victimUserName”,”email1@gmail.com”,”email2@gmail.com”,”email3@gmail.com”]}

Qs = {“ email”: [“ victimUserName”,“ email1@gmail. com”,“ email2@gmail. com”,“ email3@gmail. com”]}

Now if any of the email from the request belonged to vicitmUserName:

现在,如果请求中的任何电子邮件属于 vicitmUserName:

Summary=3
//Response of email1+email2+email3

3//回复邮件1 + 邮件2 + 邮件3

Else summary=4
//Response of vicitmUsername+email1+email2+email3

4///响应 vicitmUsername + email1 + email2 + email3

This made it easier to bruteforce and effectively identify any user’s private email.

这样可以更容易地强制和有效地识别任何用户的私人电子邮件。

Diagram demonstrating the binarySearch

示范 binarySearch 的图表

I also received this sweeeet response from the Facebook team,
felt good 😉

我也收到了来自 Facebook 团队的甜蜜回复,感觉很好;)

Timeline
Submitted : January 3
Triaged: February 13
Bounty $XXXX Awarded :March 22

递交时间表: 1月3日分流: 2月13日赏金: XXXX: 3月22日