首页
社区
课程
招聘
[原创]既然是软件安全论坛,贴点这种东西不跑题吧——漏洞利用学习笔记之一:栈溢出
发表于: 2007-4-25 18:58 17219

[原创]既然是软件安全论坛,贴点这种东西不跑题吧——漏洞利用学习笔记之一:栈溢出

2007-4-25 18:58
17219

  程序在运行过程中,为了临时存取数据的需要,一般都要分配一些内存空间,
通常称这些空间为缓冲区。如果向缓冲区中写入超过其本身长度的数据,以致于缓
冲区无法容纳,就会造成缓冲区以外的存储单元被改写,这种现象就称为缓冲区溢
出。下面要谈到的栈溢出就是缓冲区溢出的一种。

  由于缓冲区溢出而使得有用的存储单元被改写,往往会引发不可预料的后果。
向这些单元写入任意的数据,一般只会导致程序崩溃之类的事故,对这种情况我们
也至多说这个程序有bug。但如果向这些单元写入的是精心准备好的数据,就可能
使得程序流程被劫持,致使不希望的代码被执行,落入攻击者的掌控之中,这就不
仅仅是bug,而是漏洞(exploit)了。

  说到这里,应该注意到这样一个事实:当前应用最广的Intel x86体系构架的
CPU,对于指令和数据并没有区分,而是cs:eip指向什么它就执行什么。换言之,
我们只要能操纵eip,让它指向我们所期望的代码,CPU也就乖乖地听话照办了。

  不过,操纵eip毕竟不是那么容易。可以改写8个通用寄存器的那些指令如mov、
lea、pop、add/sub等等,到了eip身上统统行不通。修改eip只能通过很有限的几
条专属指令。这也难怪,eip始终代表着CPU的前进方向,如果eip可以象通用寄存
器那样随意操作,CPU也就只好象只没头苍蝇到处乱撞,到时候不要说CPU自己,恐
怕连程序员都无法预测它下一步要干什么了。

  然而不能随意操作不意味着不能操纵。在修改eip的指令中,call/ret是很有
名堂的一对。call把当前eip——或者叫返回地址——保存在栈上,到了子程序执
行完了再由ret把这个值弹回eip。栈是什么?栈是一片可读可写的存储区域。既然
可写,那就意味着可以暗地里修改这个返回地址。(这么重要的东西竟然放在一个
可以随便进行写操作的地方!这算不算CPU本身的机制缺陷?)

  光是这一点,call/ret还够不上称为“很有名堂”,得综合另外一方面的因素
进行考虑。在高级语言的实现中,子程序里如果用到变量——即所谓局部变量,这
些变量的存储空间是从栈上分配的,具体表现形式就是通过减少栈指针esp的值来
留出这些空间。又是跟栈有关!你有没有联想到什么呢?

  一方面是修改栈上的返回地址,另一方面是在栈上分配缓冲区。再联想到前面
所谈到的缓冲区溢出。如果在栈上造成溢出……

  哼哼,聪明的你,总算猜对了!

  作为一个具体的例子,我们来看下面的程序:

;===============栈溢出利用的例子,由MASM编写===============
                  .386
                  .model      flat, stdcall
                  option      casemap: none
                  
                  include     windows.inc
                  include     kernel32.inc
                  include     user32.inc
                  includelib  kernel32.lib
                  includelib  user32.lib
                  
                  .data?

hKeyFile          dd          ?
dwBytesRead       dd          ?

                  .const

szKeyFileName     db          'thekey.nk',0
szMessCap         db          'message',0
szBadboy          db          'The program will continue in trial mode.', 0
szGoodboy         db          'Thanks for registering. The program is unlocked now.', 0
                 
                  .code

_HomeProc         proc
                  local       loc_Buff[8]:byte                   ;分配8字节缓冲区,作溢出用
                  
                  invoke      CreateFile, offset szKeyFileName, GENERIC_READ, FILE_SHARE_READ, \
                                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL
                  cmp         eax, INVALID_HANDLE_VALUE
                  jne         @F
                  ret
                  
              @@:
                  mov         hKeyFile, eax
                  invoke      ReadFile, hKeyFile, addr loc_Buff, 16, offset dwBytesRead, NULL  ;此处读入16字节
                  invoke      CloseHandle, hKeyFile
                  ret

_HomeProc         endp

_HijackedProc     proc
       
                  invoke      MessageBox, NULL, offset szGoodboy, offset szMessCap, MB_ICONINFORMATION
                  invoke      ExitProcess, NULL
                  ret

_HijackedProc     endp

START:
                  
                  call        _HomeProc
                  invoke      MessageBox, NULL, offset szBadboy, offset szMessCap, MB_ICONWARNING
                  ret
                  
                  end         START
;===============栈溢出利用的例子,由MASM编写===============

