Parameter Pollution | JSON Injection

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

HTTP Parameter Pollution (HPP) 概要

HTTP Parameter Pollution (HPP) は、攻撃者がHTTPパラメータを操作して、ウェブアプリケーションの動作を意図しない方法で変更する手法です。この操作は、HTTPパラメータを追加、変更、または複製することで行われます。これらの操作の影響はユーザーに直接は見えないことが多いですが、サーバー側でアプリケーションの機能を大きく変化させ、クライアント側で観測可能な影響を与える可能性があります。

HTTP Parameter Pollution (HPP) の例

銀行アプリケーションのトランザクションURL:

  • Original URL: https://www.victim.com/send/?from=accountA&to=accountB&amount=10000

追加の from パラメータを挿入すると:

  • Manipulated URL: https://www.victim.com/send/?from=accountA&to=accountB&amount=10000&from=accountC

トランザクションが意図した accountA ではなく accountC に誤って請求される可能性があり、HPP がトランザクションやパスワードリセット、2FA 設定、API キー要求などの機能を操作できることを示しています。

技術ごとのパラメータ解析

  • パラメータの解析や優先順位は基盤となるウェブ技術によって異なり、HPP の悪用方法にも影響します。
  • Wappalyzer のようなツールは、これらの技術とその解析挙動を識別するのに役立ちます。

PHP と HPP の悪用

OTP Manipulation Case:

  • Context: One-Time Password (OTP) を必要とするログイン機構が悪用されました。
  • Method: Burp Suite のようなツールで OTP リクエストを傍受し、HTTP リクエスト内の email パラメータを複製しました。
  • Outcome: 元のメールアドレスに対して生成されたはずの OTP が、改ざんされたリクエストで指定された2番目のメールアドレスに送信されました。この脆弱性により、意図したセキュリティ対策を回避して不正アクセスが可能になりました。

この事例は、アプリケーションのバックエンドが最初の email パラメータを OTP 生成に使用し、配信には最後の email を使用していたという重大な見落としを示しています。

API Key Manipulation Case:

  • Scenario: アプリケーションがプロフィール設定ページを通じてユーザーの API キーを更新できる機能を持っていました。
  • Attack Vector: 攻撃者は、POST リクエストに追加の api_key パラメータを付加することで、API キー更新機能の結果を操作できることを発見しました。
  • Technique: Burp Suite のようなツールを利用して、正当なものと悪意あるものの2つの api_key パラメータを含むリクエストを作成しました。サーバーが最後の出現だけを処理する場合、API キーは攻撃者の指定した値に更新されます。
  • Result: 攻撃者は被害者の API 機能を支配し、許可なくプライベートデータにアクセスまたは変更する可能性があります。

この例は、特に API キー管理のような重要な機能における安全なパラメータ処理の必要性を強調しています。

パラメータ解析: Flask vs. PHP

重複した HTTP パラメータの扱いはウェブ技術ごとに異なり、HPP 攻撃への脆弱性に影響します:

  • Flask: クエリ文字列 a=1&a=2 のような場合、最初に出現した値(例: a=1)を採用します。最初のインスタンスを優先します。
  • PHP (on Apache HTTP Server): 対照的に、最後のパラメータ値を優先し、この例では a=2 を採用します。この挙動は、攻撃者の改ざんしたパラメータを元のものより優先してしまい、HPP の悪用を助長する可能性があります。

HPP テストの注意点 (OWASP WSTG)

  • HTTP 規格は同一名の複数パラメータの解釈方法を定義していないため、スタックやコンポーネントによって挙動が異なります。
  • サーバー側の HPP をテストする際は、クエリ文字列やボディ内で各パラメータを複製し、アプリケーションが値を連結するか、最初/最後の値を使うか、エラーになるかを観察してください。
  • クライアント側の HPP については、反映されるパラメータ値に URL エンコードされた &(例: %26HPP_TEST)を注入し、生成されたリンクや form action 内でデコードされた &HPP_TEST&HPP_TEST の出現を探します。

Server-Side Parameter Pollution (SSPP) と Internal APIs

一部のアプリケーションは、ユーザー入力を内部 API へのサーバー側リクエストに埋め込みます。その入力が適切にエンコードされていない場合、内部リクエスト内のパラメータを注入または上書きできます。クエリパラメータ、フォームフィールド、ヘッダ、URL パスパラメータなど、あらゆるユーザー入力をテストしてください。

