FreeBuf|图解利用虚函数过GS保护( 二 )


1)类Vir中有个虚函数virfun和成员函数test 。 在成员函数test中 , 将传入的数据payload作为参数 , 并将其赋值到成员变量buf中 , 这里存在典型的溢出漏洞 。
2)在函数test中也调用了虚函数virfun , 因此buf变量发生溢出有可能会影响到虚函数指针 。
3)系统调用虚函数是在检查securitycookie之前 , 因此可以在调用虚函数时 , 拿到程序控制 , 将其指向自己的payload 。
各函数变量地址:为了更好的理解后面的payload构造 , 我们先给出代码中关键变量和虚函数相关地址 。 其中虚表指针地址为0x0018ff34 , 虚表地址为0x41402254 , 虚函数入口地址为0x41401070 , 调用虚函数virfun即call0x41401070 。 原始参数str首地址为0x41402138 , 局部变量buf地址为0x0018fe24 。
FreeBuf|图解利用虚函数过GS保护
文章图片
通过虚函数过GS保护利用思路:主要是通过局部变量溢出 , 覆盖虚表指针值 , 将虚表指针指向我们精心构造的payload , 下面我们就详细说明payload的构造过程 。
3.3payload构造为了精准覆盖虚表指针 , 我们首先需要计算偏移量 , 即虚表指针地址与局部变量buf的距离 , 然后将虚表指针指向的虚表地址0x41402254覆盖成原始参数str的首地址0x41402138 , 即让虚表指针指向原始参数 。
计算偏移量有很多种方法 , 可以直接手算虚表指针地址与局部变量buf的距离为0x0018ff34-0x0018fe24=0x00000110=272字节 。 如果遇到难算的可以利用ImmunityDebugger工具生成字符串 , 然后计算偏移量 。 这里还是演示下做法 。
(1)利用ImmunityDebugger工具生成300字节的字符串
!monapc300
FreeBuf|图解利用虚函数过GS保护
文章图片
(2)打开ImmunityDebugger工具所在目录的pattern.txt文件 , 得到300长度字符串:
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9(3)传入300字符串 , 调试运行 , 报错 , 复制报错地址0x316A4130
FreeBuf|图解利用虚函数过GS保护
文章图片
(4)计算偏移量 , 得到偏移量为272
!monapo0x316A4130或者!monapo0Aj1
FreeBuf|图解利用虚函数过GS保护
文章图片
这时候的payload构成初步如下:
虚函数寻址变成了下图所示 。
FreeBuf|图解利用虚函数过GS保护
文章图片
图中完成了将虚表指针指向原始参数str(0x41402138) , 实现了虚表指针跳到了原始参数上(原先的虚表) , 但是我们知道虚表指针跳到虚表 , 然后继续跳转到虚函数地址处 , 执行虚函数地址处的代码 。 因此下一步我们需要考虑虚函数地址填什么(图中问号???处)?即原始参数str(payload)前四个字节的值 。 这里我们需要考虑两个问题:
1)图中问号处的内容必须是地址(可跳转) , 而不是数据
2)面临着一个call操作 , 即call虚函数地址 , 因此我们要考虑怎么能执行完call后 , 还可以回到shellcode内存空间继续执行呢?这里我们知道存储shellcode内存空间有两块 , 一个是原始参数str处(0x41402138) , 第二个是通过strcpy函数赋值成功的局部变量buf(0x0018fe24) , 这个时候我们需要观察栈和寄存器的状态 , 如下图所示 。