前言
之前就想复现这个洞,不过因为环境的问题迟迟没有开工。巧在前一阵子有个师傅来找我讨论劫持ssl结构体中函数指针时如何确定堆溢出的偏移,同时还他把搭建好了的环境发给了我,因此才有了此文。
如何劫持SSL结构体指针实现控制程序流
就我个人理解而言,我觉得劫持的这个函数指针类似于我们常见的 __malloc_hook,__free_hook。它本身的值为空,当他不为空时,便会调用这个函数指针。如果我们把这个函数指针劫持为合适的gadget便可以控制程序的执行流。相关代码如下:
1 | __int64 __fastcall debug_2nd_control(__int64 a1, char a2) |
漏洞点
从下面的汇编中可知,这里分配的大小是由movsxd rsi, esi,直接从4字节扩展为了8字节,如果我们把大小控制为0x1b00000000,这样就会导致分配并初始化的大小为1,从而产生堆溢出。利用手法是,在堆上大量喷射SSL结构体,从而劫持其中对应的函数指针。
1 | 0000000001811174 8B 40 18 mov eax, [rax+18h] ; Keypatch modified this from: |
如何确定填充数量
网上已经有文章 (https://forum.butian.net/index.php/share/2166) 给出了一个可劫持到函数指针的poc。我们这里就直接用了他这种布局,重点记录一下如何找到这个填充的数量。对于这个固件而言ssl结构体初始化时,我们可以看到如下的代码。很明显可以看到,他会把字符串read_post_data拷贝到距离结构体偏移为 200的地方。而根据上面的代码可知,我们要劫持的函数指针在结构体偏移为192的地方。故我们只需定位到read_post_data,即可确定偏移。
1 | sub_181BC20(a2, "read_post_data", 0, 1, (__int64)sslvpnd_read_post_data); |
调试时内存分布如下,有0x2638-0x1818 = 0xE20 = 3616
1 | (gdb) i r $rdi |
poc
1 | import struct |
参考链接
https://forum.butian.net/index.php/share/2166
https://bestwing.me/CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow.html
https://wzt.ac.cn/2022/12/15/CVE-2022-42475/
https://devco.re/blog/2019/08/09/attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn/