CVE-2023-25136 doublefree
0.45元的巨额红包让我获得了复现这个cve的机会。
搭建环境
这个cve出现在openssh9.1p上,所以得安装这个版本的openssh,我是下载源码然后编译安装的,起初这样做的目的是便于后面gdb源码调试,但在安装完之后使用一般启动sshd的命令并没有办法启动成功,比如这种命令。
1 | service sshd start |
至于为什么不能这样做,大概率是我编译安装的openssh并不是通过apt安装的,导致包管理中没有sshd的信息,要启动自己编译安装的openssh得通过自己编译的sshd启动,比如
1 | /home/lot/openssh/openssh-9.1p1/sshd |
这样就算搭建成功了,白神给的文章中说还需要修改sshd_config文件,经过我的测试,发现并不需要,在这篇文章中,作者是采用PuTTY软件和sshd交互的,而且他使用的PuTTY版本很低,所以里面的一些协议或者算法过时了可能,想要连接成功就需要sshd也支持这些过时的协议或者算法,在poc脚本中直接采用paramiko
模块和sshd交互,这个模块没有使用这些旧协议或者算法,所以不需要。
漏洞成因
首先是PuTTY和sshd的关系,putty就是个连接工具。一般是windows用,支持ssh协议,当PuTTY连接sshd的时候,会在连接报文中会表明自己是PuTTY,poc脚本的transport.local_version = f"SSH-2.0-{CLIENT_ID}"
就是干这件事,然后sshd分析报文,解析出这个字段后就会进入专门的处理函数。
漏洞就出现在处理函数compat_kex_proposal
上,下面是这个函数的代码.
1 | compat_kex_proposal(struct ssh *ssh, char *p) |
openssh是这样调用这个函数的
1 | ptrb = compat_kex_proposal(v90, options.kex_algorithms); |
他把全局变量options的kex_algorithms
传入了这个函数,即p=kex_algorithms
然后当选择[1]条件通过时就让cp=p,然后free(cp),相当于free(kex_algorithms
),关键就是他free完没有清空kex_algorithms,然后在assemble_algorithms()
函数中又调用了这样一条语句
1 | v8 = kex_assemble_names(&o->kex_algorithms, def_kex, v3); |
他把kex_algorithms
的地址又传入kex_assemble_names()
函数中,他会执行下面这段代码,其中list
就等于kex_algorithms
的值,这样就把一个堆块free了两次,导致程序崩溃。
1 | if ((tmp = kex_names_cat(list + 1, def)) == NULL) { |
攻击过程
poc如下
1 | import paramiko |
直接拿poc跑,然后断在kex_assemble_names()
函数的free(list)
语句,下面是当时的截图,能够比较清晰的看见即将free0x556d983e2a00
,但这个堆块同时在smallbins
上,肯定就会导致doublefree,进而导致程序崩溃。
直接注意的一点是不能先断在compat_kex_proposal
让程序执行到这里再断到free(list)
,因为这个过程很耗时,导致客户端退出连接,那sshd也不会执行正常逻辑了,即不会执行到free(list)
。
攻击效果
感觉有点差强人意,sshd是每有一个连接就新开一个进程,这个cve只能导致和自己连接的分支进程崩溃,不会导致sshd崩溃。至于能不能rce,我只能说理论上可以。