乍一看,这个程序一开始只是调用一个子过程_HomeProc,接着就弹出一个消息框
显示szBadboy的内容。再一看_HomeProc这个过程,只是打开一个叫做"thekey.nk"
的文件,并读入一些字节,似乎也没有什么特别之处。

  另一方面,整个程序中虽然有一处MessageBox调用显示szGoodboy的内容,但
这个地方在一个_HijackedProc的子程序中,而根据主程序的流程来看,并没有任
何地方调用这个_HijackedProc,于是szGoodboy的内容似乎无法显示出来,你只能
永远做个Bad Boy。果真如此吗?

  实际上,妙就妙在_HomeProc当中。这段程序经过masm预处理后,会变成下面
的样子:

;==========================================================
START:          call    _HomeProc
                ....

_HomeProc:      push    ebp
                mov     ebp, esp
                add     esp, -8
                ....
;==========================================================

其中用add esp, -8留出8字节缓冲区loc_Buff,执行完该句后,栈的情形如下图所
示。


loc_Buff只分配了8个字节的空间,但是后来却从thekey.nk文件中读出16个字节放
到以它为起始地址的内存空间,放不下多出来的那8个字节跑到哪里了呢?显然,
这8个字节数据将会覆盖所保存的ebp值(图中绿色部分)和返回地址(图中黄色部
分)。

  因此,我们只要控制thekey.nk中覆盖返回地址的那4个字节的内容,就达到了
修改返回地址的目的。等_HomeProc执行到末尾时,ret指令不会发现这个返回地址
被动了手脚,仍然忠实地把它弹出到eip中,我们就到了想去的地方了!

  刚才不是还为szGoodboy无法显示而叹息吗,我们现在就来把这个返回地址修
改成_HijackedProc的入口地址,相当于间接调用这个过程。_HijackedProc的入口
地址可以通过反汇编而得到,在笔者机器上,这个地址是0x401053。这也就是说,
构造一个thekey.nk文件,它的前12字节任意,但第13到16字节依次为53 10 40 00
(别忘了Intel x86遵循的是“高高低低”原则),然后把它放到与原程序同一目
录下。好了,现在来看运行结果:

就这样,漏洞利用宣告成功!

  谢谢观赏,敬请关注下一节:漏洞利用之格式化字符串


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (48)
雪    币: 2943
活跃值: (1788)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
2
好文,顶一下
2007-4-25 19:23
0
雪    币: 110
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
强,支持一下再看
2007-4-25 19:45
0
雪    币: 200
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
强人,学习中,等待下一篇
2007-4-25 22:25
0
雪    币: 433
活跃值: (176)
能力值: ( LV13,RANK:1250 )
在线值:
发帖
回帖
粉丝
5
感谢斑竹加精,感谢各位支持!
2007-4-25 23:04
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
6
crackme那里就有一个是溢出的,我正想多了解些呢
2007-4-26 00:25
0
雪    币: 297
活跃值: (21)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
7
说的浅显易懂,好东东!!
2007-4-26 08:15
0
雪    币: 12
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
所以现在 Vista 无法执行 栈 中的代码
2007-4-26 10:41
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
好文章 顶!
2007-4-26 10:49
0
雪    币: 29243
活跃值: (7764)
能力值: ( LV15,RANK:3306 )
在线值:
发帖
回帖
粉丝
10
强,期待下一节~
2007-4-26 13:38
0
雪    币: 208
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
好强,顺便也把堆溢出讲一下吧!
2007-4-26 14:21
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lcy
12
晕死了,vista如法支持了!!!
2007-4-26 14:51
0
雪    币: 242
活跃值: (163)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
13
好,学习了!
2007-4-26 15:34
0
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
写得很好啊 我支持你!
2007-4-26 23:37
0
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
强烈期待你的 漏洞利用之格式化字符串
严重要顶你!!
2007-4-26 23:43
0
雪    币: 200
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
写的浅显易懂,期待后续文章!
2007-4-27 11:05
0
雪    币: 217
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
好文章,学习,期待继续。
2007-4-27 11:09
0
雪    币: 690
活跃值: (1826)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
18
学习+支持。
2007-4-27 11:17
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
很好的文章,顶下楼主。只是vista中栈溢出已经有些问题,堆溢出利用更值得期待!
相对而言,堆溢出复杂,但是其利用更加巧妙
2007-4-27 13:13
0
雪    币: 193
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
汗,牛人牛贴,慢慢消化!
2007-4-27 16:29
0
雪    币: 79
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
我也期待呢,看看很有帮助,谢谢楼主了!!
2007-4-27 16:33
0
雪    币: 213
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
22
楼主强。好文。
2007-4-27 17:54
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
不错的好东西啊
2007-4-27 19:05
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
强人,学习中,等待下一篇
2007-4-29 09:22
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
好文章 通俗易懂 强
2007-5-1 17:23
0
游客
登录 | 注册 方可回帖
返回
//