首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第44期->技术专题
期刊号: 类型: 关键词:
利用监视点定位导致溢出的代码点

作者:scz <scz@nsfocus.com>
主页:http://www.nsfocus.net
日期:2003-09-03

/*
* For x86/EWindows XP SP1 & VC 7
* cl vulnerable_0.c /nologo /Os /G6 /W3 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /link /RELEASE
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma comment( linker, "/INCREMENTAL:NO"    )
#pragma comment( linker, "/subsystem:console" )

int __cdecl main ( int argc, char * argv[] )
{
    unsigned char buf[8];

    if ( 2 != argc )
    {
        fprintf( stderr, "Usage: %s <any string>\n", argv[0] );
        return( EXIT_FAILURE );
    }
    strcpy( buf, argv[1] );
    printf( "%s\n", buf );
    return( EXIT_SUCCESS );
}  /* end of main */

3) 利用监视点定位导致溢出的代码点

前面讨论了如何尽早中断在vulnerable_0.exe进程空间中,这次介绍如何利用监视点
定位导致溢出的代码点。

在<<SMB系列(11)--TRANSACT2_OPEN处理过程存在远程缓冲区溢出漏洞>>中介绍过GDB
调试技巧,利用watch功能定位导致溢出的代码点。windbg的ba不能在用户级调试中
使用,很奇怪为什么是这样。SoftICE的bpm断点等价于gdb的watch命令。

打开faults on,让EIP等于0x41414141时SoftICE弹出:

Break due to BP 00: BPX #001B:00401289  (ET=4.41 seconds)
:bl
00)   BPX #001B:00401289
:faults on
:g
Break due to UnhandledException NTSTATUS=STATUS_ACCESS_VIOLATION

在当前栈顶(ESP)以低位置搜索特征字节,试图定位ret指令用过的那个栈帧:

:s -a esp&ffff0000 L esp&0000ffff "AAAAAAAAAAAAAAAA"
Pattern found at 0023:0012F948 (0000F948)
Pattern found at 0023:0012FA60 (0000FA60)
0000000002 occurances found
:db 0012F948 L 20
0023:0012F948 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
0023:0012F958 0D 0A 00 00 A8 03 00 00-00 00 00 00 01 00 00 00  ................
:db 0012FA60 L 20
0023:0012FA60 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
0023:0012FA70 0D 0A 02 03 02 03 02 03-02 03 10 02 10 02 10 02  ................
:faults off
:g

注意到这两处结尾都有"\r\n",从源代码可知这两处必不是buf[]所在,像printf()
所用缓冲区。一般没有源代码可供参考,只能试着先在这两外下写监视点,,找出向
此写入"AA..AA"的代码点。重新执行vulnerable_0.exe,中断在总入口点:

:bd 0
:bpmd 0012F948 w if *0012F948==41414141
:bpmd 0012FA60 w if *0012FA60==41414141
:bl
00) * BPX #001B:00401289
01)   BPMD #0023:0012F948 W DR3  IF (*(0x12F948)==0x41414141)
02)   BPMD #0023:0012FA60 W DR2  IF (*(0x12FA60)==0x41414141)

再次提醒,bpm断点随进程空间消失而消失,因此应该尽早中断在vulnerable_0.exe
进程空间中,然后设置bpm断点,而不是其它时刻。g继续执行,其中一个写监视点命
中:

:g
Break due to BP 02: BPMD #0023:0012FA60 W DR2  IF (*(0x12FA60)==0x41414141)
:d 0012FA60 L 20
0023:0012FA60 41 41 41 41 02 03 02 03-02 03 02 03 02 03 02 03  AAAA............
0023:0012FA70 02 03 02 03 02 03 02 03-02 03 10 02 10 02 10 02  ................
:d 0012F948 L 20
0023:0012F948 00 01 00 00 84 FD 12 00-00 01 00 00 84 FC 12 00  ................
0023:0012F958 00 01 00 00 A8 03 00 00-00 00 00 00 01 00 00 00  ................
:

有代码在向0x0012FA60写入"AA..AA",在这段代码附近F10单步跟几步,就发现源串
跟如下代码相关:

001B:00403C11  8B55F8              MOV       EDX,[EBP-08]
001B:00403C14  FF45F8              INC       DWORD PTR [EBP-08]
001B:00403C17  8A12                MOV       DL,[EDX]

:dd ebp-8 L 4
0023:0012FE74 003718BC  C0BDC4AA  0012FEE4  0040217A      ..7.........z!@.
:db 003718BC-20 L 40
0023:0037189C 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0023:003718AC 00 00 00 00 01 02 01 01-00 01 08 00 41 41 41 41  ............AAAA
0023:003718BC 41 41 41 41 41 41 41 41-41 41 41 41 0A 00 00 00  AAAAAAAAAAAA....
0023:003718CC 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

这回发现0x003718B8处也有16个'A',后面还有一个'\n'。再次搜索内存:

