最近出了一个libSSH认证绕过漏洞,刚开始时候看的感觉这洞可能挺厉害的,然后很快github上面就有PoC了,msf上很快也添加了exp,但是在使用的过程中发现无法getshell,对此,我进行了深入的分析研究。

前言

360发了一篇分析文章,有getshell的图:

Python版本的PoC到Github上搜一下就有了:

https://github.com/search?utf8=%E2%9C%93&q=CVE-2018-10933&type=

环境

libSSH-0.7.5源码下载地址:https://www.libssh.org/files/0.7/libssh-0.7.5.tar.xz

PS: 缺啥依赖自己装,没有当初的编译记录了,也懒得再来一遍

$ tar -xf libssh-0.7.5.tar.xz
$ cd libssh-0.7.5
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
$ make

主要用两个,一个是SSH服务端Demo:examples/ssh_server_fork, 一个是SSH客户端Demo:./examples/samplessh

服务端启动命令:sudo examples/ssh_server_fork -p 22221 127.0.0.1 -v

客户端使用命令:./examples/samplessh -p 22221 myuser@127.0.0.1

PS: 用户那随便填,我使用myuser,只是为了对比正常认证请求和bypass请求有啥区别,正常情况下SSH服务端是使用账户密码认证,账户是: myuser, 密码是: mypassword

修改../src/auth.cssh_userauth_xxxx函数,我修改的是ssh_userauth_password:

根据360的分析文章和我自己的研究结果,修改了上图箭头所示的三处地方,这样./examples/samplessh就会成为了验证该漏洞的PoC

PS: 修改完源码后记得再执行一次make

漏洞分析

根据服务端输出的调试信息,可以找到ssh_packet_process函数, 看到第1211行:

1121        r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user);

然后追踪到callbacks数组等于default_packet_handlers

正常情况下,发送SSH2_MSG_USERAUTH_REQUEST请求,进入的是ssh_packet_userauth_request函数,而该漏洞的利用点就是,发送SSH2_MSG_USERAUTH_SUCCESS请求,从而进入ssh_packet_userauth_success函数

PS: 我们可以进入该数组中的任意函数,但是看了下其他函数,也没法getshell

正常情况下的执行路径是:

ssh_packet_userauth_request ->
ssh_message_queue ->
ssh_execute_server_callbacks ->
ssh_execute_server_request ->
rc = session->server_callbacks->auth_password_function(session,msg->auth_request.username, msg->auth_request.password,session->server_callbacks->userdata);

找找这个函数,发现在服务端Demo中进行了设置:

// examples/ssh_server_fork.c
......
514    struct ssh_server_callbacks_struct server_cb = {
515        .userdata = &sdata,
516        .auth_password_function = auth_password,
517        .channel_open_request_session_function = channel_open,
518    };
519    ssh_callbacks_init(&server_cb);
520    ssh_callbacks_init(&channel_cb);
521    ssh_set_server_callbacks(session, &server_cb);
......

找到了auth_password函数,由服务端的编写者设置的:

// examples/ssh_server_fork.cstatic int auth_password(ssh_session session, const char *user,const char *pass, void *userdata) {struct session_data_struct *sdata = (struct session_data_struct *) userdata;(void) session;if (strcmp(user, USER) == 0 && strcmp(pass, PASS) == 0) {sdata->authenticated = 1;return SSH_AUTH_SUCCESS;}sdata->auth_attempts++;return SSH_AUTH_DENIED;
}

认证成功后的路径:

ssh_message_auth_reply_success ->
ssh_auth_reply_success:
994  session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
995  session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;

正常情况下,在SSH登录成功后,libSSH给session设置了认证成功的状态,SSH服务端编写的人给自己定义的标志位设置为1: sdata->authenticated = 1;

利用该漏洞绕过验证,服务端的流程:

ssh_packet_userauth_success:SSH_LOG(SSH_LOG_DEBUG, "Authentication successful");SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_SUCCESS");session->auth_state=SSH_AUTH_STATE_SUCCESS;session->session_state=SSH_SESSION_STATE_AUTHENTICATED;session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;

可以成功的把libSSH的session设置为认证成功的状态,但是却不会进入auth_password函数,所以用户定义的标志位sdata->authenticated仍然等于0

我们在网上看到别人PoC验证成功的图,就是由ssh_packet_userauth_success函数输出的Authentication successful

研究不能getshell之谜

很多人复现该漏洞的时候肯定都发现了,服务端调试的信息都输出了认证成功,但是在getshell的时候却一直无法成功,根据上面的代码,发现session已经被设置成认证成功了,但是为啥还无法获取shell权限呢?对此,我又继续深入研究。

