CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

渗透技巧 10个月前 admin
450 0 0

TL; DR

这两天和 @leoomxj 一起分析了和写了一下 CVE-2023-27997 的漏洞利用, 顺便一想想 CVE-2022-42475 这个漏洞也过去蛮久的了,于是准备把这篇 CVE-2022-42475 漏洞分析分享出来。注:本文不含完整的漏洞利用脚本。

下图为 CVE-2023-27997 的利用录屏, 与本文要讲的 CVE-2022-42475 无关

注:这篇笔记成文于 2023-02-28 , 发表于 2023-06-18

正文

2022 年 12 月 12 日,Fortinet 官方发布了影响 FortiGate SSLVPN 的 RCE 漏洞 CVE-2022-42475 相关信息。本文对此漏洞的成因进行分析。

环境配置

测试版本为 7.2.2, 环境的安装和部署可以参考这篇文章: https://blog.csdn.net/meigang2012/article/details/87903878。 另外感谢下 @explore 网管大哥在部署环境上的帮助。

导入虚拟机后需要配置下网络, 参考 https://docs.fortinet.com/document/fortigate-private-cloud/7.2.0/vmware-esxi-administration-guide/615472/configuring-port-1

有个重点 dns 要设置下:

1
2
3
4
5
6
config system dns
set primary <Primary DNS server>
set secondary <Secondary DNS server>
end

# The default DNS servers are 208.91.112.53 and 208.91.112.52.

需要配置一个 sslvpn ,然后能访问即可。

设备权限获取

挂载虚拟机 vmdk 硬盘后, 可以看到有个 rootfs.gz 文件。

1
2
root@Jas-22:/home/user/Desktop/fuck-fortigate/rootfs# ls
bin  bin.tar.xz  boot  data  data2  dev  etc  fortidev  init  lib  lib64  migadmin.tar.xz  node-scripts.tar.xz  proc  sbin  sys  tmp  usr  usr.tar.xz  usr.tar.xz.chk  var

可以看到有如下内容, 我们需要进一步解压 bin.tar.xz 文件夹,使用 sbin 目录自带的命令解压

1
2
chroot . sbin/ftar -cf bin.tar bin
chroot . sbin/xz --check=sha256 -e bin.tar

然后需要在 bin 目录中放入后门,第一个是生成一个反弹shell替换 smartctl 文件, 以及我这里放入一个 busybox ,做一个软链接 ln -sn /bin/busybox bin/sh 设备中默认没有 bash (sh)文件 (或者说他的 sh 功能比较鸡肋), 然后重新打包。

1
2
3
4
5
6
7
8
```bash
# 重新打包 bin 文件夹
chroot . sbin/ftar -cf bin.tar bin
chroot . sbin/xz --check=sha256 -e bin.tar
# 重新打包 rootfs
find . | cpio -H newc -o > ../rootfs.raw
cat ./rootfs.raw | gzip > rootfs.gz
```

重打包完成后, 我们需要过调几个校验,才能正常启动系统。

vmlinux :

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

解下来是 bin/init:

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

这里会校验 fgtsum , 失败直接给你重启最后是 rootfs 检查

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

由于,我是采用 vmware + gdb 的调试方式, 即 使用VMware和GDB进行Linux内核调试 (bestwing.me), 因此我直接写了一个 gdb python 脚本动态修改返回值即可:

这里皮一句,依稀记得这段代码是 chatGPT 帮我生成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import gdb

class SetRaxBreakpoint(gdb.Breakpoint):
    def __init__(self, bp_expr, rax_value, temporary=False):
        gdb.Breakpoint.__init__(self, bp_expr, gdb.BP_BREAKPOINT, False, temporary )
        # super(SetRaxBreakpoint, self).__init__(spec, temporary)
        self.rax_value = rax_value
        self.silent = True

    def stop(self):
        gdb.execute('set $rax = {}'.format(self.rax_value))

gdb.execute('set architecture i386:x86-64')
gdb.execute('set pagination off')

r1 = SetRaxBreakpoint('*0xffffffff807ac11c', 0)
r2 = SetRaxBreakpoint('*0x4518C9', 1) # 
r3 = SetRaxBreakpoint('*0x277fccc', 1)

当系统成功执行后,使用 diagnose hardware smartctl 即可运行我们的后门文件。

漏洞分析

Root Cause

在处理 用户 post 数据的时候,

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

会根据 http header 中的 content-lenght字段分配 buffer , 然而在分配之前, 即在调用 pool_alloc 函数之前

pool_alloc 有两个参数, 第二个为即将要分配的buffer 大小

rax 为用户请求结构体指针,偏移位置 0x18 存放了 CL 值。先将 CL 放在 eax 寄存器中,使用 lea 指令将其加一后放在 esi 寄存器,再用 movsxd 扩展为 64 bit 值。

在调用 pool_alloc 函数时使用 32 位数值 + 1 拓展成 64 位的方法,这里存在整数溢出。那么我们可以构造特殊的 CL 值,比如 0x1b00000000,经过运算拓展之后会变成 0x1 。会分配一个小的内存空间导致溢出

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

上面这个是断点是初始化 buffer , 可以看到大小是 1, 之后在 memcpy 处就 会溢出。

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

exploit

这里首先明确一下,我不会公开完整的利用,这里这提一点利用上的思路。利用整体思路参考 Orange 2017 年的文章, 大致思路就是进行进行竞争, 一边在堆上布局 SSL 结构体,一边触发漏洞,然后溢出覆盖 SSL 结构体。

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

之后就可以控制 PC , 当我们控制 PC 后我们需要确定 padding , 这个步骤比较繁琐, 我拿 PoC 改了一个循环 fuzz 的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
def do_exploit(padding):
 ...
 payload = p64(ret) * padding + 'A' * 0x1000
 ...

for i in range(123, 384):
    padding = int(i )
    if do_exploit(padding):
        continue
    else:
        print('timeout ...')
        break

然后对 ret 这个gadget 下一个断点, 当触发断点的时候, 脚本会因为timeout 触发异常,然后这附近大概就是咱们的padding。

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

然后这个时候只需要找栈迁移的gadget 即可。这里我找了的 push rdx ; add bl, byte ptr [rbx + 0x41] ; pop rsp ; pop rbp ; ret , 这个gadget , 正好可以将栈迁移到 rdi 寄存器所指向的内存地址上。然后将剩下 ret 指令的替换成 pop rax ; ret
这样的gadget, 这样就能一直迁移到可控制的 AAAAAAA 的地方进行 rop 链了。

再阅读这一部分的内容,我突然反应过来其实不需要替换指令, 当前的 ret 指令就足够迁移到可控的 AAAA 的位置进行 ROP 了

由于 fortigate 的这个程序很大,正如 CVE-2023-27997 的作者所说的,

CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

该程序很大,想找到适合的 gadget 来组成 ropchain 仅仅需要花费一点时间就行了。

参考连接

【隧道篇 / SSL】(6.0) ❀ 02. 通过 SSL 访问 IPsec (中) ❀ FortiGate 防火墙_启用隧道分割_飞塔老梅子的博客-CSDN博客

Configuring port 1 | FortiGate Private Cloud 7.2.0 (fortinet.com)

attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn

使用VMware和GDB进行Linux内核调试 (bestwing.me)

CVE-2022-42475 | CataLpa’s Site (wzt.ac.cn)

转:fortios 5.4后门植入 – studyskill – 博客园 (cnblogs.com)

 

原文始发于Swing:CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow

版权声明:admin 发表于 2023年6月19日 上午9:23。
转载请注明:CVE-2022-42475-FortiGate-SSLVPN-HeapOverflow | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...