Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
regreSSHion — 这是我为CVE-2024-6387编写的PoC | Kitploit
工具/GitHubGitHub/teamos-hub/regresshion
漏洞分析漏洞利用渗透测试红队远程访问工具二进制利用
GitHubteamos-hub/regresshion

regreSSHion

这是我为CVE-2024-6387编写的PoC

查看仓库
1182年前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Qualys Security Advisory

regreSSHion: RCE in OpenSSH's server, on glibc-based Linux systems (CVE-2024-6387)

======================================================================== 目录

摘要 SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3 (Debian 3.0r6, 2005 年版)

  • 理论
  • 实践
  • 时机 SSH-2.0-OpenSSH_4.2p1 Debian-7ubuntu3 (Ubuntu 6.06.1, 2006 年版)
  • 理论,第一版
  • 理论,第二版
  • 实践
  • 时机 SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2 (Debian 12.5.0, 2024 年版)
  • 理论
  • 实践
  • 时机 关于 amd64 利用 补丁与缓解措施 致谢 时间线

======================================================================== 摘要

All it takes is a leap of faith
    -- The Interrupters, "Leap of Faith"

初步说明:OpenSSH 是世界上最安全的软件之一;此漏洞是其近乎完美的实现中一次偶然失误。其纵深防御设计和代码是典范和灵感来源,我们感谢 OpenSSH 开发者的杰出工作。

我们在 OpenSSH 服务器(sshd)中发现了一个漏洞(信号处理程序竞争条件):如果客户端未能在 LoginGraceTime 秒内(默认为 120 秒,旧版 OpenSSH 中为 600 秒)完成身份验证,则 sshd 的 SIGALRM 处理程序会被异步调用,但该信号处理程序调用了多个非异步信号安全的函数(例如 syslog())。此竞争条件在默认配置下影响 sshd。

经过调查,我们意识到此漏洞实际上是 CVE-2006-5051(“OpenSSH 4.4 之前版本中的信号处理程序竞争条件允许远程攻击者导致拒绝服务(崩溃),并可能执行任意代码”)的回归,该漏洞由 Mark Dowd 于 2006 年报告。

