CVE-2025-15224:未设置代理时libssh密钥口令绕过漏洞
报告摘要
漏洞概述:
libcurl的libssh后端未能正确实现CURLOPT_SSH_AUTH_TYPES选项中的CURLSSH_AUTH_AGENT标志。如果设置了CURLSSH_AUTH_PUBLICKEY,实现的行为会如同CURLSSH_AUTH_AGENT始终被隐式定义,因此认证时不需要密钥口令。
后果:
如果用户正在运行ssh-agent/pageant,使用libcurl且未专门设置CURLSSH_AUTH_AGENT的应用程序仍会使用ssh-agent/pageant进行认证,从而绕过对密钥口令的认知要求。
影响版本: 8.17.0
漏洞复现步骤
- 配置并构建带有
--with-libssh选项的libcurl。 - 编译以下概念验证(PoC)应用程序:
1 2 3 4 5 6 7 8 9 10 11 12 13#include <curl/curl.h> int main(void) { CURL *curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_URL, "sftp://host.example/"); curl_easy_setopt(curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PUBLICKEY); curl_easy_perform(curl); curl_easy_cleanup(curl); } return 0; } - 确保当前用户在
host.example上拥有账户,用户的SSH密钥设有口令,公钥已添加到对应用户的~/.ssh/authorized_keys文件中,并且ssh-agent正在运行且已添加该用户密钥。 - 执行概念验证应用程序。
- 结果: 应用程序无需SSH密钥口令即可成功认证到
host.example。
技术详情与讨论
问题代码位置:
- libcurl调用libssh
ssh_userauth_publickey_auto的代码:链接 - libssh
ssh_userauth_publickey_auto与ssh-agent交互的代码:链接
影响评估:
- 主要影响: 绕过了SSH密钥口令要求。
- 讨论:
- 漏洞影响可能相对较小,因为用户需要运行代理并已输入口令,但这实际上是一种相当常见的情况。
- 可能引发严重问题的场景有限。例如,某些应用程序可能出于特定原因(如希望每次认证都要求用户输入密钥口令作为第二因素)而不希望使用代理。在这种情况下,libssh后端会绕过第二因素(口令)。
漏洞等级: curl开发团队将严重性评级为低(Low)。原因在于攻击者已经处于受信任的上下文中(代理正在运行,口令已输入)。这可能被用于链式攻击,但更偏向于一种不便。
修复尝试与方案:
-
初步修复尝试(存在问题):
1 2 3 4 5 6 7 8 9--- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -974,11 +974,11 @@ static int myssh_in_AUTH_PKEY_INIT(struct Curl_easy *data, return rc; } myssh_to(data, sshc, SSH_AUTH_PKEY); } - else { + else if(data->set.ssh_auth_types & CURLSSH_AUTH_AGENT) {问题: 此修复会导致当
CURLSSH_AUTH_AGENT未设置时,代码永远卡在SSH_AUTH_PKEY_INIT状态,因为无法进行任何认证。 -
提议的修复方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c index 5d5125b526..bde6355f73 100644 --- a/lib/vssh/libssh.c +++ b/lib/vssh/libssh.c @@ -921,7 +921,11 @@ static int myssh_in_AUTHLIST(struct Curl_easy *data, "keyboard-interactive, " : "", sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ? "password": ""); - if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { + /* For public key auth we need either the private key or + CURLSSH_AUTH_AGENT. */ + if((sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) && + (data->set.str[STRING_SSH_PRIVATE_KEY] || + (data->set.ssh_auth_types & CURLSSH_AUTH_AGENT))) { myssh_to(data, sshc, SSH_AUTH_PKEY_INIT); infof(data, "Authentication using SSH public key file"); }修复逻辑: 对于公钥认证,要求必须提供私钥文件路径(
CURLOPT_SSH_PRIVATE_KEYFILE)或设置了CURLSSH_AUTH_AGENT标志,否则直接失败。 注意: 此修复使libssh后端的行为与libssh2后端略有不同。libssh2会自动尝试查找并使用的私钥(例如$HOME/.ssh/id_*),而此修复方案下的libssh后端在不满足上述条件时将直接失败,而不是尝试定位私钥。
CWE分类讨论:
- CWE-1023(缺失因素的不完全比较): 用于比较本身存在问题的情况。
- CWE-287(不正确的认证): 更准确地描述了最终导致的安全弱点(应用逻辑完全忽略了配置状态)。
- 最终倾向使用CWE-287。
时间线与状态
- 报告提交: 2025年12月28日
- 状态更新: 2026年1月7日前已标记为已解决(Resolved)
- CVE分配: CVE-2025-15224
- 修复PR: https://github.com/curl/curl/pull/20110
- 报告披露: 2026年1月7日
- 赏金状态: 无(由互联网漏洞赏金计划管理)