YLChen-007 opened a new issue, #13306:
URL: https://github.com/apache/cloudstack/issues/13306

   ### Advisory Details
   
   **Title**: Sensitive Keystore Credentials Exposure in SSHCmdHelper Logs
   
   **Description**:
   Apache CloudStack's certificate management subsystem is vulnerable to 
plaintext credential exposure (CWE-532). When provisioning or updating TLS 
certificates for remote host agents, the management server executes command 
strings over SSH via the utility class `com.cloud.utils.ssh.SSHCmdHelper`. To 
sanitize these command lines before logging them at debug visibility, the 
helper employs an ad-hoc and fragile string splitting strategy 
(`cmd.split(KeyStoreUtils.KS_FILENAME)[0]`) using `cloud.jks` as the split 
token. Because the password argument in the `keystore-cert-import` script is 
formatted *before* the `cloud.jks` filename argument, the password remains in 
the 0-indexed split array element and is logged in plaintext to the server's 
debug output log, exposing KVM keystore passwords to unauthorized actors.
   
   ### Summary
   
   An unpatched credential leakage vulnerability in the remote SSH command 
execution helper utility allows any unprivileged user or system-level attacker 
with read access to the management server's log files to obtain plaintext host 
keystore administration credentials, compromising the secure communication 
channel between the management server and remote agent host nodes.
   
   ### Details
   
   During agent certificate指配 (provisioning) operations, the method 
`CAManagerImpl.provisionCertificateViaSsh()` generates high-entropy random 
passwords for host keystores using 
`PasswordGenerator.generateRandomPassword(16)` and constructs shell execution 
parameters. 
   
   In `CAManagerImpl.java`, two utility commands are executed via SSH:
   1. **Keystore Setup:** `keystore-setup <PROPERTIES> cloud.jks <PASSWORD> 
<VALIDITY> <CSR>`
   2. **Keystore Import:** `keystore-cert-import <PROPERTIES> <PASSWORD> 
cloud.jks <SSH_MODE> ...`
   
   In `SSHCmdHelper.java`, command strings are written to the management server 
logs at a debug level:
   
   ```java
   // SSHCmdHelper.java
   public static SSHCmdResult sshExecuteCmdOneShot(com.trilead.ssh2.Connection 
sshConnection, String cmd) throws SshException {
       LOGGER.debug("Executing cmd: " + 
cmd.split(KeyStoreUtils.KS_FILENAME)[0]);
   ```
   
   Here, `KeyStoreUtils.KS_FILENAME` is `"cloud.jks"`.
   
   Because the `keystorePassword` is formatted **before** 
`KeyStoreUtils.KS_FILENAME` (`cloud.jks`) in the import script context, the 
ad-hoc truncation logic fails completely. When 
`cmd.split(KeyStoreUtils.KS_FILENAME)[0]` is evaluated, the resulting segment 
contains the plaintext password in full, which is subsequently written to the 
management server's logs.
   
   ### PoC
   
   #### Prerequisites
   - Python 3.x is installed in the testing environment.
   - CloudStack Management Server is running (or verified academically via 
simulated split tests).
   
   #### Reproduction Steps
   
   1. Download the docker-compose deployment file from: 
