CVE-2025-15224深度解析:libcurl libssh后端认证绕过漏洞

本文详细分析了libcurl在使用libssh后端时存在的一个安全漏洞(CVE-2025-15224)。当应用程序未显式设置CURLSSH_AUTH_AGENT标志时,若用户运行了ssh-agent,libcurl仍会使用代理进行认证,从而绕过了密钥口令要求。

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

漏洞复现步骤

  1. 配置并构建带有--with-libssh选项的libcurl。
  2. 编译以下概念验证(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;
    }
    
  3. 确保当前用户在host.example上拥有账户,用户的SSH密钥设有口令,公钥已添加到对应用户的~/.ssh/authorized_keys文件中,并且ssh-agent正在运行且已添加该用户密钥。
  4. 执行概念验证应用程序。
  5. 结果: 应用程序无需SSH密钥口令即可成功认证到host.example

技术详情与讨论

问题代码位置:

  • libcurl调用libssh ssh_userauth_publickey_auto的代码:链接
  • libssh ssh_userauth_publickey_auto与ssh-agent交互的代码:链接

影响评估:

  • 主要影响: 绕过了SSH密钥口令要求。
  • 讨论:
    • 漏洞影响可能相对较小,因为用户需要运行代理并已输入口令,但这实际上是一种相当常见的情况。
    • 可能引发严重问题的场景有限。例如,某些应用程序可能出于特定原因(如希望每次认证都要求用户输入密钥口令作为第二因素)而不希望使用代理。在这种情况下,libssh后端会绕过第二因素(口令)。

漏洞等级: curl开发团队将严重性评级为低(Low)。原因在于攻击者已经处于受信任的上下文中(代理正在运行,口令已输入)。这可能被用于链式攻击,但更偏向于一种不便。

修复尝试与方案:

  1. 初步修复尝试(存在问题):

    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状态,因为无法进行任何认证。

  2. 提议的修复方案:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    diff --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日
  • 赏金状态: 无(由互联网漏洞赏金计划管理)
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计