一、缓冲区溢出攻击原理
缓冲区溢出攻击是利用 缓冲区溢出漏洞 所进行的攻击行动。 缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛 存在 。 利用缓冲区溢出攻击,可以导致程序 运行 失败、系统关机、重新启动等后果。 缓冲区 溢出是指当 计算机 向缓冲区内填充数据位数时超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上。 理想的情况是:程序会检查数据长度,而且并不允许输入超过缓冲区长度的字符。 但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患。 操作系统所使用的缓冲区,又被称为“ 堆栈 ”,在各个操作进程之间,指令会被临时储存在“堆栈”当中,“堆栈”也会出现 缓冲区溢出 。 可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。
当某个函数运行时,机器需要分配一定的内存去进行函数内的各种操作,这个过程中分配的那部分栈称为栈帧。栈帧是一段有界限的内存区间,由最顶端的两个指针界定,寄存器EBP为帧指针,而寄存器ESP为栈指针。当程序执行时,栈指针(栈顶)可以移动,因此大多数信息的访问都是相对于桢指针的。
二、实验内容
1.根据源代码,完成变量覆盖,实现攻击并取得“Access granted.”
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int checkPass(const char* strPass)
{
int flag = 0;
char passwd_buff[16];
strcpy(passwd_buff, strPass);
if( strcmp(passwd_buff, "sysadmin123") == 0 )
{
flag = 1;
}
return flag;
}
int main(int argc, char* argv[])
{
if( argc < 2 ){
printf("Usage: %s <passwd> \n", argv[0]);
return 1;
}
int isUserOK = checkPass(argv[1]);
if( isUserOK ){
printf("Access granted.\n");
}else{
printf("Wrong password.\n");
}
return 0;
}
画出栈帧的图,并标出相应的地址。
攻击成功的方法,及截图
2.根据源代码,实现返回地址覆盖,并弹出显示信息的对话框; 要求弹出自己的信息等。:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
int readFromFile(char* filename, char* buff, int len)
{
FILE *file;
for(int i=0;i<len;i++) buff[i] = '\0'; //init
/*1. ´ò¿ªÎļþ*/
file=fopen(filename,"rb"); //malloc
if(file==NULL)
{
printf("File open error!\n");
return -1;
}
/*2. ¶ÁÈ뻺³åÇø*/
fread(buff,1,len,file);
/*3. ¹Ø±ÕÎļþ*/
fclose(file); //free
return 1;
}
int hello()
{
return return MessageBox(0,"缓冲区溢出示例",0x21);
}
int checkPass(const char* strPass)
{
int flag = 0;
char passwd_buff[16];
strcpy(passwd_buff, strPass);
if( strcmp(passwd_buff, "sysadmin123") == 0 )
{
flag = 1;
}
return flag;
}
int main(int argc, char* argv[])
{
char buff[80+1];
printf("Address of hello(): 0x%0X \n", hello);
if( argc < 2 ){
printf("Usage: %s <passwd-file> \n", argv[0]);
return 1;
}
readFromFile(argv[0], buff,80);
int isUserOK = checkPass(buff);
if( isUserOK ){
printf("Access granted.\n");
}else{
printf("Wrong password.\n");
}
return 0;
}
画出栈帧图,并标出相应地址
攻击成功的方法,并截图。
3.完成linux下的缓冲区攻击实验,完成变量覆盖和返回地址覆盖并取得shell
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int pwn()
{
return system("/bin/sh");
}
int checkPass(const char* strPass)
{
int flag = 0;
char passwd_buff[8];
//int flag = 0; //is false;
strcpy(passwd_buff, strPass);
if( strcmp(passwd_buff, "sysadmin123") == 0 )
{
flag = 1;
}
return flag;
}
int main(int argc, char* argv[])
{
printf("Address of pwn: %p \n", pwn);
if( argc < 2 ){
printf("Usage: %s <password> \n", argv[0]);
return 1;
}
int isUserOK = checkPass(argv[1]);
if( isUserOK ){
printf("Access granted.\n");
}else{
printf("Wrong password.\n");
}
return 0;
}
画出栈帧图,并标出相应地址
攻击成功的方法,并截图。
三、总结
1.缓冲区溢出的概念
计算机程序一般都会使用到一些内存,这些内存或是程序内部使用,或是存放用户的输入数据,这样的内存一般称作缓冲区。溢出是指盛放的东西超出容器容量而溢出来了,在计算机程序中,就是数据使用到了被分配内存空间之外的内存空间。而缓冲区溢出,简单的说就是计算机对接收的输入数据没有进行有效的检测(理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符),向缓冲区内填充数据时超过了缓冲区本身的容量,而导致数据溢出到被分配空间之外的内存空间,使得溢出的数据覆盖了其他内存空间的数据。
2.BOF的两种覆盖方式分别是什么
EBP,EIP
3.被调用函数栈帧的情况
函数调用操作包括从一块代码到另一块代码之间的双向数据传递和执行控制转移。数据传递通过函数参数和返回值来进行。另外,我们还需要在进入函数时为函数的局部变量分配存储空间,并且在退出函数时收回这部分空间。Intel 80x86 CPU为控制传递提供了简单的指令,而数据的传递和局部变量存储空间的分配与回收则通过栈操作来实现。