GraphQL
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
GraphQLは、バックエンドからデータをクエリするための簡素化されたアプローチを提供する効率的な代替手段として強調されています。データを収集するためにさまざまなエンドポイントに対して多数のリクエストを必要とすることが多いRESTとは対照的に、GraphQLは単一のリクエストを通じて必要なすべての情報を取得することを可能にします。この簡素化は、データ取得プロセスの複雑さを減少させることにより、開発者に大きな利益をもたらします。
GraphQLを含む新しい技術の登場に伴い、新しいセキュリティの脆弱性も現れます。重要な点は、GraphQLにはデフォルトで認証メカニズムが含まれていないということです。開発者がそのようなセキュリティ対策を実装する責任があります。適切な認証がない場合、GraphQLエンドポイントは認証されていないユーザーに機密情報を露出する可能性があり、重大なセキュリティリスクを引き起こします。
露出したGraphQLインスタンスを特定するために、ディレクトリブルートフォース攻撃に特定のパスを含めることが推奨されます。これらのパスは次のとおりです:
/graphql
/graphiql
/graphql.php
/graphql/console
/api
/api/graphql
/graphql/api
/graphql/graphql
オープンなGraphQLインスタンスを特定することで、サポートされているクエリを調査することができます。これは、エンドポイントを通じてアクセス可能なデータを理解するために重要です。GraphQLのイントロスペクションシステムは、スキーマがサポートするクエリを詳細に示すことでこれを容易にします。これに関する詳細は、GraphQLのイントロスペクションに関するドキュメントを参照してください:GraphQL: A query language for APIs.
ツールgraphw00fは、サーバーで使用されているGraphQLエンジンを検出し、セキュリティ監査人に役立つ情報を印刷することができます。
URLがGraphQLサービスであるかどうかを確認するために、ユニバーサルクエリ query{__typename}
を送信できます。レスポンスに {"data": {"__typename": "Query"}}
が含まれている場合、そのURLがGraphQLエンドポイントをホストしていることが確認されます。この方法は、クエリされたオブジェクトのタイプを明らかにするGraphQLの __typename
フィールドに依存しています。
Graphqlは通常、GET、POST(x-www-form-urlencoded)およびPOST(json)をサポートしています。ただし、セキュリティのためにCSRF攻撃を防ぐためにjsonのみを許可することが推奨されます。
スキーマ情報を発見するためにインストロスペクションを使用するには、__schema
フィールドをクエリします。このフィールドはすべてのクエリのルートタイプで利用可能です。
このクエリを使用すると、使用されているすべてのタイプの名前を見つけることができます:
このクエリを使用すると、すべてのタイプ、そのフィールド、および引数(および引数のタイプ)を抽出できます。これは、データベースをクエリする方法を知るのに非常に役立ちます。
エラー
エラーが表示されるかどうかを知ることは興味深いことであり、それは有用な情報に貢献します。
インストロスペクションを介してデータベーススキーマを列挙する
インストロスペクションが有効であるが、上記のクエリが実行されない場合は、クエリ構造から onOperation
、onFragment
、および onField
ディレクティブを削除してみてください。
インラインイントロスペクションクエリ:
最後のコード行は、graphqlからすべてのメタ情報(オブジェクト名、パラメータ、タイプなど)をダンプするgraphqlクエリです。
イントロスペクションが有効になっている場合、GraphQL Voyagerを使用して、GUIですべてのオプションを表示できます。
データベースにどのような情報が保存されているかがわかったので、いくつかの値を抽出してみましょう。
イントロスペクションでは、どのオブジェクトを直接クエリできるかを見つけることができます(オブジェクトが存在するからといってクエリできるわけではありません)。次の画像では、"queryType"が"Query"と呼ばれ、"Query"オブジェクトのフィールドの1つが"flags"であり、これはオブジェクトのタイプでもあります。したがって、フラグオブジェクトをクエリできます。
"flags"のクエリのタイプは"Flags"であり、このオブジェクトは以下のように定義されています:
"Flags"オブジェクトはnameとvalueで構成されていることがわかります。次に、クエリを使用してフラグのすべての名前と値を取得できます:
注意してください、クエリするオブジェクトがプリミティブ****タイプ(例えば文字列)の場合、以下の例のように
単に次のようにクエリできます:
別の例では、"Query" タイプオブジェクトの中に "user" と "users" の 2 つのオブジェクトがありました。 これらのオブジェクトが検索に引数を必要としない場合、必要なデータを 要求する だけで すべての情報を取得 できます。このインターネットの例では、保存されたユーザー名とパスワードを抽出できます:
しかし、この例ではそうしようとすると、次の エラー が発生します:
どうやら、"uid" 型の引数 Int を使用して検索するようです。
とにかく、Basic Enumeration セクションでは、必要な情報をすべて表示するクエリが提案されていました: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}
そのクエリを実行したときに提供された画像を読むと、"user" に型 Int の arg "uid" があることがわかります。
したがって、軽い uid ブルートフォースを実行したところ、uid=1 でユーザー名とパスワードが取得されました:
query={user(uid:1){user,password}}
私は、パラメータ "user" と "password" を要求できることを 発見 したことに注意してください。なぜなら、存在しないものを探そうとすると (query={user(uid:1){noExists}}
) このエラーが発生するからです:
そして、列挙フェーズの間に、"dbuser" オブジェクトが "user" と "password" をフィールドとして持っていることを発見しました。
クエリ文字列ダンプトリック(@BinaryShadow_ に感謝)
文字列型で検索できる場合、例えば: query={theusers(description: ""){username,password}}
とし、空の文字列を 検索 すると、すべてのデータが ダンプ されます。 (この例はチュートリアルの例とは関係ありません。この例では、"theusers" を "description" という文字列フィールドで検索できると仮定してください)。
このセットアップでは、データベースには 人 と 映画 が含まれています。 人 は メール と 名前 で識別され、映画 は 名前 と 評価 で識別されます。 人 は互いに友達になり、映画を持つこともでき、データベース内の関係を示します。
名前 で人を 検索 し、彼らのメールを取得できます:
あなたは名前で人を検索し、彼らの登録された映画を取得できます:
subscribedMovies
のname
を取得する方法に注意してください。
複数のオブジェクトを同時に検索することもできます。この場合、2つの映画を検索します:
または、エイリアスを使用した複数の異なるオブジェクトの関係:
ミューテーションはサーバーサイドで変更を加えるために使用されます。
イントロスペクションでは、宣言された ミューテーションを見つけることができます。次の画像では、"MutationType"は"Mutation"と呼ばれ、"Mutation"オブジェクトにはミューテーションの名前(この場合は"addPerson"など)が含まれています:
このセットアップでは、データベースには人物と映画が含まれています。人物はそのメールと名前で識別され、映画はその名前と評価で識別されます。人物は互いに友達になったり、映画を持ったりすることができ、データベース内の関係を示します。
データベース内に新しい映画を作成するためのミューテーションは、次のようになります(この例ではミューテーションはaddMovie
と呼ばれます):
クエリ内で値とデータの型がどのように示されているかに注意してください。
さらに、データベースは、既存の友人や映画との関連を持つ人物の作成を可能にするaddPerson
という名前のミューテーション操作をサポートしています。新しく作成された人物にリンクする前に、友人と映画はデータベースに事前に存在している必要があることに注意することが重要です。
このレポートで説明されている脆弱性の1つで説明されているように、ディレクティブのオーバーロードは、サーバーが操作を無駄にするまで、ディレクティブを何百万回も呼び出すことを意味します。
この情報はhttps://lab.wallarm.com/graphql-batching-attack/から取得されました。 異なる認証情報で多くのクエリを同時に送信することでGraphQL APIを通じて認証を行います。これは古典的なブルートフォース攻撃ですが、GraphQLのバッチ機能により、1つのHTTPリクエストで複数のログイン/パスワードペアを送信することが可能になりました。このアプローチは、外部のレート監視アプリケーションを欺いて、すべてが正常であり、パスワードを推測しようとするブルートフォースボットがいないと考えさせることができます。
以下は、同時に3つの異なるメール/パスワードペアを使用したアプリケーション認証リクエストの最も簡単なデモです。明らかに、同じ方法で1回のリクエストで数千を送信することが可能です:
レスポンスのスクリーンショットからわかるように、最初と3番目のリクエストは_null_を返し、_error_セクションに対応する情報を反映しました。2番目のミューテーションは正しい認証データを持ち、レスポンスには正しい認証セッショントークンが含まれています。
ますます多くのgraphqlエンドポイントがインストロスペクションを無効にしています。しかし、予期しないリクエストが受信されたときにgraphqlが投げるエラーは、clairvoyanceのようなツールがスキーマのほとんどを再構築するのに十分です。
さらに、Burp Suite拡張機能GraphQuailは、Burpを通過するGraphQL APIリクエストを観察し、新しいクエリを見るたびに内部GraphQL スキーマを構築します。また、GraphiQLやVoyager用にスキーマを公開することもできます。この拡張機能は、インストロスペクションクエリを受信すると偽のレスポンスを返します。その結果、GraphQuailはAPI内で使用可能なすべてのクエリ、引数、およびフィールドを表示します。詳細についてはこちらを確認してください。
素晴らしいワードリストは、GraphQLエンティティを発見するためにここにあります。
APIのインストロスペクションクエリに対する制限を回避するために、__schema
キーワードの後に特殊文字を挿入することが効果的です。この方法は、インストロスペクションをブロックすることを目的とした正規表現パターンにおける一般的な開発者の見落としを利用します。GraphQLが無視するが正規表現では考慮されない可能性のあるスペース、改行、カンマのような文字を追加することで、制限を回避できます。たとえば、__schema
の後に改行を含むインストロスペクションクエリは、そのような防御を回避する可能性があります:
成功しない場合は、GETリクエストや**x-www-form-urlencoded
を使用したPOST**などの代替リクエスト方法を検討してください。制限がPOSTリクエストのみに適用される可能性があります。
このトークで述べたように、WebSocketsを介してgraphQLに接続できるかどうかを確認してください。これにより、潜在的なWAFを回避し、WebSocket通信がgraphQLのスキーマを漏洩させる可能性があります。
イントロスペクションが無効になっている場合、JavaScriptライブラリにプリロードされたクエリをウェブサイトのソースコードで調べることは有効な戦略です。これらのクエリは、開発者ツールのSources
タブを使用して見つけることができ、APIのスキーマに関する洞察を提供し、潜在的に露出した機密クエリを明らかにします。開発者ツール内で検索するためのコマンドは次のとおりです:
もしCSRFが何か分からない場合は、以下のページを読んでください:
CSRF (Cross Site Request Forgery)外には、CSRFトークンなしで構成されたいくつかのGraphQLエンドポイントを見つけることができるでしょう。
GraphQLリクエストは通常、Content-Type **application/json
**を使用してPOSTリクエストで送信されることに注意してください。
しかし、ほとんどのGraphQLエンドポイントは**form-urlencoded
POSTリクエスト**もサポートしています:
したがって、前述のようなCSRFリクエストはプレフライトリクエストなしで送信されるため、CSRFを悪用してGraphQLに変更を加えることが可能です。
ただし、Chromeのsamesite
フラグの新しいデフォルトクッキー値はLax
であることに注意してください。これは、クッキーがGETリクエストでのみサードパーティのウェブから送信されることを意味します。
クエリ リクエストをGET リクエストとして送信することも通常可能であり、GETリクエストではCSRFトークンが検証されない可能性があります。
また、XS-Search 攻撃を悪用することで、ユーザーの資格情報を悪用してGraphQLエンドポイントからコンテンツを抽出することが可能かもしれません。
詳細については、こちらの元の投稿を確認してください。
GraphQLを悪用するCRSF脆弱性と同様に、保護されていないクッキーを使用してGraphQLでの認証を悪用するためのクロスサイトWebSocketハイジャックを実行することも可能です。これにより、ユーザーがGraphQLで予期しないアクションを実行することになります。
詳細については、次を確認してください:
WebSocket Attacksエンドポイントで定義された多くのGraphQL関数は、リクエスターの認証のみをチェックし、認可はチェックしない場合があります。
クエリ入力変数を変更すると、機密アカウントの詳細が漏洩する可能性があります。
ミューテーションは、他のアカウントデータを変更しようとすることでアカウントの乗っ取りにつながる可能性があります。
クエリのチェーニングを行うことで、弱い認証システムをバイパスできます。
以下の例では、操作が「forgotPassword」であり、それに関連するforgotPasswordクエリのみを実行する必要があることがわかります。これをバイパスするには、最後にクエリを追加します。この場合、「register」と新しいユーザーとしてシステムに登録するためのユーザー変数を追加します。
GraphQLでは、エイリアスはAPIリクエストを行う際にプロパティの名前を明示的に指定することを可能にする強力な機能です。この機能は、同じタイプのオブジェクトの複数のインスタンスを単一のリクエスト内で取得するのに特に便利です。エイリアスを使用することで、GraphQLオブジェクトが同じ名前の複数のプロパティを持つことを妨げる制限を克服できます。
GraphQLエイリアスの詳細な理解のために、以下のリソースを推奨します: エイリアス。
エイリアスの主な目的は多数のAPI呼び出しの必要性を減らすことですが、エイリアスを利用してGraphQLエンドポイントに対してブルートフォース攻撃を実行するという意図しない使用例が特定されています。これは、一部のエンドポイントがブルートフォース攻撃を防ぐためにHTTPリクエストの数を制限するレートリミッターによって保護されているため可能です。しかし、これらのレートリミッターは、各リクエスト内の操作の数を考慮しない場合があります。エイリアスを使用すると、単一のHTTPリクエスト内に複数のクエリを含めることができるため、そのようなレート制限を回避できます。
以下の例を考えてみましょう。これは、エイリアス付きのクエリを使用してストアの割引コードの有効性を確認する方法を示しています。この方法は、複数のクエリを1つのHTTPリクエストにまとめるため、レート制限を回避できる可能性があり、同時に多数の割引コードの確認を可能にします。
https://github.com/dolevf/graphql-cop: graphql エンドポイントの一般的な誤設定をテストします
https://github.com/assetnote/batchql: バッチ GraphQL クエリとミューテーションの実行に焦点を当てた GraphQL セキュリティ監査スクリプト。
https://github.com/dolevf/graphw00f: 使用されている graphql のフィンガープリンティング
https://github.com/gsmith257-cyber/GraphCrawler: スキーマを取得し、機密データを検索し、認可をテストし、スキーマをブルートフォースし、特定のタイプへのパスを見つけるために使用できるツールキット。
https://blog.doyensec.com/2020/03/26/graphql-scanner.html: スタンドアロンまたは Burp 拡張機能として使用できます。
https://github.com/swisskyrepo/GraphQLmap: CLI クライアントとしても使用でき、攻撃を自動化します
https://gitlab.com/dee-see/graphql-path-enum: GraphQL スキーマ内の特定のタイプに到達するためのさまざまな方法をリストするツール。
https://github.com/doyensec/GQLSpection: InQL のスタンドアロンおよび CLI モードの後継
https://github.com/doyensec/inql: 高度な GraphQL テスト用の Burp 拡張機能。_スキャナーは InQL v5.0 のコアであり、GraphQL エンドポイントまたはローカルのイントロスペクションスキーマファイルを分析できます。すべての可能なクエリとミューテーションを自動生成し、分析のために構造化されたビューに整理します。アタッカー_コンポーネントを使用すると、バッチ GraphQL 攻撃を実行でき、実装が不十分なレート制限を回避するのに役立ちます。
https://github.com/nikitastupin/clairvoyance: 一部の Graphql データベースの助けを借りて、イントロスペクションが無効になっていてもスキーマを取得しようとします。
https://github.com/graphql/graphiql: GUI クライアント
https://altair.sirmuel.design/: GUI クライアント
AutoGraphQL を説明するビデオ: https://www.youtube.com/watch?v=JJmufWfVvyU
AWS ハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE) GCP ハッキングを学び、実践する: HackTricks Training GCP Red Team Expert (GRTE)