0x00 前言
这一节开始,我们学习整数溢出相关漏洞。
实验环境:Win10专业版+VMware Workstation 15 Pro+Win7 x86 sp1
实验工具:VS2015+Windbg+KmdManager+DbgViewer
0x01 漏洞原理
整数溢出
整数分为有符号和无符号两种类型,有符号数以其最高为作为其符号位,即正整数最高为0,负整数最高为为1,而无符号数无此类情况,其取值范围是非负数。平常在编程时。最常用到的整型变量有 short int(2B),unsigned int(2B),int(4B)和long int(4B)。不同类型的整数在内存中均有不同的取值范围,当我们向其存储的数据超过该类型整数的最大值,就会导致整数溢出。溢出后的数据,可能会被截断,而造成程序出现错误。
Demo(基于栈的整数溢出)
1 |
|
上面的demo中,size为无符号短整数(0-65535),当我们输入大于65535是就会造成溢出,例如我们输入65536,最终得到的size为0,从而绕过边界检查,但是在memcpy函数复制数据时,使用的是int类型的i参数,导致栈溢出。
Demo(基于堆的整数溢出)
1 |
|
上述demo中size为unsigned short int,小于5时,例如,当size=2时,size减去5则得到负数,但size取值范围导致无法识别负数,而得到正数65533,而分配得到大的堆块,从而溢出导致覆盖到后面的堆管理结构。
分析
打开漏洞驱动程序源码,找到漏洞函数TriggerIntegerOverflow,如下:
1 | __declspec(safebuffers) |
函数中比较了用户提交缓冲区长度和内核缓冲区长度,在有漏洞的版本中,这一比较采用了:
1 | if ((Size + TerminatorSize) > sizeof(KernelBuffer)) |
TerminatorSize为4字节,当用户传过来的缓冲区大小为0xfffffffc~0xffffffff时,假发之后结果溢出,并且巧妙地通过了长度检查!
在Powershell中,我们可以清晰地看到这一问题。
我们在Windbg中同样可以看到这一问题:
1 | 97c4ba9f 8b450c mov eax,dword ptr [ebp+0Ch] |
检查完之后,则进入循环,将用户缓冲区的数据拷贝到内核缓冲区。当内核地址不等于缓冲区结束标志0xBAD0B0B0时,拷贝数据。
在拷贝数据前,查看寄存器,当前ebp为0x9398fab0,查看内存,得知当前返回地址为0x9398fab0。
1 | kd> r |
0x02 漏洞利用
利用防方法与之前无二,主要是覆盖函数返回地址。
但是亲自测试过后,感觉函数内存结构与我们所构想的有所区别:
上面为覆盖前内核内存,红色为ebp地址,后面的0x97c5a956为返回地址,可以看到,覆盖后的内存并没有修改到返回地址,那么是怎么利用的呢?这让我很费解。
仔细想了一下,应该是VS编译器的原因,导致堆栈数据之间有保护间隙,所以实际的内存情况与我们所构造的并不一致。整个的利用思路和栈溢出是类似的。
使用HackSys Team发布的Release第二版,测试一哈,可以看到,此时提权利用是可以成功的。
0x03 漏洞反思
尽管利用的过程不太顺利,但是就原理来讲,参照安全版本,我们可以预估数据大小的情况下,如果传入数据较大,有可能向上溢出时,我们采用减法判断,类似的如果可能向下溢出,则我们采用加法判断。
当然了,如果无法判断大小那应该进行更为周密的考虑。
0x04 链接
fuzzsecurity:https://www.fuzzysecurity.com/tutorials/expDev/18.html