:s -a 0 L 7fffffff "AAAAAAAAAAAAAAAA"
Pattern found at 0023:0012FEDC (0012FEDC)
Pattern found at 0023:00142371 (00142371)
Pattern found at 0023:00142FD9 (00142FD9)
Pattern found at 0023:00370B3D (00370B3D)
Pattern found at 0023:003718B8 (003718B8)
0000000005 occurances found

不必搜索0x80000000开始的空间,那是内核空间。

:stack
FrameEBP  RetEIP     Symbol
0012FE7C  0040217A   vulnerable_0!.text+2C11
0012FEE4  41414141   vulnerable_0!.text+117A

查看调用栈回溯时意外发现某个返回地址已经被覆盖成0x41414141,与内存搜索结果
对照,显然我们应该在0x0012FEDC下写监视点:

:be 0
:bc 2
:bpe 1
:BPMD #0023:0012FEDC W DR3  IF (*(0x0012FEDC)==0x41414141)
:bl
00)   BPX #001B:00401289
01)   BPMD #0023:0012FEDC W DR3  IF (*(0x12FEDC)==0x41414141)
:g

不过这次bpm断点已经无效,0x0012FEDC已经被写过了,而且进程空间消失后bpm断点
随之消失。我用bpe命令先设置一次,留在命令缓冲中。下次因bpx中断后,只需用上
键头找出bpm命令重新设置即可,不必输入很长的一串。重新执行vulnerable_0.exe:

Break due to BP 00: BPX #001B:00401289  (ET=14.80 seconds)
:bl
00)   BPX #001B:00401289
:BPMD #0023:0012FEDC W DR3  IF (*(0x0012FEDC)==0x41414141)
:bl
00)   BPX #001B:00401289
01)   BPMD #0023:0012FEDC W DR3  IF (*(0x12FEDC)==0x41414141)
:db 0012FEDC L 20
0023:0012FEDC 00 00 00 00 31 00 00 00-44 9F 59 80 02 00 00 00  ....1...D.Y.....
0023:0012FEEC FF FF FF FF 00 08 00 00-10 8C 18 FD B1 77 4F 80  .............wO.

g继续执行,写监视点命中:

:g
Break due to BP 01: BPMD #0023:0012FEDC W DR3  IF (*(0x12FEDC)==0x41414141)
:db 0012FEDC L 20
0023:0012FEDC 41 41 41 41 41 41 41 00-C0 FF 12 00 F9 13 40 00  AAAAAAA.......@.
0023:0012FEEC 02 00 00 00 20 0B 37 00-58 0B 37 00 94 00 00 00  .... .7.X.7.....
:stack
FrameEBP  RetEIP     Symbol
0012FEE4  004013F9   vulnerable_0!.text+011B
0012FFC0  77E814C7   vulnerable_0!.text+03F9
0012FFF0  00000000   kernel32!_BaseProcessStart+0023

在栈帧0x0012FEE4(EBP)所对应的函数中,有代码导致自己的栈帧被覆盖,这是最典
型的栈溢出。而我们已经找到导致溢出的代码点:

EAX=7EFEFEFE   EBX=7FFDF000   ECX=00370B44   EDX=41414141   ESI=00000A28
EDI=0012FEDF   EBP=0012FEE4   ESP=0012FECC   EIP=0040111B   o d I s Z a P c
CS=001B   DS=0023   SS=0023   ES=0023   FS=0038   GS=0000
─────────────────────────────────PROT32─
001B:0040111B  83C704              ADD       EDI,04
001B:0040111E  BAFFFEFE7E          MOV       EDX,7EFEFEFF
001B:00401123  8B01                MOV       EAX,[ECX]
001B:00401125  03D0                ADD       EDX,EAX
... ...
001B:00401150  EBC7                JMP       00401119
001B:00401152  8917                MOV       [EDI],EDX
(PASSIVE)-KTEB(8106B240)-TID(0164)──vulnerable_0!.text+011B──────

总结一下全过程:

a. 执行问题程序,EIP为0x41414141时SoftICE弹出,在内存中搜索特征字节,记录
   地址,准备下次设置写监视点用。

   用stack命令查看此刻调用栈回溯,获取更多有用信息。

   立即根据PE头计算出程序总入口点,在程序总入口点设置bpx断点。

b. 重新执行问题程序,SoftICE因bpx断点而弹出。根据步骤a记录下来的地址设置写
   监视点。

   g命令继续执行问题程序。

c. SoftICE因写监视点命中而弹出。再次在内存中搜索特征字节,配合stack命令确
   定被覆盖的栈帧以及相应的缓冲区起始地址。

   清空那些无用的写监视点,保持bpx断点。

   g命令结束本次执行。

d. 重新执行问题程序,SoftICE因bpx断点而弹出。根据步骤c记录下来的地址设置写
   监视点。

   g命令继续执行问题程序。

e. SoftICE因写监视点命中而弹出。此刻EIP附近的代码就是我们要找的代码。

这是一个逐步逼近的调试过程。vulnerable_0.c相当简单,因此逼近过程快。如果碰
上没有源代码可供参考的复杂应用程序,就远不是这样轻松了。不过整体抽象思路依
旧。
版权所有,未经许可,不得转载