拖了挺久了,网上关于这CVE复现的文章不多,文章内容讲的也比较简略,甚至还有文章存在一些错误表述……中间一度想要放弃qwq,后来也是连续肝了好几天去调试 orz,终于突破,主要是触发劫持程序流的流程问题
上篇文章:CVE-2023-27997环境搭建以及堆溢出复现 | 1uckyc’s blog
讲到可以实现堆溢出任意写入了,参考文章(放在文末),然后可以去修改ssl结构体从而控制程序流
先要解决第一个问题:怎么稳定溢出到ssl结构体呢?
ssl结构体是用ssl_new申请得到的,当我们申请到ssl结构体之后会申请缓冲区来存放我们申请的原始数据,我们可以先创建多个ssl结构体、然后free两块(je_malloc的堆块先进后出),再申请ssl结构体并发送大小与ssl结构体大小差不多的请求,此时我们就可以通过堆溢出来修改ssl结构体了。实际操作时可能会有其他的chunk干扰、多创建一些ssl结构体找到合适位置
小技巧:利用gdb的commands和logging可以更方便观察ssl结构体的地址,0x166CA12
1 | b *0x166CA12 |
然后就是我们要怎么劫持程序流呢?
先讲一下网上文章最大问题: 这里利用根本没有用到ssl_do_handshake
,虽然也是利用的ssl+0x30
,可能是我没能发现这条利用链,师傅们都是简单带过、我没能领会到其中精髓,如果有师傅看到这篇文章又恰好有所了解的话,请不吝赐教,不胜感激
以下是我自己调试发现ssl_read会执行到
sub_1AFB0中,*(a1+8)
实际是libssl.so
的函数跳表(我是这样理解的)
这里是根据调试得到的地址,到libssl.so里面查看 *(a1+8)+0x38
:
这里又会跳到*(a1+8)+0x68
*(a1+8)+0x68
:
在sub_26B30函数中就到了指针
这里会直接执行*(a1+0x30)
,a1也就是ssl结构体
注意这里执行之前有执行SSL_in_init
、也就是ssl+0x64
需要为非0值
后面和xsh师傅交流了下,socket链接时可以选择暂时不进行握手,这样ssl+0x64
也就会为1,当然也可以堆溢出覆盖为1
1 | _socket = _default_context.wrap_socket(_socket, do_handshake_on_connect=False) |
从上面截图可以看到,我们执行call ssl+0x30
时,RDI、RSP都是ssl结构体本身地址,后续就是找gadget构造ROP
构造ROP
程序比较大,gadget有点难找,而且ssl能写的地方也有限,需要慢慢试
注意最后rdi、rbp的地址是我们可以溢出写的ssl结构体。
参考文章:
CVE-2022-42475-FortiGate-SSLVPN HeapOverflow 学习记录 - 狒猩橙 - 博客园 (cnblogs.com)
奇安信攻防社区-CVE-2022-42475 FortiGate SSLVPN 堆溢出漏洞分析与利用 (butian.net)
CVE-2023-27997-FortiGate-SSLVPN-HeapOverflow (bestwing.me)
Fortigate SSL VPN漏洞分析 - 知乎 (zhihu.com)Lexfo – Cabinet d’expertises techniques en sécurité des systèmes d’information. Aider nos clients dans la protection de leur patrimoine informationnel par une approche offensive et innovante.
- 本文作者: 1uckyc
- 本文链接: https://1uckyc.github.io/2024/05/20/CVE-2023-27997堆溢出利用(续)/