Write-Ups
Write-Ups
Write-Ups
  • 📙Write-Ups
  • 🔋Hack The Box
    • đŸ•šī¸Challenges
      • 🎰AI - ML
        • â˜„ī¸AI SPACE
      • â›“ī¸Blockchain
        • 🤸Survival of the Fittest
      • 🔮Crypto
        • đŸ‘ļBaby Time Capsule
        • đŸ•ēThe Last Dance
      • âĒReversing
        • BabyEncryption
        • 🌒Behind the Scenes
        • đŸŖBabyEncryption
        • 💹Simple Encryptor
      • đŸŽ›ī¸Hardware
        • 💉The Needle
        • 🔏Photon Lockdown
      • đŸĨ¸OSINT
        • 💸Money Flowz
      • đŸ•¸ī¸Web
        • đŸ´â€â˜ ī¸Flag Command
        • 💓LoveTok
        • đŸ—’ī¸PDFy
        • jscalc
        • 🙈ProxyAsAService
        • ApacheBlaze
        • ❓RenderQuests
        • đŸ’ĨNeonify
        • 😑No Treshold
        • 🎑Breathtaking View
    • 🏰Fortress
      • đŸĻ™AWS
    • đŸ’ģMachines
      • 🎒Backfire
      • đŸ’ĨBigBang
      • 🐈‍âŦ›Cat
      • âœ”ī¸Checker
      • đŸļDog
      • 🧧Environment
      • 👮EscapeTwo
      • âšœī¸Eureka
      • đŸĻNocturnal
      • 🔞UnderPass
      • đŸšĸTitanic
      • TheFrizz
      • 🐰WhiteRabbit
    • 🧐Sherlocks
      • Meerkat
      • Bumblebee
    • đŸĨŧProLabs
      • 🃏FullHouse
    • 💀Season 8
    • đŸĻ“Scripts/Functions/Tools
  • 💔PortSwigger
    • đŸ›Ŗī¸Learning Path
      • â™ŋApi testing
        • Lab: Exploiting an API endpoint using documentation
        • Lab: Finding and exploiting an unused API endpoint
        • Lab: Exploiting a mass assignment vulnerability
        • Lab: Exploiting server-side parameter pollution in a query string
      • 🔐Authentication vulnerabilities
        • Lab: Username enumeration via different responses
        • Lab: Username enumeration via subtly different responses
        • Lab: Username enumeration via response timing
        • Lab: Broken brute-force protection, IP block
        • Lab: Username enumeration via account lock
        • Lab: 2FA simple bypass
        • Lab: 2FA broken logic
        • Lab: Brute-forcing a stay-logged-in cookie
        • Lab: Offline password cracking
        • Lab: Password reset broken logic
        • Lab: Password reset poisoning via middleware
        • Lab: Password brute-force via password change
      • 📁File upload vulnerabilities
        • Lab: Remote code execution via web shell upload
        • Lab: Web shell upload via Content-Type restriction bypass
        • Lab: Web shell upload via path traversal
      • 📉GraphQL API vulnerabilities
        • Lab: Accessing private GraphQL posts
        • Lab: Accidental exposure of private GraphQL fields
        • Lab: Finding a hidden GraphQL endpoint
        • Lab: Bypassing GraphQL brute force protections
        • Lab: Performing CSRF exploits over GraphQL
      • đŸ–Ĩī¸Server-side vulnerabilities
        • đŸ›¤ī¸Path traversal
          • Lab: File path traversal, simple case
        • 🛂Access control
          • Lab: Unprotected admin functionality
          • Lab: Unprotected admin functionality with unpredictable URL
          • Lab: User role controlled by request parameter
          • Lab: User ID controlled by request parameter, with unpredictable user IDs
          • Lab: User ID controlled by request parameter with password disclosure
        • 🔐Authentication
          • Lab: Username enumeration via different responses
        • đŸ–Ĩī¸Server-side request forgery(SSRF)
          • SSRF attacks against the server
          • Lab: Basic SSRF against the local server
          • Lab: Basic SSRF against another back-end system
        • 🆙File upload vulnerabilities
          • Lab: Remote code execution via web shell upload
          • Lab: Web shell upload via Content-Type restriction bypass
        • 👊OS command injection
          • Lab: OS command injection, simple case
        • 💉SQL injection (SQLi)
          • Lab: SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
          • Lab: SQL injection vulnerability allowing login bypass
      • đŸ§ĻWebSockets
        • Lab: Manipulating WebSocket messages to exploit vulnerabilities
        • Lab: Manipulating the WebSocket handshake to exploit vulnerabilities
        • Lab: Cross-site WebSocket hijacking
Powered by GitBook
On this page
  • Finding GraphQL endpoints
  • Universal queries
  • Common endpoint names
  • Request methods
  • Exploiting unsanitized arguments
  • Discovering schema information
  • Using introspection
  • Probing for introspection
  • Running a full introspection query
  • Visualizing introspection results
  • Suggestions
  • Bypassing GraphQL introspection defenses
  • Bypassing rate limiting using aliases
  • GraphQL CSRF
  • How do CSRF over GraphQL vulnerabilities arise?
  • Preventing GraphQL attacks
  • Preventing GraphQL brute force attacks
  • Preventing CSRF over GraphQL
  1. PortSwigger
  2. Learning Path