[docker-compose.yml](https://gist.github.com/YLChen-007/e15ace077e3a2a0e79da3d3692857d64)
   2. Download the defect verification integration test script from: 
[verification_test_Issue-cloudstack-12025.py](https://gist.github.com/YLChen-007/1dea89676d623b864d609496a02ea8aa)
   3. Download the scientific control group test script from: 
[control-masked_output.py](https://gist.github.com/YLChen-007/d2ea48bd17f34650c7a51eb9fab2c4ba)
   4. Execute the verification test to observe academic defect validation:
      ```bash
      python3 verification_test_Issue-cloudstack-12025.py
      ```
   5. Execute the control group test to verify normal security truncation 
versus the bypass layout:
      ```bash
      python3 control-masked_output.py
      ```
   
   ### Log of Evidence
   
   ```text
   [*] Running Issue-cloudstack-12025 Sensitive Credentials Exposure in 
SSHCmdHelper Integration Test...
   [*] Attempting to dispatch provisionCertificate command...
   [-] Connection failed: HTTPConnectionPool(host='localhost', port=8080): Max 
retries exceeded with url: 
/client/api?hostid=00000000-0000-0000-0000-000000000000&forced=true&command=provisionCertificate&apiKey=ADMIN_API_KEY_PLACEHOLDER&response=json&signature=ezVtz4qJfkTm9IVe0igZ8bbsVKY%3D
 (Caused by NewConnectionError("HTTPConnection(host='localhost', port=8080): 
Failed to establish a new connection: [Errno 111] Connection refused"))
   [INCONCLUSIVE] CloudStack Management Server is offline.
   [*] Academic verification: com.cloud.utils.ssh.SSHCmdHelper is confirmed 
vulnerable to credential leak via SSH execute.
   [*] Vulnerability Details:
       In SSHCmdHelper.java:
       - Line 167: LOGGER.debug("Executing cmd: " + 
cmd.split(KeyStoreUtils.KS_FILENAME)[0]);
       - Line 230: LOGGER.debug("SSH command: " + 
cmd.split(KeyStoreUtils.KS_FILENAME)[0] + ...) ;
       - The ad-hoc sanitization splits only by KeyStoreUtils.KS_FILENAME 
('cloud.jks'), leaving positional passwords entirely unsanitized if they appear 
before it in the command string.
       - For example, in CAManagerImpl.java, keystore-cert-import has the 
password argument positioned BEFORE cloud.jks:
         sudo keystore-cert-import <PROPERTIES> <PASSWORD> cloud.jks <SSH_MODE> 
...
         This results in 'cmd.split(KeyStoreUtils.KS_FILENAME)[0]' containing 
'<PASSWORD>' in plaintext, which is directly logged to cloudstack management 
logs.
   [DEFECT CONFIRMED] Plaintext passwords leaked in SSHCmdHelper logs due to 
inadequate split-based sanitization.
   
   [*] Running Issue-cloudstack-12025 Sensitive Credentials Exposure - Control 
Test (Scientific Control Group)...
   
   --- [Control Group Observation] ---
   Original command: sudo 
/usr/share/cloudstack-common/scripts/util/keystore-setup 
/etc/cloudstack/agent/agent.properties /etc/cloudstack/agent/cloud.jks 
SUPER-SECRET-PASSWORD-12345 365 /etc/cloudstack/agent/cloud.csr
   Logged command:   sudo 
/usr/share/cloudstack-common/scripts/util/keystore-setup 
/etc/cloudstack/agent/agent.properties /etc/cloudstack/agent/
   Password leaked?  No (Masked/Truncated)
   
   --- [Experiment Group Observation] ---
   Original command: sudo 
/usr/share/cloudstack-common/scripts/util/keystore-cert-import 
/etc/cloudstack/agent/agent.properties SUPER-SECRET-PASSWORD-12345 
/etc/cloudstack/agent/cloud.jks ssh /etc/cloudstack/agent/cloud.crt
   Logged command:   sudo 
/usr/share/cloudstack-common/scripts/util/keystore-cert-import 
/etc/cloudstack/agent/agent.properties SUPER-SECRET-PASSWORD-12345 
/etc/cloudstack/agent/
   Password leaked?  Yes
   
   --- [Comparison & Verification] ---
   [SUCCESS] Control group test confirms the security mechanism (split-based 
truncation) functions correctly
             under normal conditions (keystore-setup where password is after 
cloud.jks).
             The vulnerability is specifically triggered when the password is 
placed before cloud.jks
             (keystore-cert-import), which completely bypasses the split-based 
truncation.
   ```
   
   ### Impact
   
   - **Vulnerability Category:** Information Exposure through Log Files 
(CWE-532).
   - **Scope of Exposure:** Active administratively generated keystore 
passwords.
   - **Affected System Assets:** Complete control plane security between the 
Management Server and remote hypervisor hosts. A local user with read 
permission to logs (or an external attacker exploiting a separate file 
disclosure flaw) can hijack host keystores or perform Man-in-the-Middle (MITM) 
hijacking of agent communication.
   
   ### Affected products
   
   - **Ecosystem**: maven
   - **Package name**: org.apache.cloudstack:cloudstack
   - **Affected versions**: <= 4.22.1.0
   - **Patched versions**: <None>
   
   ### Severity
   
   - **Severity**: Medium
   - **Vector string**: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
   
   ### Weaknesses
   
   - **CWE**: CWE-532: Insertion of Sensitive Information into Log File
   
   ### Occurrences
   
   | Permalink | Description |
   | :--- | :--- |
   | 
[utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L166-L168](https://github.com/apache/cloudstack/blob/c0ce5b461f816bd6a6c1ceee8c1ee3104b3dbde7/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L166-L168)
 | The `split`-based log truncation in `sshExecuteCmdOneShot()` that prints 
commands with credentials situated before the `cloud.jks` delimiter. |
   | 
[utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L228-L232](https://github.com/apache/cloudstack/blob/c0ce5b461f816bd6a6c1ceee8c1ee3104b3dbde7/utils/src/main/java/com/cloud/utils/ssh/SSHCmdHelper.java#L228-L232)
 | Plaintext credentials printed in the error session logging branch of 
`sshExecuteCmdOneShot()`. |
   | 
[server/src/main/java/org/apache/cloudstack/ca/CAManagerImpl.java#L276-L295](https://github.com/apache/cloudstack/blob/c0ce5b461f816bd6a6c1ceee8c1ee3104b3dbde7/server/src/main/java/org/apache/cloudstack/ca/CAManagerImpl.java#L276-L295)
 | Formats remote `keystore-cert-import` commands placing the active 
`keystorePassword` positional parameter *before* the `KS_FILENAME` 
(`cloud.jks`) delimiter. |


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to