Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save BuffaloWill/a50c7fe465b98884ed42e1a94aaea56c to your computer and use it in GitHub Desktop.
Save BuffaloWill/a50c7fe465b98884ed42e1a94aaea56c to your computer and use it in GitHub Desktop.

Revisions

  1. BuffaloWill created this gist Sep 26, 2024.
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,102 @@
    ## Summary

    This document has references and notes from the OWASP Global AppSec 2024 talk; "GraphQL Exploitation: Secondary Context Attacks and Business Logic Vulnerabilities".

    ## Author

    * Github: [BuffaloWill](https://github.com/BuffaloWill)
    * LinkedIn: [Will Vandevanter](https://www.linkedin.com/in/willis-vandevanter-82a05018/)

    ##

    ### Secondary Context Attacks References

    * Hacking Starbucks and Accessing Nearly 100 Million Customer Records - Sam Curry 06/20/2020
    * [https://samcurry.net/hacking-starbucks](https://samcurry.net/hacking-starbucks)
    * Leaked Secrets and Unlimited Miles: Hacking the Largest Airline and Hotel Rewards Platform - Sam Curry 08/03/2023
    * [https://samcurry.net/points-com](https://samcurry.net/points-com)
    * KernelCon 2020: Attacking Secondary Contexts in Web Applications - Sam Curry
    * [https://www.youtube.com/watch?v=hWmXEAi9z5w](https://www.youtube.com/watch?v=hWmXEAi9z5w)

    ### Tool References

    * [https://github.com/BuffaloWill/burpsuite-project-file-parser](https://github.com/BuffaloWill/burpsuite-project-file-parser)

    ### Defense References
    * [GraphQL Scalars - https://the-guild.dev/graphql/scalars/docs](https://the-guild.dev/graphql/scalars/docs)
    * [Escape Tech - How To Secure GraphQL APIs](https://escape.tech/blog/how-to-secure-graphql-apis/)

    ### Bambadas Code

    GraphQL Operation Name in URL

    ```
    return requestResponse.request().parameterValue("operationName", HttpParameterType.URL);
    ```

    Show Content Type in Table Column:

    ```
    return requestResponse.request().headerValue("Content-Type");
    ```

    Highlight a request if it has ID! in it. This gets kind of janky trying to pull the mutation or query name:

    ```
    // Get the request body
    String body = requestResponse.request().bodyToString();
    if (body.contains("ID!") || body.contains("String!")) {
    requestResponse.annotations().setHighlightColor(HighlightColor.RED);
    }
    // Check for POST requests (most common for GraphQL)
    if (requestResponse.request().method().equals("POST")) {
    try {
    // Pattern to match mutations, including inline definitions and input parameters
    Pattern mutationPattern = Pattern.compile("\"mutation\"\\s*:\\s*\"\\s*(mutation\\s+(\\w+)(\\([^)]*\\))?|mutation)\\s*\\{|\"mutation\"\\s*:\\s*\"mutation\\s+(\\w+)(\\([^)]*\\))?");
    Matcher mutationMatcher = mutationPattern.matcher(body);
    if (mutationMatcher.find()) {
    String operationName = mutationMatcher.group(2) != null ? mutationMatcher.group(2) : mutationMatcher.group(4);
    String inputs = mutationMatcher.group(3) != null ? mutationMatcher.group(3) :
    (mutationMatcher.group(5) != null ? mutationMatcher.group(5) : "");
    if (operationName != null && !operationName.isEmpty()) {
    return "mutation " + operationName + inputs;
    } else {
    return "mutation (unnamed)" + inputs;
    }
    }
    // If no mutation found, check for queries
    Pattern queryPattern = Pattern.compile("\"query\"\\s*:\\s*\"\\s*(query\\s+(\\w+)(\\([^)]*\\))?|query)\\s*\\{|\"query\"\\s*:\\s*\"query\\s+(\\w+)(\\([^)]*\\))?");
    Matcher queryMatcher = queryPattern.matcher(body);
    if (queryMatcher.find()) {
    String operationName = queryMatcher.group(2) != null ? queryMatcher.group(2) : queryMatcher.group(4);
    String inputs = queryMatcher.group(3) != null ? queryMatcher.group(3) :
    (queryMatcher.group(5) != null ? queryMatcher.group(5) : "");
    if (operationName != null && !operationName.isEmpty()) {
    return "query " + operationName + inputs;
    } else {
    return "query (unnamed)" + inputs;
    }
    }
    } catch (Exception e) {
    // If parsing fails, try to find GraphQL operations in raw body
    Pattern rawPattern = Pattern.compile("(mutation|query)\\s+(\\w+)(\\([^)]*\\))?");
    Matcher rawMatcher = rawPattern.matcher(body);
    if (rawMatcher.find()) {
    String inputs = rawMatcher.group(3) != null ? rawMatcher.group(3) : "";
    return rawMatcher.group(1) + " " + rawMatcher.group(2) + inputs;
    } else {
    // Check for unnamed operations
    Pattern unnamedPattern = Pattern.compile("(mutation|query)\\s*(\\([^)]*\\))?\\s*\\{");
    Matcher unnamedMatcher = unnamedPattern.matcher(body);
    if (unnamedMatcher.find()) {
    String inputs = unnamedMatcher.group(2) != null ? unnamedMatcher.group(2) : "";
    return unnamedMatcher.group(1) + " (unnamed)" + inputs;
    }
    }
    }
    }
    ```