一般的なプローブ:

  • 新しいパラメータを %26 (URL エンコードされた &) で追加する。
  • 下流のクエリを %23 (URL エンコードされた #) で切り捨てる。
  • 既存のパラメータを複製して上書きする。

例:

GET /userSearch?name=peter%26name=carlos&back=/home

次のようなサーバーサイドのリクエストが発生する可能性があります:

GET /users/search?name=peter&name=carlos&publicProfile=true

Parameter pollution by technology

結果は https://medium.com/@0xAwali/http-parameter-pollution-in-2024-32ec1b810f89 から取得しました

PHP 8.3.11 AND Apache 2.4.62

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*l_Pf2JNCYhmfAvfk7UTEbQ.jpeg

  1. パラメータ名の %00 以降を無視する。
  2. name[] を配列として扱う。
  3. _GET は GET メソッドを意味しない。
  4. 最後のパラメータを優先する。

Ruby 3.3.5 and WEBrick 1.8.2

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*kKxtZ8qEmgTIMS81py5hhg.jpeg

  1. パラメータを分割する際に & と ; を区切り文字として使用する。
  2. name[] を認識しない。
  3. 最初のパラメータを優先する。

Spring MVC 6.0.23 AND Apache Tomcat 10.1.30

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*llG22MF1gPTYZYFVCmCiVw.jpeg

  1. POST RequestMapping == PostMapping & GET RequestMapping == GetMapping.
  2. POST RequestMapping および PostMapping は name[] を認識する。
  3. name と name[] の両方が存在する場合は name を優先する。
  4. パラメータを連結する(例: first,last)。
  5. POST RequestMapping および PostMapping は Content-Type がある場合でもクエリパラメータを認識する。

NodeJS 20.17.0 AND Express 4.21.0

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*JzNkLOSW7orcHXswtMHGMA.jpeg

  1. name[] を認識する。
  2. パラメータを連結する(例: first,last)。

GO 1.22.7

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*NVvN1N8sL4g_Gi796FzlZA.jpeg

  1. name[] を認識しない。
  2. 最初のパラメータを優先する。

Python 3.12.6 AND Werkzeug 3.0.4 AND Flask 3.0.3

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*Se5467PFFjIlmT3O7KNlWQ.jpeg

  1. name[] を認識しない。
  2. 最初のパラメータを優先する。

Python 3.12.6 AND Django 4.2.15

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rf38VXut5YhAx0ZhUzgT8Q.jpeg

  1. name[] を認識しない。
  2. 最後のパラメータを優先する。

Python 3.12.6 AND Tornado 6.4.1

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*obCn7xahDc296JZccXM2qQ.jpeg

  1. name[] を認識しない。
  2. 最後のパラメータを優先する。

JSON Injection

JSON, XML and YAML Hacking

重複したキー

obj = {"test": "user", "test": "admin"}

front-endはキーの最初の出現を信じるかもしれませんが、backendはキーの2番目の出現を使用することがあります。

Key Collision: Character Truncation and Comments

特定の文字はfrontendでは正しく解釈されないことがありますが、backendはそれらを解釈してキーとして使用するため、特定の制限を回避するのに役立つことがあります:

{"test": 1, "test\[raw \x0d byte]": 2}
{"test": 1, "test\ud800": 2}
{"test": 1, "test"": 2}
{"test": 1, "te\st": 2}

これらの場合、front end は test == 1 と判断するかもしれませんが、backend は test == 2 と判断する点に注意してください。

これは次のような値制限を bypass するためにも使えます:

{"role": "administrator\[raw \x0d byte]"}
{"role":"administrator\ud800"}
{"role": "administrator""}
{"role": "admini\strator"}

コメント切り捨ての使用

obj = {"description": "Duplicate with comments", "test": 2, "extra": /*, "test": 1, "extra2": */}

ここでは、各パーサーのシリアライザを使って、それぞれの出力を確認します。

Serializer 1(例: GoLang’s GoJay library)は次を出力します:

  • description = "Duplicate with comments"
  • test = 2
  • extra = ""

Serializer 2(例: Java’s JSON-iterator library)は次を出力します:

  • description = "Duplicate with comments"
  • extra = "/*"
  • extra2 = "*/"
  • test = 1

または、単純にコメントを使用する方法も有効です:

obj = {"description": "Comment support", "test": 1, "extra": "a"/*, "test": 2, "extra2": "b"*/}

Java の GSON ライブラリ:

{ "description": "Comment support", "test": 1, "extra": "a" }

Rubyのsimdjsonライブラリ:

{ "description": "Comment support", "test": 2, "extra": "a", "extra2": "b" }

優先順位の不整合: Deserialization vs. Serialization

obj = {"test": 1, "test": 2}

obj["test"] // 1
obj.toString() // {"test": 2}

Float and Integer

数値

999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999

次のような複数の表現にデコードできます:

999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9.999999999999999e95
1E+96
0
9223372036854775807

これにより不整合が発生する可能性があります

参考文献

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする