generated at
Prototype Pollution
外部からJavaScriptのオブジェクトのプロトタイプを汚染する攻撃
オブジェクトのプロパティアクセスに影響を与えることができる

プロトタイプとは?
JavaScriptにおける継承を実現する機構のこと
オブジェクト指向言語で言えば親クラスのようなもの
詳しくはMDNを読んでください
重要なこと
オブジェクトのプロトタイプは、 obj.__proto__ で取得できる
標準で非推奨の機能なので、将来削除される可能性がある
JavaScriptのプロパティアクセスは、プロトタイプに対して該当するプロパティがあるかどうか再帰的に調べて、あればその値を、無ければ undefined を返すようになっている
A -> B -> C というプロトタイプチェーンがあるときに A.foo にアクセスした場合
A foo というプロパティがあれば、それを返す
A foo というプロパティが無ければ、 A のプロトタイプの B foo というプロパティがあるか調べる
B foo があればそれを、無ければ B のプロトタイプの C を調べ...
基本的にオブジェクトはすべて Object.prototype を継承している
Number String Array Function Object.prototype をプロトタイプチェーンに持つ
JavaScriptのプロパティアクセスはドットでも添字でもアクセスできる
a["b"]["c"] a.b.c は等価
a["__proto__"] でプロトタイプにアクセスできる

Prototype Pollutionとは?
プロトタイプのプロパティに対して悪意のある書き込みを行い、そのオブジェクトをプロトタイプに持つ全てのオブジェクトのプロパティアクセスに対して影響を与える攻撃
obj[A][B] = C のような処理があり、攻撃者がA,B,Cを操作できるとき典型的なPrototype Pollutionの脆弱性が生まれる
poc.js
const obj = {}; // プロトタイプチェーンは obj => Object.prototype => null // 攻撃者がObject.prototype.pollutedに書き込みを行う obj["__proto__"]["polluted"] = "pwned"; // 別のオブジェクトを作成する const obj2 = {}; // プロトタイプチェーンは obj2 => Object.prototype => null // obj["__proto__"] === obj2["__proto__"] なので obj2.__proto__.polluted も"pwned"になる console.log(obj2.polluted); // => pwned
上書きできるのは元のオブジェクトで定義されていないプロパティだけ
poc.js
const obj = {hoge: "original"}; // {hoge: "original"} => Object.prototype => null obj["__proto__"]["hoge"] = "pwned"; // objにhogeプロパティが存在するため、プロトタイプにさかのぼらずにobj.hogeを出力する console.log(obj.hoge) // => "original";
定義されてないプロパティを上書きするだけで脆弱性になるの?
危険なオプションを有効にしたり、外部からの書き込みが想定されていない部分に書き込んだりすることで攻撃につなげたりできる
KibanaのPrototype PollutionによるRemote Code Execution

対策
Object.prototype.hasOwnProperty を用いて上書きするプロパティが自分で定義したものか確認する
obj = {a: 1} のとき
Object.prototype.hasOwnProperty.call(obj, "a") === true
Object.prototype.hasOwnProperty.call(obj, "toString") === false (objで定義したものではないので)
これを使って obj[A] = B の前にAをチェックする
{} ではなく Object.create(null) を利用する
Object.create(null) とするとプロトタイプを持たない(プロトタイプがnullの)オブジェクトを作成できる
プロトタイプを持たないので、 Object.prototype などを汚染できない
オブジェクトの代わりに new Map() を使えないか考える

攻撃テクニック
obj.__proto__ 以外にも obj.constructor.prototype でプロトタイプにアクセスできる
__proto__ を弾くだけでは不十分
Gadgetを探す
一般に適用できるテクニックはないので、問題ごとにGadgetを探す必要があることが多い
既存のCVEや既知のgadgetを使うときもある
ソースコードやライブラリを調べてPrototype Pollutionで悪用できそうな未定義のプロパティを探す
if (A.B) { ~ } や、 if (A[B]) { ~ } // Bは操作可能 が狙い目
過去の例
Asian Cyber Security Challange 2021 - Cowsay as a Service
child_process.spawnSync options.shell を汚染して任意コード実行
CakeCTF 2022 - Panda Memo
テンプレートエンジン mustache のキャッシュの汚染
MapleCTF 2022 - Viene Library
node-fetch X-HTTP-Method-Override を汚染してMethodを上書き
require の内部を汚染してRemote Code Execution
テンプレートエンジンのASTを汚染してRemote Code Executionにつなげる手法
参加者ごとにインスタンスが提供されたり、毎回インスタンスが破棄される問題はPrototype Pollution (?)
Prototype Pollutionは性質上環境を永続的に汚染するので、複数の参加者がひとつのサーバーを共有する問題を壊れないように作るのは難しい
そのためPrototype Pollutionの問題はインスタンスは破棄されたり分けられたりすることが多いので、その形式ならPrototype Pollutionだろうというジンクス
もう古いかも

資料
クライアントサイドで発見されたPrototype Pollutionと悪用できる汚染先
Node.jsにおけるプロトタイプ汚染攻撃とは何か https://jovi0608.hatenablog.com/entry/2018/10/19/083725
プロトタイプ汚染周りの提案と primordials.js https://zenn.dev/petamoriken/articles/2f6511742d7907
CTFのWebセキュリティにおけるJavaScript,nodejsまとめ(Prototype pollution, 難読化)
【1分見て】実例から学ぶprototype pollution【kurenaif勉強日記】 https://www.youtube.com/watch?v=qP8ihBctMeY

Prototype pollutionの攻撃手法に関する発表のスライド