CVE-2025-26469
An incorrect default permissions vulnerability exists in the CServerSettings::SetRegistryValues functionality of MedDream PACS Premium 7.3.3.840. A specially crafted application can decrypt credentials stored in a configuration-related registry key. An attacker can execute a malicious script or application to exploit this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
MedDream PACS Premium 7.3.3.840
MedDream PACS Premium - https://meddream.com/products/meddream-pacs-server/
9.3 - CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CWE-732 - Incorrect Permission Assignment for Critical Resource
MedDream PACS is a DICOM 3.0-compliant server for storing, managing, and retrieving medical images. It includes a web-based DICOM viewer and administration interface, with features like user access control, study forwarding, and multi-format image support.
Inadequate permissions on the registry values enable anyone with login access to read the encrypted data and subsequently recover the plaintext username and password, granting full access to the database.
As a result, the host, database name, port number, username, and password become accessible from a hacker’s perspective.
It is worth mentioning that the problem with accessing credentials is even more significant when the database is installed on the same system as the MedDream server. In such cases, the credentials are stored in plaintext in one of the files.
Below part of pseudo code responsible for handling registry values to construct some object i named CServerSettings
. LINE 44
encryption key is stored hardcoded from the binary itself and is used to encrypt/decrypt data from registry LINE 68
for database username and LINE 93
for corresponding password.
LINE1 void __thiscall CServerSettings::SetRegistryValues(CServerSettings *this)
LINE2 {
LINE3 undefined *puVar1;
LINE4 BYTE *pBVar2;
LINE5 BYTE *lpData;
LINE6 BYTE *lpData_00;
LINE7 undefined1 *lpData_01;
LINE8 LSTATUS LVar3;
LINE9 int iVar4;
LINE10 uint uVar5;
LINE11 longlong lVar6;
LINE12 ulonglong l_len_passkey;
LINE13 undefined stack [32];
LINE14 DWORD encrypted_buffer [2];
LINE15 DWORD l_buffer;
LINE16 undefined4 uStack_2ac;
LINE17 undefined8 local_2a8;
LINE18 SymmetricCipherFinal local_2a0;
LINE19 char cipher_key [40];
LINE20 BYTE l_encrypted_data [256];
LINE21 ulonglong cookie;
LINE22 INT64 uVar6;
LINE23
LINE24 [...]
LINE25 this->SessionTimeout = encrypted_buffer[0];
LINE26 _l_buffer = (char *)CONCAT44(uStack_2ac,0x100);
LINE27 lpData_01 = &this->DatabaseHost;
LINE28 LVar3 = RegQueryValueExA(this->hkey,"DatabaseHost",(LPDWORD)0x0,(LPDWORD)0x0,lpData_01,&l_buffer);
LINE29 if (LVar3 != 0) {
LINE30 strncpy(lpData_01,"localhost",0x100);
LINE31 iVar4 = lstrlenA(lpData_01);
LINE32 RegSetValueExA(this->hkey,"DatabaseHost",0,1,lpData_01,iVar4 + 1);
LINE33 }
LINE34 _l_buffer = (char *)CONCAT44(uStack_2ac,0x20);
LINE35 puVar1 = &this->field_0x278;
LINE36 LVar3 = RegQueryValueExA(this->hkey,"Database",(LPDWORD)0x0,(LPDWORD)0x0,puVar1,&l_buffer);
LINE37 if (LVar3 != 0) {
LINE38 strncpy(puVar1,"Database",32);
LINE39 iVar4 = lstrlenA(puVar1);
LINE40 RegSetValueExA(this->hkey,"Database",0,1,puVar1,iVar4 + 1);
LINE41 }
LINE42 encrypted_buffer[0] = 0x100;
LINE43 memset(l_encrypted_data,0,256);
LINE44 builtin_strncpy(cipher_key,"XiaohuiLi",10);
LINE45 uVar6 = -1;
LINE46 do {
LINE47 l_len_passkey = uVar6 + 1;
LINE48 lVar6 = uVar6 + 1;
LINE49 uVar6 = l_len_passkey;
LINE50 } while (cipher_key[lVar6] != '\0');
LINE51 LVar3 = RegQueryValueExA(this->hkey,"MySqlUser",(LPDWORD)0x0,(LPDWORD)0x0,l_encrypted_data,
LINE52 encrypted_buffer);
LINE53 if (LVar3 == 0) {
LINE54 FUN_140001b80(&local_2a0);
LINE55 FUN_140001b80(&local_2a0.StreamInformation_vftable);
LINE56 _l_buffer = local_2a0.buffer;
LINE57 local_2a0.size_buffer = 256;
LINE58 local_2a0.size_below_0x101 = 1;
LINE59 local_2a0.ptr_buffer = local_2a0.buffer;
LINE60 local_2a0.SymmetricCipherFinal1_vtable = &CryptoPP::SymmetricCipherFinal<>::vftable;
LINE61 local_2a0.StreamInformation_vftable = &CryptoPP::SymmetricCipherFinal<>::vftable;
LINE62 local_2a0.SymmetricCipherFinal2_vtable = &CryptoPP::SymmetricCipherFinal<>::vftable;
LINE63 somecrypto((SymmetricCipherFinal *)&local_2a0.SymmetricCipherFinal2_vtable,cipher_key,
LINE64 l_len_passkey & 0xffffffff,&PTR_vftable_14030e4c8);
LINE65 (*(code *)(local_2a0.StreamInformation_vftable)->140001f20_StreamTransform)
LINE66 (&local_2a0.StreamInformation_vftable,l_encrypted_data,l_encrypted_data,
LINE67 encrypted_buffer[0]);
LINE68 strncpy(&this->encrypted_mysqluser,(char *)l_encrypted_data,32);
LINE69 clear_buffer(&local_2a0);
LINE70 }
LINE71 else {
LINE72 strncpy(&this->encrypted_mysqluser,"dicom",32);
LINE73 }
LINE74 encrypted_buffer[0] = 0x100;
LINE75 memset(l_encrypted_data,0,256);
LINE76 LVar3 = RegQueryValueExA(this->hkey,"MySqlPassword",(LPDWORD)0x0,(LPDWORD)0x0,l_encrypted_data,
LINE77 encrypted_buffer);
LINE78 if (LVar3 == 0) {
LINE79 FUN_140001b80(&local_2a0);
LINE80 FUN_140001b80(&local_2a0.StreamInformation_vftable);
LINE81 _l_buffer = local_2a0.buffer;
LINE82 local_2a0.size_buffer = 0x100;
LINE83 local_2a0.size_below_0x101 = 1;
LINE84 local_2a0.ptr_buffer = local_2a0.buffer;
LINE85 local_2a0.SymmetricCipherFinal1_vtable = &CryptoPP::SymmetricCipherFinal<>::vftable;
LINE86 local_2a0.StreamInformation_vftable = &CryptoPP::SymmetricCipherFinal<>::vftable;
LINE87 local_2a0.SymmetricCipherFinal2_vtable = &CryptoPP::SymmetricCipherFinal<>::vftable;
LINE88 somecrypto((SymmetricCipherFinal *)&local_2a0.SymmetricCipherFinal2_vtable,cipher_key,
LINE89 l_len_passkey & 0xffffffff,&PTR_vftable_14030e4c8);
LINE90 (*(code *)(local_2a0.StreamInformation_vftable)->140001f20_StreamTransform)
LINE91 (&local_2a0.StreamInformation_vftable,l_encrypted_data,l_encrypted_data,
LINE92 encrypted_buffer[0]);
LINE93 strncpy(&this->encryped_mysql_password,(char *)l_encrypted_data,32);
LINE94 clear_buffer(&local_2a0);
LINE95 }
LINE96 else {
LINE97 strncpy(&this->encryped_mysql_password,"",32);
LINE98 }
LINE99 [...]
LINE100 }
LINE101 __security_check_cookie(cookie ^ (ulonglong)stack);
LINE102 return;
LINE103 }
LINE104
It is important to highlight that choosing the RC4 algorithm these days is not the best choice due to its vulnerability to a variety of attacks.
Incorrect permissions on registry keys and values allow anyone with access to the system to read the encrypted data and decrypt it using the RC4 algorithm with a hardcoded cipher key. This results in full access to the database associated with the registry records, local or remote.
2025-03-04 - Initial Vendor Contact
2025-03-04 - Vendor Disclosure
2025-07-28 - Vendor Patch Release
2025-07-28 - Public Release
Discovered by Emmanuel Tacheau of Cisco Talos.