はじめに
Webアプリケーションの世界では、Prototype Pollution(プロトタイプ汚染)はもはや珍しい脆弱性ではない。しかし、実際に攻撃チェーンとして成立するパターンは多くない。
本記事では、Lodash の _set 関数を悪用した Prototype Pollution と Stored XSS が組み合わさると何が起きるのかを、TryHackMe のサンプルアプリを題材にわかりやすく解説する。
Prototype Pollution とは何か
JavaScript ではオブジェクトが prototype を共有しており、その prototype を改ざんできてしまうと…
- すべてのオブジェクトに新しいプロパティが共有される
- すべての class/object の挙動を一度に変えられる
という、“根本からの書き換え”が発生する。
攻撃者が狙うキーはほぼ決まっている:
__proto__constructorprototype
これらを利用することで、意図しない共有プロパティ(例:isAdmin)をアプリ全体にばら撒くことが可能だ。
ゴールデンルール:Path-based Property Definition が穴になる
典型的な攻撃例は次のようなコードに潜む。
_.set(obj, input.path, input.value);
もし攻撃者が input.path を自由に設定できる場合、
input.path = "__proto__.isAdmin"
input.value = true
と送られれば、Object.prototype に isAdmin が生える。
これが後続の認証・権限チェックに利用されていれば、一瞬で管理者権限が奪われる。
実例:Review 機能を悪用した XSS + Prototype Pollution
TryHackMe のサンプルアプリに、友人にレビューを投稿する機能がある。
提供されているクライアント側のフォーム
<form action="/submit-friend-review" method="post">
<input type="hidden" name="friendId" value="1">
<textarea name="reviewContent"></textarea>
</form>
どこにでもある、ごく普通のレビュー投稿機能だ。
サーバー側の処理が危険
問題はバックエンドにある。
const input = JSON.parse(reviewContent);
_.set(friend, input.path, input.value);
ユーザーの入力を JSON としてパースし、Lodash の _set で friend オブジェクトに保存している。
この 1 行が、Prototype Pollution を誘発する“起爆剤”だ。
攻撃ステップ:Stored XSS の注入
まずは攻撃者が XSS を仕込む場合の例。
{
"path": "reviews[0].content",
"value": "<script>alert('Hacked')</script>"
}
レビュー欄は HTML エスケープされていないため、
ユーザーのプロフィールを閲覧するたびに XSS が発火する。
XSS 単体でも十分危険だが、本当の問題はここからだ。
本命:Prototype Pollution による権限の乗っ取り
同じ仕組みで攻撃者が次の payload を送るとどうなるか:
{
"path": "__proto__.isAdmin",
"value": true
}
するとアプリ全体の prototype に isAdmin = true が追加される。
もしどこかに下記のような権限チェックが存在すれば…
if (req.user.isAdmin) {
// 管理者機能
}
→ ログイン済みの全ユーザーが admin に昇格する。
もはや「レビュー投稿機能」どころか、
アプリケーションの基盤そのものが破壊される。
重要ポイント
1. Path-based 操作をユーザー入力に使ってはいけない
_.set, _.get, _.merge は Prototype Pollution の常連犯。
これらを そのままユーザー入力に適用するのは絶対に避けるべき。
2. JSON.parse(reviewContent) の設計がそもそも誤っている
レビュー内容を JSON として受ける必要はない。
- 文字列として受け取る
- server-side で最低限の sanitization を行う
- 保存と画面表示は分離する
という設計にすべき。
3. XSS が Prototype Pollution を加速させる
Prototype Pollution は単体だと exploit しづらいが、
XSS・CSRF・認証周りの欠陥と組み合わされると一気に実用化する。
この組み合わせは、攻撃者から見ると非常に“扱いやすい”。
防御策まとめ
| 攻撃手法 | 防御策 |
|---|---|
| Path-based pollution |
__proto__, constructor, prototype を入力拒否 |
| Lodash 使用 |
_set / _merge をユーザー入力に使用しない |
| XSS | すべてのユーザー入力を HTML エスケープ |
| データモデル | ReviewContent を JSON 形式で受けない |
| Prototype Pollution 対策 |
Object.hasOwnProperty をチェックしながら処理する |
まとめ:Prototype Pollution は“静かにアプリを乗っ取る”
Prototype Pollution は単体だと目立たないが、
XSS や権限チェックと組み合わさると爆発的な被害を生む脆弱性である。