根据服务端的调试信息,我发现都能成功打开channel,但是在下一步pty-req channel_request我服务端显示的信息是被拒绝:

所以我继续跟踪代码执行的流程,跟踪到了ssh_execute_server_request函数:

166        case SSH_REQUEST_CHANNEL:channel = msg->channel_request.channel;if (msg->channel_request.type == SSH_CHANNEL_REQUEST_PTY &&ssh_callbacks_exists(channel->callbacks, channel_pty_request_function)) {rc = channel->callbacks->channel_pty_request_function(session, channel,msg->channel_request.TERM,msg->channel_request.width, msg->channel_request.height,msg->channel_request.pxwidth, msg->channel_request.pxheight,channel->callbacks->userdata);if (rc == 0) {ssh_message_channel_request_reply_success(msg);} else {ssh_message_reply_default(msg);}return SSH_OK;

接着发现ssh_callbacks_exists(channel->callbacks, channel_pty_request_function)检查失败,所以没有进入到该分支,导致请求被拒绝。

然后回溯channel->callbacks,回溯到了SSH服务端ssh_server_fork.c

530    ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
531    ssh_event_add_session(event, session);
532    n = 0;
533    while (sdata.authenticated == 0 || sdata.channel == NULL) {
534        /* If the user has used up all attempts, or if he hasn't been able to
535         * authenticate in 10 seconds (n * 100ms), disconnect. */
536        if (sdata.auth_attempts >= 3 || n >= 100) {
537            return;
538        }
539        if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
540            fprintf(stderr, "%s\n", ssh_get_error(session));
541            return;
542        }
543        n++;
544    }
545    ssh_set_channel_callbacks(sdata.channel, &channel_cb);

在libSSH中没有任何设置channel的回调函数的代码,只要在服务端中,由开发者手动设置,比如上面的545行的代码

然后我们又看到了sdata.authenticated,该变量再之前说了,该漏洞绕过的认证,只能把session设置为认证状态,却无法修改SSH服务端开发者定义的sdata.authenticated变量,所以该循环将不会跳出,直到n = 100的情况下,return结束该函数。这就导致了我们无法getshell。

如果想getshell,有两种修改方式:

1.删除sdata.authenticated变量

533    while (sdata.channel == NULL) {
......
544    }

2.把channel添加回调函数的代码移到循环之前

