
SureForms <= 2.2.0 - 認証されていない保存型クロスサイトスクリプティング
SureForms プラグインには、重大な保存型XSS脆弱性が存在します。この脆弱性は、entries.js における安全でないクライアントサイド実装に起因します。ここでは、ユーザー入力をプログラム的にデコード(サーバーサイドのサニタイズを逆変換)し、その後、適切なクライアントサイドのサニタイズなしに dangerouslySetInnerHTML を使用してレンダリングします。これにより、未認証の攻撃者が標準のフォームフィールドを介して悪意のある JavaScript ペイロードを注入し、WordPress のデフォルトの wp_kses フィルターをバイパスできます。
対象サイトが SureForms を実行しているか確認するには、通常バージョン番号を含む翻訳ファイルのヘッダーを調べます。
対象URL:
http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot
確認コマンド:
curl -s "http://target-site.com/wp-content/plugins/sureforms/languages/sureforms.pot" | grep "Project-Id-Version"
脆弱性は、フォームエントリーを閲覧するための React ベースの管理インターフェース(entries.js)に存在します。
minify された entries.js ファイルには、HTML エンティティを処理するために設計されたヘルパー関数(解析したビルドでは Xv と識別)があります。
コードロジック(再構成):
// Function Xv: Pre-processing field values
var Xv = function(input) {
var value = input.value;
// VULNERABILITY ROOT CAUSE:
// If the string contains HTML entities (e.g., <), create a textarea,
// inject the content, and extract the value.
// This effectively DECODES HTML entities back to raw HTML tags.
// Example: "<img ...>" becomes ""
if (typeof value === "string" && value.match(/&[a-zA-Z0-9#]+;/)) {
var textarea = document.createElement("textarea");
textarea.innerHTML = value;
// Logic to revert sanitization
if (textarea.value.includes("<") || textarea.value.includes(">")) {
value = textarea.value; // Now 'value' contains RAW HTML
}
}
return { ...input, value: value };
}
分析: この関数はバックエンドのセキュリティを無効化します。WordPress がデータベースに <script> を <script> として正しく保存しても、この関数は API から取得した直後に <script> に変換し戻します。
デコード後、データはレンダリングコンポーネント(Jv と識別)に渡されます。
コードロジック(再構成):
// Function Jv: Rendering the field
var Jv = function(props) {
var field = props.field;
var val = field.value; // This value is now raw HTML (post-decoding)
// THE TRIGGER: Check if the string looks like HTML
if (typeof val === "string" && val.match(/<[^>]+>/g)) {
// THE SINK: Render using dangerouslySetInnerHTML WITHOUT client-side sanitization (e.g., DOMPurify)
return React.createElement("span", {
dangerouslySetInnerHTML: { __html: val }
});
}
// Safe render for non-HTML text
return React.createElement("span", null, val);
}
インジェクション: 未認証の攻撃者がフロントエンドでフォームを送信します。WordPress バックエンドによって除去/サニタイズされる生の HTML タグを使用する代わりに、攻撃者はHTMLエンティティを送信します。
保存: WordPress は入力(例: <img...)を安全なテキストとして認識し、データベースに保存します。
実行(トラップ):
Xv 関数がエンティティを検出し、<img... を ` Entries に移動します。ステップ1で送信したエントリーをクリックして詳細を表示します。
結果: ブラウザが JavaScript ペイロード (alert('XSS_SUREFORMS')) を実行します。