此回归是由 2020 年 10 月(OpenSSH 8.5p1)的提交 752250c(“为 OpenSSH 修订的日志基础设施”)引入的,该提交意外地从 sigdie() 函数中移除了“#ifdef DO_LOG_SAFE_IN_SIGHAND”,而 sigdie() 直接被 sshd 的 SIGALRM 处理程序调用。换句话说:

  • OpenSSH < 4.4p1 受此信号处理程序竞争条件影响,如果未针对 CVE-2006-5051 进行反向移植修补,或未针对 CVE-2008-4109(CVE-2006-5051 的错误修复)进行修补;
  • 4.4p1 <= OpenSSH < 8.5p1 不受此信号处理程序竞争条件影响(因为 CVE-2006-5051 补丁添加到 sigdie() 的“#ifdef DO_LOG_SAFE_IN_SIGHAND”将此不安全函数转换为安全的 _exit(1) 调用);
  • 8.5p1 <= OpenSSH < 9.8p1 再次受此信号处理程序竞争条件影响(因为“#ifdef DO_LOG_SAFE_IN_SIGHAND”被意外地从 sigdie() 中移除)。

此漏洞在基于 glibc 的 Linux 系统上可被远程利用,因为 syslog() 本身会调用异步信号不安全的函数(例如 malloc() 和 free()):这是一个以 root 身份执行的未认证远程代码执行,因为它影响 sshd 的特权代码,该代码未经沙箱化且拥有完全权限。我们尚未调查其他 libc 或操作系统;但 OpenBSD 显然不受影响,因为其 SIGALRM 处理程序调用 syslog_r(),这是 OpenBSD 于 2001 年发明的 syslog() 的异步信号安全版本。

为了远程利用此漏洞(据我们所知,CVE-2006-5051 此前从未被成功利用),我们从 Michal Zalewski 于 2001 年发表的一篇具有远见的论文《Delivering Signals for Fun and Profit》中汲取了灵感:

https://lcamtuf.coredump.cx/signals.txt

然而,我们立即面临三个主要问题:

  • 从理论角度,我们必须找到一条有用的代码路径,如果该路径在适当时间被 SIGALRM 中断,会使 sshd 处于不一致状态,然后我们必须在 SIGALRM 处理程序内部利用此不一致状态。

  • 从实践角度,我们必须找到一种方法在 sshd 中到达这条有用的代码路径,并最大化在正确时间中断它的机会。

  • 从时机角度,我们必须找到一种方法进一步增加在正确时间中断这条有用代码路径的机会,并且是远程实现。

为了专注于这三个问题,而不必立即对抗所有现代操作系统保护(特别是 ASLR 和 NX),我们决定先利用旧的 i386 上的 OpenSSH 版本,然后基于此经验,再针对较新版本:

  • 首先,“SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3”,来自“debian-30r6-dvd-i386-binary-1_NONUS.iso”:这是第一个默认启用权限分离,并已修补那个时代所有关键漏洞(特别是 CVE-2003-0693 和 CVE-2002-0640)的 Debian 版本。

    为了远程利用此版本,我们使用 SIGALRM 中断对 free() 的调用(在 sshd 的公钥解析代码中),使堆处于不一致状态,然后在 SIGALRM 处理程序中对 free() 的另一次调用期间利用此不一致状态。

    在我们的实验中,平均需要约 10,000 次尝试才能赢得此竞争条件;即,600 秒(LoginGraceTime)内接受 10 个连接(MaxStartups),平均约需 1 周才能获得远程 root shell。

  • 其次,“SSH-2.0-OpenSSH_4.2p1 Debian-7ubuntu3”,来自“ubuntu-6.06.1-server-i386.iso”:这是最后一个仍受 CVE-2006-5051 影响的 Ubuntu 版本(“OpenSSH 4.4 之前版本中的信号处理程序竞争条件”)。

    为了远程利用此版本,我们使用 SIGALRM 中断对 pam_start() 的调用,使 PAM 的某个结构处于不一致状态,然后在 SIGALRM 处理程序中对 pam_end() 的调用期间利用此不一致状态。

    在我们的实验中,平均需要约 10,000 次尝试才能赢得此竞争条件;即,120 秒(LoginGraceTime)内接受 10 个连接(MaxStartups),平均约需 1-2 天才能获得远程 root shell。

  • 最后,“SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u2”,来自“debian-12.5.0-i386-DVD-1.iso”:这是当前的 Debian 稳定版,并且受 CVE-2006-5051 回归的影响。

    为了远程利用此版本,我们使用 SIGALRM 中断对 malloc() 的调用(在 sshd 的公钥解析代码中),使堆处于不一致状态,然后在 SIGALRM 处理程序中对 malloc() 的另一次调用期间(更准确地说,在 syslog() 内部)利用此不一致状态。

    在我们的实验中,平均需要约 10,000 次尝试才能赢得此竞争条件,因此 120 秒(LoginGraceTime)内接受 100 个连接(MaxStartups)大约需要 3-4 小时。最终,平均约需 6-8 小时才能获得远程 root shell,因为我们只有一半时间能正确猜测 glibc 的地址(由于 ASLR)。

这项研究仍在进行中:

  • 我们仅针对虚拟机,而非裸机服务器,在基本稳定的网络链路上(约 10ms 数据包抖动);
  • 我们相信我们利用的各个方面都可以得到显著改进;
  • 我们已开始着手处理 amd64 利用,由于更强的 ASLR,这要困难得多。

在我们开始 amd64 工作几天后,我们注意到 OpenSSH 的公共 Bugzilla 中有以下关于 sshd 的 SIGALRM 处理程序中死锁的错误报告:

https://bugzilla.mindrot.org/show_bug.cgi?id=3690

因此,我们决定立即联系 OpenSSH 开发者(告知他们此死锁是由一个可利用的漏洞引起的),暂停了我们的 amd64 工作,并开始编写此公告。

======================================================================== SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3 (Debian 3.0r6, 2005 年版)


理论

But that's not like me, I'm breaking free
    -- The Interrupters, "Haven't Seen the Last of Me"

此 OpenSSH 版本的 SIGALRM 处理程序调用 packet_close(),后者调用 buffer_free(),然后调用 xfree() 进而调用 free(),而 free() 不是异步信号安全的:


302 grace_alarm_handler(int sig) 303 { ... 307 packet_close();

329 packet_close(void) 330 { ... 341 buffer_free(&input); 342 buffer_free(&output); 343 buffer_free(&outgoing_packet); 344 buffer_free(&incoming_packet);

35 buffer_free(Buffer *buffer) 36 { 37 memset(buffer->buf, 0, buffer->alloc); 38 xfree(buffer->buf); 39 }

51 xfree(void *ptr) 52 { 53 if (ptr == NULL) 54 fatal("xfree: NULL pointer given as argument"); 55 free(ptr); 56 }

因此,我们开始阅读此 Debian 的 glibc(2.2.5)的 malloc 代码,以查看对 free() 的第一次调用是否可以被 SIGALRM 中断,并在 SIGALRM 处理程序中对 free() 的第二次调用期间(上述第 341-344 行)被利用。由于该 glibc 的 malloc 未针对 Solar Designer 于 2000 年首创的 unlink() 技术进行加固,我们很快在 chunk_free()(由 free() 内部调用)中发现了一条有趣的代码路径:


1028 struct malloc_chunk 1029 { 1030 INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). / 1031 INTERNAL_SIZE_T size; / Size in bytes, including overhead. / 1032 struct malloc_chunk fd; /* double links -- used only if free. / 1033 struct malloc_chunk bk; 1034 };

2516 #define unlink(P, BK, FD)
2517 {
2518 BK = P->bk;
2519 FD = P->fd;
2520 FD->bk = BK;
2521 BK->fd = FD;
2522 } \

3160 chunk_free(arena ar_ptr, mchunkptr p) .... 3164 { 3165 INTERNAL_SIZE_T hd = p->size; / its head field / .... 3177 sz = hd & ~PREV_INUSE; 3178 next = chunk_at_offset(p, sz); 3179 nextsz = chunksize(next); .... 3230 if (!(inuse_bit_at_offset(next, nextsz))) / consolidate forward / 3231 { .... 3241 unlink(next, bck, fwd); .... 3244 } 3245 else 3246 set_head(next, nextsz); / clear inuse bit */ .... 3251 frontlink(ar_ptr, p, sz, idx, bck, fwd);

为了利用此代码路径,我们安排 sshd 的堆具有以下布局(chunk_X、chunk_Y 和 chunk_Z 是 malloc() 分配的内存块,p、s、f、b 分别是它们的 prev_size、size、fd 和 bk 字段):

-----|---+---------------|---+---------------|---+---------------|----- ... |p|s|f|b| chunk_X |p|s|f|b| chunk_Y |p|s|f|b| chunk_Z | ... -----|---+---------------|---+---------------|---+---------------|----- |<------------->| user data

  • 首先,如果对 free(chunk_Y) 的调用在第 3246 行 之后 但在第 3251 行 之前 被 SIGALRM 中断,则 chunk_Y 已被标记为空闲(因为第 3246 行清除了 chunk_Z 的 PREV_INUSE 位),但尚未链接到其双向链表中(第 3251 行):换句话说,chunk_Y 的 fd 和 bk 指针仍然包含用户数据(攻击者控制的数据)。
下载工具