530    ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
531    ssh_event_add_session(event, session);
532    ssh_set_channel_callbacks(sdata.channel, &channel_cb);
533    n = 0;
534    while (sdata.authenticated == 0 || sdata.channel == NULL) {
......

在修改了服务端代码后,我也能成功getshell:

总结

之后我看了审计了一下ssh_execute_server_request函数的其他分支,发现SSH_REQUEST_CHANNEL分支下所有的分支:

SSH_CHANNEL_REQUEST_PTY
SSH_CHANNEL_REQUEST_SHELL
SSH_CHANNEL_REQUEST_X11
SSH_CHANNEL_REQUEST_WINDOW_CHANGE
SSH_CHANNEL_REQUEST_EXEC
SSH_CHANNEL_REQUEST_ENV
SSH_CHANNEL_REQUEST_SUBSYSTEM

都是调用channel的回调函数,所以在回调函数未注册的情况下,是无法成功getshell。

最后得出结论,CVE-2018-10933并没有想象中的危害大,而且网上说的几千个使用libssh的ssh目标,根据banner,我觉得都是libssh官方Demo中的ssh服务端,存在漏洞的版本的确可以绕过认证,但是却无法getshell。

引用

  1. https://0x48.pw/libssh/
  2. https://www.anquanke.com/post/id/162225
  3. https://github.com/search?utf8=%E2%9C%93&q=CVE-2018-10933&type=
  4. https://www.libssh.org/files/0.7/libssh-0.7.5.tar.xz
  5. https://0x48.pw/libssh/libssh_0.7.6/src/packet.c.html#ssh_packet_process
  6. https://0x48.pw/libssh/libssh_0.7.5/src/packet.c.html#default_packet_handlers

libssh 认证绕过漏洞(cve-2018-10933)分析相关推荐

  1. 网络靶场实战--飞塔(Fortinet)防火墙认证绕过漏洞(CVE-2022-40684)

    本环境是蛇矛实验室基于"火天网演攻防演训靶场"进行搭建,通过火天网演中的环境构建模块,可以灵活的对目标网络进行设计和配置,并且可以快速进行场景搭建和复现验证工作. 背景 Forti ...

  2. Apache Qpid 认证绕过漏洞

    漏洞名称: Apache Qpid 认证绕过漏洞 CNNVD编号: CNNVD-201303-222 发布时间: 2013-03-13 更新时间: 2013-03-13 危害等级:    漏洞类型: ...

  3. 速修复!Netgear交换机曝3个严重的认证绕过漏洞

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 昵称为 "Gynvael Coldwind" 的波兰安全研究员在网件中找到并报告了网件交换机中的三个严重漏洞 Demon's ...

  4. Bouncy Castle 加密库修复高危的认证绕过漏洞

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 最近,Bouncy Castle 加密库修复了一个高危的认证绕过漏洞. 该项目建立于2000年,表示 Java 和 C# 加密中使用的 ...

  5. 【CNNVD-201303-018】D-Link DIR-645 Routers 认证绕过漏洞复现

    目录 0x00 漏洞概述 0x01 影响版本 0x02 漏洞评级 0x03 shodan搜索漏洞环境 0x04 漏洞验证 0x05 修复建议 0x00 漏洞概述 友讯科技股份有限公司(D-Link C ...

  6. 思科不打算修复SMB路由器中严重的认证绕过漏洞

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 思科SMB路由器中存在两个严重的漏洞(CVE-2023-20025和CVE-2023-20026),可导致未认证攻击者完全控制目标设备,以roo ...

  7. Nacos 1.4.1 紧急升级修复Alibaba Nacos 认证绕过漏洞

    使用背景 Nacos是Spring Cloud Alibaba的微服务的配置和发现的组件,目前暴露出安全漏洞,主要包括如下: 根据Nacos官方在github发布的issue,Alibaba Naco ...

  8. Apache Shiro 身份认证绕过漏洞(CVE-2022-32532)漏洞复现

    Apache Shiro 身份认证绕过漏洞(CVE-2022-32532)漏洞复现 0x01 漏洞简介 Apache Shiro 是一个强大且易用的 Java 安全框架,通过它可以执行身份验证.授权. ...

  9. 【认证绕过】NACOS身份认证绕过漏洞分析

    前言 工作中遇到一个nacos服务认证绕过的问题,在此总结一下漏洞原因. 一.nacos简介 官方文档描述: Nacos 致力于帮助您发现.配置和管理微服务.Nacos 提供了一组简单易用的特性集,帮 ...

最新文章

  1. nginx proxy_next_upstream导致的一个重复提交错误
  2. 重启oracle服务顺序,oracle 10g]命令行启动ORACLE服务及顺序
  3. python网络攻击代码_Python-python网络编程写arp攻击代码
  4. BZOJ 1412: [ZJOI2009]狼和羊的故事( 最小割 )
  5. 苹果iOS设备解锁软件:iToolab UnlockGo
  6. cnchar.js 获取汉字的拼音和笔画数的js库 cnchar2.0 支持繁体字、笔画顺序、多音字词
  7. Arcgis操作系列一:shp矢量数据的面积计算
  8. 测试网卡芯片型号的软件,查看电脑无线网卡型号_查看无线网卡芯片型号
  9. 效率倍升:逐浪HMS主题大师1.2-全渠道自动打包、快速传送、锁屏提取、资源审计,移动主题设计辅助利器(全面支持华V米O)
  10. protobuf3 oneof
  11. 农大计算机工程,肖德琴-华南农业大学计算机科学与工程系
  12. 仓储物流系统初级架构
  13. 哪些深度相机有python接口_三种主流深度相机介绍
  14. 轻蜗牛直租平台-业务背景介绍
  15. 深入浅出图神经网络|GNN原理解析☄学习笔记(四)表示学习
  16. LDP中的UE(一元编码)和LATENT中方法UER实现
  17. Mac恢复被修改的文档
  18. 0-c语言入门这一篇就够了-学习笔记(一万字)
  19. Linux主机安全配置
  20. teredo实现ipv4公网环境下接入ipv6

热门文章

  1. 笔记本的处理器型号怎么区别好坏
  2. Linux_Shell基础
  3. j-link接口定义及实际使用
  4. Tomcat容器做到自我保护,设置最大连接数(服务限流:tomcat请求数限制)
  5. [转]CSS3 transform顺序问题
  6. 算法导论-MIT笔记
  7. LigerUI 使用教程表格篇
  8. 配置Spring数据源c3p0与dbcp
  9. 简单实现ibatis的物理分页
  10. 什么样的人不适合做SEO呢