Full Report
SSH is used to log in to servers by everyone. Finding a vulnerability in the authentication process for this would be catastrophic. This is exactly what the author found here! In this case, it is libssh and not openssh, meaning that we cannot simply log into other people's servers. The function pki_verify_data_signature is used during the public key authentication check. In particular, it's checking to see if we've provided the proper signature to authenticate. At the beginning of the function, the rc (return code) is set to SSH_ERROR in order to prevent accidentally returning the improper value in case of a jump to the end. However, one of the later function calls sets the variable when doing a hash comparison check. The idea was to reuse the variable rc for various calls. But, this comes with a problem: if we can get rc returned with the code assuming that it's set to the original default value, we could spoof a success! In several places, there is a goto that assumes this. A good find for code snippets is here. But, in what cases? There is one directly before the signature verification! How do we trigger this to error? The function is trying to get a directly object from malloc. If the code errors, it would only be under extreme memory pressure. So, we need a memory leak or something else in order to trigger this? Kevin's POC generates a large amount of memory pressure by sending a large number of service requests that require zlib compression. By not reading the reply of the server, the data is kept in memory. Even though this isn't hard to do, it's complicated to have it run out of memory at the exact right time on this tiny 72 byte allocation. Analysis of the memory at this point did not work very well. So, instead of doing further work, they simply embraced the chaos. They kept triggering out of memory errors in the wrong locations. So, they ran the same copy of the PoC multiple times and it works! By bombarding the service, an attacker will eventually get lucky. This bug is only exploitable in very memory-constrained systems. The author uses a container where only 256MB are allowed to be used. Additionally, since this is a library, it depends on how the library is used. The author was using the demo ssh server from the examples directory to test this out. Overall, a simple bug once you see it but a crazy hard thing to find and exploit. Good work!
Analysis Summary
# Vulnerability: libssh Authentication Bypass via Memory Pressure
## CVE Details
- **CVE ID:** CVE-2023-2283
- **CVSS Score:** 6.1 (Medium) - *Note: While the impact is high, complexity reduces the score.*
- **CWE:** CWE-252 (Unchecked Return Value) / CWE-664 (Improper Control of a Resource Through its Lifetime)
## Affected Systems
- **Products:** libssh
- **Versions:** Versions prior to 0.10.5 and 0.9.7
- **Configurations:** Systems where libssh is used as a server and is under significant memory pressure or operating in memory-constrained environments (e.g., small containers, embedded devices).
## Vulnerability Description
The flaw exists in the `pki_verify_data_signature` function, which is responsible for validating public key signatures during the authentication process.
The function initially sets a return code variable (`rc`) to `SSH_ERROR` as a safety measure. However, this same variable is reused for various internal operations, including a hash comparison check. If a memory allocation (via `malloc`) fails specifically before the signature verification step, the code executes a `goto` statement that jumps to the end of the function. Due to the reuse of the `rc` variable in previous logic, if the variable happens to be set to `SSH_OK` at the time of the jump, the function inadvertently returns a success status. This allows an attacker to bypass authentication without providing a valid signature.
## Exploitation
- **Status:** Proof of Concept (PoC) available.
- **Complexity:** High (Requires precise timing and extreme memory pressure).
- **Attack Vector:** Network.
- **Mechanism:** The exploit involves "heap grooming" or "memory spraying" by sending a large volume of zlib-compressed service requests. By not reading the server's replies, the attacker forces the server to keep data in memory, increasing the likelihood of a failed allocation at the critical moment in the signature check.
## Impact
- **Confidentiality:** High (Unauthorized access to the server).
- **Integrity:** High (Unauthorized command execution/modification).
- **Availability:** Medium (The memory pressure required for exploitation may crash the service).
## Remediation
### Patches
- **libssh 0.10.5**: Contains the fix for this vulnerability.
- **libssh 0.9.7**: Contains the fix for older stable branches.
### Workarounds
- **Resource Limits:** Implement strict memory limits and monitoring to prevent the level of memory exhaustion required for this attack.
- **Update Libraries:** Ensure all applications statically or dynamically linked to libssh are updated to the patched versions.
## Detection
- **Indicators of Compromise:** Unusual spikes in memory usage followed by successful authentication attempts from unexpected IP addresses.
- **Detection Methods:** Monitor server logs for repeated, incomplete authentication attempts or failures followed by a single successful login without corresponding valid credentials.
## References
- **Vendor Advisory:** hxxps://www[.]libssh[.]org/security/advisories/CVE-2023-2283.txt
- **Researcher Post:** hxxps://x[.]com/kevin_backhouse/status/1666459308941357056
- **GitHub Issue/Commit:** hxxps://gitlab[.]com/libssh/libssh-mirror/-/commit/0656a88a (Fix implementation)