SSTエンジニアブログ

SSTのエンジニアによるWebセキュリティの技術を中心としたエンジニアブログです。

Burp SuiteのGraphQL手動検査ツールさわってみた

はじめに

本記事は、Burp Suite 2023.11.1.3の安定版リリースで追加された、GraphQLの手動検査ツール機能に関する紹介記事になります。

原文をご確認されたい方は、公式のリリースノートをご覧ください。

portswigger.net

機能紹介

これまでのGraphQLに関する機能では、Burp ScannerによるGraphQLの検査が可能でしたが、手動による検査は(Burpだけで行うなら)GraphQL構文を操作するためのExtenderを利用するしかありませんでした。 いくつかGraphQL用のExtenderはありますが、有名どころだとinQLが挙げられます。

github.com

ですが、今回のリリースでExtender無しでGraphQLを操作することができるようになりました。具体的には以下の機能がリリースされています。

  • GraphQL リクエストの表示と編集
  • イントロスペクションクエリの生成

それぞれどのような機能なのか実際に試してみます。

GraphQL リクエストの表示と編集

GraphQLのエンドポイントにアクセスすると、Burpは自動的にGraphQLエンドポイントを検出するようです。 検出後、GraphQL用のタブが表示・選択できるようになり、GraphQLのシンタックスを解析してくれます。 リクエストをRepeaterに移動させて、QueryやVariablesを改変して送信することができます。

GraphQLタブが表示されている

GraphQLの編集画面

イントロスペクションクエリの生成

イントロスペクションクエリは、GraphQLのエンドポイントリクエストをRepeaterに移し、コンテキストメニューから生成することができます。

生成できるイントロスペクションクエリは、通常のものとlegacyタイプの2種類がありました。

通常のイントロスペクションクエリ

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

Legacyイントロスペクションクエリ

query IntrospectionQuery {
  __schema {
    queryType {
      name
    }
    mutationType {
      name
    }
    types {
      ...FullType
    }
    directives {
      name
      description
      args {
        ...InputValue
      }
      onOperation
      onFragment
      onField
    }
  }
}

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

イントロスペクションクエリのレスポンスを受け取ることで、コンテキストメニューの「Save GraphQL queries to site map」が有効になります。 サイトマップ登録機能は、イントロスペクションクエリの結果をもとにクエリを解析し、未送信の状態でサイトマップに登録されます。

未送信リクエストは、コンテキストメニューの「Request in browser」で送信することができます。 送信後、サイトマップ上では灰色から白色に変わり、レスポンスも受け取れています。

IDなどのArgumentsが必要なクエリは、セット可能なVariablesを用意してくれます。ただし、Variablesのvalueは空や0の状態なので、手動で変更する必要があります。

例えば、以下の画像はサイトマップに登録されたGraphQLクエリの一部です。

このクエリは、 personID を引数として持っているため、このリクエストをそのまま送信してもpersonID がnullでエラーが返ってきます。

この場合は、Repeaterにリクエストを送り、 personID を変えて送信すると指定したPerson情報を取得することができます。

Repeaterの送信結果

まとめ

イントロスペクションクエリを自動で飛ばさない、サイトマップに登録されるクエリも自動で飛ばさない、Variablesは空や初期値がセットされている点が、人が手動で診断する前提の作りとなっていて、とても診断しやすくなったと感じました。
これまで、クエリドキュメントが公開されているアプリケーションであっても、診断員がドキュメントを見て各クエリを作成するのが大変でした。今回の機能でクエリがほぼ自動でフォーマットとして用意され、診断員は必要な値をVariablesに入れたり、クエリを変更したりといった作業だけで診断が出来るようになったのはとても良いですね。

それではよいBurpライフを!