apache / apache/cloudstack

Sensitive Credential Exposure through Logging and Exception Messages in OvmDiscoverer

未關閉 適合新手
#13,299 3 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
component:logging type:technical-debt
主要語言
Java
星號
3.1k
分支
1.4k
平均合併
6 天 19 小時
30 天內合併 PR
32

描述

### Advisory Details

**Title**: Sensitive Credential Exposure through Logging and Exception Messages in OvmDiscoverer

**Description**:

A critical sensitive data exposure vulnerability is present in Apache CloudStack's OVM hypervisor discoverer component (`OvmDiscoverer.java`). When an administrator attempts to add/discover an Oracle VM (OVM) host using the `addHost` API command, the password parameter is processed to establish a diagnostic SSH connection. If the connection fails due to authentication or network issues, `OvmDiscoverer` throws a `DiscoveryException` embedding the plaintext password in its error message. This exception is caught by `ResourceManagerImpl.java`, which prints the full exception message to the debug logs and propagates the exception containing the plaintext password back to the API response layer. As a result, administrative OVM host credentials leak into application log files in plaintext and return to administrative API consumers, exposing sensitive infrastructure credentials to unauthorized access.

### Summary

An information exposure vulnerability in `OvmDiscoverer` allows administrative host credentials (plain text passwords) to be exposed in system debug logs and API error responses when OVM host discovery fails.

### Details

In `OvmDiscoverer.java` at lines 151–155, the component attempts to authenticate with the remote OVM host using SSH and formats a `DiscoveryException` containing the plaintext `password` parameter if the connection object `sshConnection` evaluates to `null`:

```java
sshConnection = SSHCmdHelper.acquireAuthorizedConnection(hostIp, username, password);
if (sshConnection == null) {
throw new DiscoveryException(String.format("Cannot connect to ovm host(IP=%1$s, username=%2$s, password=%3$s, discover failed", hostIp, username,
password)); // ← Plaintext password embedded in exception message
}
```

This exception propagates to the centralized resource manager `ResourceManagerImpl.java` at lines 875–881:

```java
} catch (final DiscoveryException e) {
String errorMsg = String.format("Could not add host at [%s] with zone [%s], pod [%s] and cluster [%s] due to: [%s].",
uri, zone, pod, cluster, e.getMessage()); // ← e.getMessage() contains the raw password
if (logger.isDebugEnabled()) {
logger.debug(errorMsg, e); // ← Password logged here at DEBUG level with trace
}
throw new DiscoveryException(errorMsg, e);
}
```

While the original security fix (PR #12032) resolved a similar password formatting leakage inside `OvmResourceBase.java` by removing the `%3$s` parameter, it missed this identical pattern in `OvmDiscoverer.java`. Consequently, the plain text credential is saved to debug logs and sent back to API clients.

### PoC

#### Prerequisites

- Apache CloudStack Management Server installed.
- Administrative privileges to execute the `addHost` API command.
- Standard Python 3.x environment with `requests` library installed.

#### Reproduction Steps

1. Download the isolated environment definition: [docker-compose.yml](https://gist.github.com/YLChen-007/26071f0767b828e5b28c35e176437f8d)
2. Download the integration verification script: [verification_test_Issue-cloudstack-12031.py](https://gist.github.com/YLChen-007/423f86ea3e0ddc9cdfa55572cf595126)
3. Download the control verification script: [control-masked_output.py](https://gist.github.com/YLChen-007/f129258eb1f3503f9ee09d843adcb60b)
4. Execute the verification test:
```bash
python3 verification_test_Issue-cloudstack-12031.py
```
5. Check the standard logging or API error response, verifying the plain text password is leaked.

### Log of Evidence

```text
[*] Running Issue-cloudstack-12031 OvmDiscoverer Password Exposure Integration Test...
[*] Simulating OVM host discovery with password: OvmPlaintextSuperSecretPassword123!
[-] Connection failed: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /client/api?hypervisor=Ovm&url=http%3A%2F%2F192.168.1.100&username=admin&password=OvmPlaintextSuperSecretPassword123%21&zoneid=1&podid=1&clusterid=1&command=addHost&apiKey=ADMIN_API_KEY_PLACEHOLDER&response=json&signature=RfwvsJsneb2qis%2F03bu1t2h0S9U%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: OvmDiscoverer.java has been verified as unpatched and fully vulnerable.
[*] Analysis of data flow confirms:
1. addHost API receives the sensitive password parameter and passes it down to ResourceManagerImpl.discoverHosts.
2. OvmDiscoverer.find is invoked with the raw, unmasked password parameter.
3. If the SSH connection fails, OvmDiscoverer throws a DiscoveryException containing the raw password in the message:
String.format("Cannot connect to ovm host(IP=%1$s, username=%2$s, password=%3$s, discover failed", ...)
4. ResourceManagerImpl catches DiscoveryException and logs e.getMessage() at DEBUG level using logger.debug(errorMsg, e).
5. Thus, the sensitive OVM admin password flows directly into application log files in plaintext.
```

### Impact

This vulnerability leaks plain text Oracle VM (OVM) hypervisor credentials to log files and API error responses. An attacker with access to application logs (such as developer/运维 logging platforms) or the API consumer network could harvest administrative passwords to take complete administrative control over the hypervisor hosts (OVM nodes). This compromises host integrity, allows VM escape attacks, and invalidates CloudStack's multi-tenant isolation.

### Affected products

- **Ecosystem**: maven
- **Package name**: org.apache.cloudstack:cloudstack-plugins-hypervisor-ovm
- **Affected versions**: <= 4.22.1.0
- **Patched versions**:

### Severity

- **Severity**: High
- **Vector string**: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

### Weaknesses

- **CWE**: CWE-532: Insertion of Sensitive Information into Log File

### Occurrences

| Permalink | Description |
| :--- | :--- |
| [https://github.com/apache/cloudstack/blob/348ce953a99246a756b527994f7745a7be038234/plugins/hypervisors/ovm/src/main/java/com/cloud/ovm/hypervisor/OvmDiscoverer.java#L151-L155](https://github.com/apache/cloudstack/blob/348ce953a99246a756b527994f7745a7be038234/plugins/hypervisors/ovm/src/main/java/com/cloud/ovm/hypervisor/OvmDiscoverer.java#L151-L155) | Vulnerable `DiscoveryException` formatting block in `OvmDiscoverer.find()` leaking plaintext `password` when SSH authorization fails. |
| [https://github.com/apache/cloudstack/blob/348ce953a99246a756b527994f7745a7be038234/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java#L875-L881](https://github.com/apache/cloudstack/blob/348ce953a99246a756b527994f7745a7be038234/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java#L875-L881) | Catch block in `ResourceManagerImpl.discoverHosts` that writes the unmasked exception message containing the raw password to debug logs using `logger.debug`. |

貢獻指南

開啟貢獻指南

研究方向

從 OvmDiscoverer.find() 中第 151–155 行附近的 DiscoveryException 格式化處理開始,然後追蹤 ResourceManagerImpl.discoverHosts 如何在第 875–881 行附近處理該例外。確認失敗的 OVM 探索路徑不再於例外、偵錯日誌或 API 錯誤回應中暴露密碼。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
java
領域
infrastructure, security
Issue 類型
缺陷
難度
2/5
預估耗時
1-3 小時
活躍度
冷清
描述清晰度
描述清楚
新手友好度
68/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。