hacktricks/pentesting-web/parameter-pollution.md

14 KiB
Raw Blame History

パラメータ汚染 | JSONインジェクション

パラメータ汚染

{% hint style="success" %} AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する: HackTricks Training GCP Red Team Expert (GRTE)

HackTricksをサポートする
{% endhint %}

{% embed url="https://websec.nl/" %}

HTTPパラメータ汚染 (HPP) 概要

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

HTTPパラメータ汚染 (HPP) の例

銀行アプリケーションの取引URL:

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

追加のfromパラメータを挿入することによって:

  • 操作されたURL: https://www.victim.com/send/?from=accountA&to=accountB&amount=10000&from=accountC

取引はaccountAではなくaccountCに誤って請求される可能性があり、HPPが取引やパスワードリセット、2FA設定、APIキーリクエストなどの他の機能を操作する可能性を示しています。

技術特有のパラメータ解析

  • パラメータが解析され、優先される方法は、基盤となるウェブ技術によって異なり、HPPがどのように悪用されるかに影響を与えます。
  • Wappalyzerのようなツールは、これらの技術とその解析動作を特定するのに役立ちます。

PHPとHPPの悪用

OTP操作のケース:

  • コンテキスト: ワンタイムパスワード (OTP) を必要とするログインメカニズムが悪用されました。
  • 方法: Burp Suiteのようなツールを使用してOTPリクエストを傍受し、攻撃者はHTTPリクエスト内のemailパラメータを複製しました。
  • 結果: 初期のメール用に意図されたOTPが、操作されたリクエストで指定された2番目のメールアドレスに送信されました。この欠陥により、意図されたセキュリティ対策を回避して不正アクセスが可能になりました。

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

APIキー操作のケース:

  • シナリオ: アプリケーションは、ユーザーがプロフィール設定ページを通じてAPIキーを更新できるようにしています。
  • 攻撃ベクトル: 攻撃者は、POSTリクエストに追加のapi_keyパラメータを追加することで、APIキー更新機能の結果を操作できることを発見しました。
  • 技術: Burp Suiteのようなツールを利用して、攻撃者は1つの正当なapi_keyパラメータと1つの悪意のあるapi_keyパラメータを含むリクエストを作成します。サーバーは最後の出現のみを処理し、攻撃者が提供した値にAPIキーを更新します。
  • 結果: 攻撃者は被害者のAPI機能を制御し、プライベートデータに不正にアクセスまたは変更する可能性があります。

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

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

ウェブ技術が重複したHTTPパラメータを処理する方法は異なり、HPP攻撃に対する脆弱性に影響を与えます:

  • Flask: クエリ文字列a=1&a=2のように、最初に遭遇したパラメータ値を採用し、初期のインスタンスを後続の重複よりも優先します。
  • PHP (Apache HTTPサーバー上): 逆に、最後のパラメータ値を優先し、与えられた例ではa=2を選択します。この動作は、攻撃者が操作したパラメータを元のものよりも優先することによって、HPPの悪用を無意識に助長する可能性があります。

技術によるパラメータ汚染

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

PHP 8.3.11 および 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 および 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 および 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 および 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 および Werkzeug 3.0.4 および Flask 3.0.3

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

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

Python 3.12.6 および Django 4.2.15

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

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

Python 3.12.6 および Tornado 6.4.1

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

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

JSONインジェクション

重複キー

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

フロントエンドは最初の出現を信じるかもしれませんが、バックエンドはキーの2番目の出現を使用します。

キー衝突: 文字の切り捨てとコメント

特定の文字はフロントエンドによって正しく解釈されないかもしれませんが、バックエンドはそれらを解釈し、これらのキーを使用します。これは特定の制限を回避するのに役立つかもしれません:

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

注意すべきは、これらのケースではフロントエンドが test == 1 と考え、バックエンドが test == 2 と考える可能性があることです。

これは、次のような値の制限を回避するためにも使用できます:

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

コメントの切り捨てを使用する

{% code overflow="wrap" %}

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

{% endcode %}

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

シリアライザー 1 (例: GoLangのGoJayライブラリ) は次のように出力します:

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

シリアライザー 2 (例: JavaのJSON-iteratorライブラリ) は次のように出力します:

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

不一致な優先順位: デシリアライズ vs. シリアライズ

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

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

Float and Integer

999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999

複数の表現にデコードできます。これには次のものが含まれます:

999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
9.999999999999999e95
1E+96
0
9223372036854775807

Which might create inconsistences

References

{% embed url="https://websec.nl/" %}

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}