GraphQL API vulnerabilities

https://portswigger.net/web-security/learning-paths/graphql-api-vulnerabilities/finding-graphql-endpoints/graphql/finding-graphql-endpoints

Finding GraphQL endpoints

Before you can test a GraphQL API, you first need to find its endpoint. As GraphQL APIs use the same endpoint for all requests, this is a valuable piece of information.

Universal queries

If you send query{__typename} to any GraphQL endpoint, it will include the string {"data": {"__typename": "query"}} somewhere in its response. This is known as a universal query, and is a useful tool in probing whether a URL corresponds to a GraphQL service.

The query works because every GraphQL endpoint has a reserved field called __typename that returns the queried object's type as a string.

Common endpoint names

GraphQL services often use similar endpoint suffixes. When testing for GraphQL endpoints, you should look to send universal queries to the following locations:

  • /graphql

  • /api

  • /api/graphql

  • /graphql/api

  • /graphql/graphql

If these common endpoints don't return a GraphQL response, you could also try appending /v1 to the path.

Request methods

The next step in trying to find GraphQL endpoints is to test using different request methods.

It is best practice for production GraphQL endpoints to only accept POST requests that have a content-type of application/json, as this helps to protect against CSRF vulnerabilities. However, some endpoints may accept alternative methods, such as GET requests or POST requests that use a content-type of x-www-form-urlencoded.

If you can't find the GraphQL endpoint by sending POST requests to common endpoints, try resending the universal query using alternative HTTP methods.

Exploiting unsanitized arguments

At this point, you can start to look for vulnerabilities. Testing query arguments is a good place to start.

If the API uses arguments to access objects directly, it may be vulnerable to access control vulnerabilities. A user could potentially access information they should not have simply by supplying an argument that corresponds to that information. This is sometimes known as an insecure direct object reference (IDOR).

For example, the query below requests a product list for an online shop:

#Example product query query { products { id name listed } }

The product list returned contains only listed products.

#Example product response { "data": { "products": [ { "id": 1, "name": "Product 1", "listed": true }, { "id": 2, "name": "Product 2", "listed": true }, { "id": 4, "name": "Product 4", "listed": true } ] } }

From this information, we can infer the following:

  • Products are assigned a sequential ID.

  • Product ID 3 is missing from the list, possibly because it has been delisted.

By querying the ID of the missing product, we can get its details, even though it is not listed on the shop and was not returned by the original product query.

#Query to get missing product query { product(id: 3) { id name listed } } #Missing product response { "data": { "product": { "id": 3, "name": "Product 3", "listed": no } } }

Discovering schema information

The next step in testing the API is to piece together information about the underlying schema.

The best way to do this is to use introspection queries. Introspection is a built-in GraphQL function that enables you to query a server for information about the schema.

Introspection helps you to understand how you can interact with a GraphQL API. It can also disclose potentially sensitive data, such as description fields.

Using introspection

To use introspection to discover schema information, query the __schema field. This field is available on the root type of all queries.

Like regular queries, you can specify the fields and structure of the response you want to be returned when running an introspection query. For example, you might want the response to contain only the names of available mutations.

Probing for introspection

It is best practice for introspection to be disabled in production environments, but this advice is not always followed.

You can probe for introspection using the following simple query. If introspection is enabled, the response returns the names of all available queries.

#Introspection probe request { "query": "{__schema{queryType{name}}}" }

Running a full introspection query

The next step is to run a full introspection query against the endpoint so that you can get as much information on the underlying schema as possible.

The example query below returns full details on all queries, mutations, subscriptions, types, and fragments.

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

Visualizing introspection results

Responses to introspection queries can be full of information, but are often very long and hard to process.

You can view relationships between schema entities more easily using a GraphQL visualizer. This is an online tool that takes the results of an introspection query and produces a visual representation of the returned data, including the relationships between operations and types.

Suggestions

Even if introspection is entirely disabled, you can sometimes use suggestions to glean information on an API's structure.

Suggestions are a feature of the Apollo GraphQL platform in which the server can suggest query amendments in error messages. These are generally used where a query is slightly incorrect but still recognizable (for example, There is no entry for 'productInfo'. Did you mean 'productInformation' instead?).

You can potentially glean useful information from this, as the response is effectively giving away valid parts of the schema.

Clairvoyance is a tool that uses suggestions to automatically recover all or part of a GraphQL schema, even when introspection is disabled. This makes it significantly less time consuming to piece together information from suggestion responses.

You cannot disable suggestions directly in Apollo. See this GitHub thread for a workaround.

Bypassing GraphQL introspection defenses

If you cannot get introspection queries to run for the API you are testing, try inserting a special character after the __schema keyword.

When developers disable introspection, they could use a regex to exclude the __schema keyword in queries. You should try characters like spaces, new lines and commas, as they are ignored by GraphQL but not by flawed regex.

As such, if the developer has only excluded __schema{, then the below introspection query would not be excluded.

#Introspection query with newline { "query": "query{__schema {queryType{name}}}" }

If this doesn't work, try running the probe over an alternative request method, as introspection may only be disabled over POST. Try a GET request, or a POST request with a content-type of x-www-form-urlencoded.

The example below shows an introspection probe sent via GET, with URL-encoded parameters.

# Introspection probe as GET request GET /graphql?query=query%7B__schema%0A%7BqueryType%7Bname%7D%7D%7D

Bypassing rate limiting using aliases

Ordinarily, GraphQL objects can't contain multiple properties with the same name. Aliases enable you to bypass this restriction by explicitly naming the properties you want the API to return. You can use aliases to return multiple instances of the same type of object in one request.

While aliases are intended to limit the number of API calls you need to make, they can also be used to brute force a GraphQL endpoint.

Many endpoints will have some sort of rate limiter in place to prevent brute force attacks. Some rate limiters work based on the number of HTTP requests received rather than the number of operations performed on the endpoint. Because aliases effectively enable you to send multiple queries in a single HTTP message, they can bypass this restriction.

The simplified example below shows a series of aliased queries checking whether store discount codes are valid. This operation could potentially bypass rate limiting as it is a single HTTP request, even though it could potentially be used to check a vast number of discount codes at once.

#Request with aliased queries query isValidDiscount($code: Int) { isvalidDiscount(code:$code){ valid } isValidDiscount2:isValidDiscount(code:$code){ valid } isValidDiscount3:isValidDiscount(code:$code){ valid } }

GraphQL CSRF

Cross-site request forgery (CSRF) vulnerabilities enable an attacker to induce users to perform actions that they do not intend to perform. This is done by creating a malicious website that forges a cross-domain request to the vulnerable application.

GraphQL can be used as a vector for CSRF attacks, whereby an attacker creates an exploit that causes a victim's browser to send a malicious query as the victim user.

How do CSRF over GraphQL vulnerabilities arise?

CSRF vulnerabilities can arise where a GraphQL endpoint does not validate the content type of the requests sent to it and no CSRF tokens are implemented.

POST requests that use a content type of application/json are secure against forgery as long as the content type is validated. In this case, an attacker wouldn't be able to make the victim's browser send this request even if the victim were to visit a malicious site.

However, alternative methods such as GET, or any request that has a content type of x-www-form-urlencoded, can be sent by a browser and so may leave users vulnerable to attack if the endpoint accepts these requests. Where this is the case, attackers may be able to craft exploits to send malicious requests to the API.

Preventing GraphQL attacks

To prevent many common GraphQL attacks, take the following steps when you deploy your API to production:

  • If your API is not intended for use by the general public, disable introspection on it. This makes it harder for an attacker to gain information about how the API works, and reduces the risk of unwanted information disclosure.

    For information on how to disable introspection in the Apollo GraphQL platform, see this blog post.

  • If your API is intended for use by the general public then you will likely need to leave introspection enabled. However, you should review the API's schema to make sure that it does not expose unintended fields to the public.

  • Make sure that suggestions are disabled. This prevents attackers from being able to use Clairvoyance or similar tools to glean information about the underlying schema.

    You cannot disable suggestions directly in Apollo. See this GitHub thread for a workaround.

  • Make sure that your API's schema does not expose any private user fields, such as email addresses or user IDs.

Preventing GraphQL brute force attacks

It is sometimes possible to bypass standard rate limiting when using GraphQL APIs. For an example of this, see the Bypassing rate limiting using aliases section.

With this in mind, there are design steps that you can take to defend your API against brute force attacks. This generally involves restricting the complexity of queries accepted by the API, and reducing the opportunity for attackers to execute denial-of-service (DoS) attacks.

To defend against brute force attacks:

  • Limit the query depth of your API's queries. The term "query depth" refers to the number of levels of nesting within a query. Heavily-nested queries can have significant performance implications, and can potentially provide an opportunity for DoS attacks if they are accepted. By limiting the query depth your API accepts, you can reduce the chances of this happening.

  • Configure operation limits. Operation limits enable you to configure the maximum number of unique fields, aliases, and root fields that your API can accept.

  • Configure the maximum amount of bytes a query can contain.

  • Consider implementing cost analysis on your API. Cost analysis is a process whereby a library application identifies the resource cost associated with running queries as they are received. If a query would be too computationally complex to run, the API drops it.

Preventing CSRF over GraphQL

To defend against GraphQL CSRF vulnerabilities specifically, make sure of the following when designing your API:

  • Your API only accepts queries over JSON-encoded POST.

  • The API validates that content provided matches the supplied content type.

  • The API has a secure CSRF token mechanism.

Last updated 3 months ago

💔
đŸ›Ŗī¸
📉