ODAY-软件漏洞分析

ODAY-软件漏洞分析

一、基础知识

定义

  1. BUG:功能性逻辑缺陷
  2. 漏洞:安全性逻辑缺陷(软件中缓冲区溢出漏洞、网站中跨站脚本xss漏洞、SQL注入漏洞等)
  3. 0day响应:
    1. CVE
    2. CERT
    3. 微软安全中心”Black Tuesday“:每个月第二周星期二发布补丁
  4. PE文件格式:Win32平台下可执行文件遵守的数据格式(“*.exe” / “*.dll”等)
    1. .text:由编译器产生,存放二进制的机器码,是反汇编和调试的对象
    2. .data:初始化的数据块(如:宏定义、全局变量、静态变量等)
    3. .idata:可执行文件所使用的动态链接库等外来函数与文件的信息
    4. .rsrc:存放程序的资源(如图标、菜单等)
    5. .reloc 、.edata 、.tls 、.rdata
  5. “虚拟内存”(非操作系统中的虚拟内存):在用户模式下,用调试器看到的内存地址 [指Windows用户态内存隐射机制下的虚拟内存]
  6. PE文件与虚拟内存的映射:VA = ImageBase + RVA
    1. 文件偏移地址(File Offset)
    2. 装载基址(Image Base)
    3. 虚拟内存地址(Virtual Address,VA)
    4. 相对虚拟地址(Relative Virtual Address,RVA)

逆向分析工具

  1. OllyDbg

  2. SoftICE

  3. WinDbg

  4. IDE Pro

  5. 二进制编辑器(Ultra Edit、Hex Workshop、WinHex)

  6. 虚拟机

  7. Crack二进制文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //密码验证实验程序
    #include <stdio.h>
    int verify_password(char *password)
    {
    int authenticated;
    authenticated=strcmp(password,PASSWORD);
    return authenticated;
    }
    main()
    {
    int valid_flag = 0;
    }

二、漏洞利用

栈溢出利用

1. 系统栈

  1. 进程使用的内存区域按功能划分

    1. 代码区:cpu在此区域取值执行
    2. 数据区:存储全局变量等
    3. 堆区:动态分配和回收。进程在堆区请求一定大小的内存
    4. 栈区:用于动态地存储函数间的调用关系,保证被调用函数在返回时恢复到母函数继续执行。
  2. Win32系统提供了两个特殊寄存器用于标识位于系统栈栈顶的栈帧

    1. ESP(栈指针寄存器):存放一个永远指向系统栈最上面一个栈帧的顶部
    2. EBP(基址指针寄存器):存放一个永远指向系统栈最上面一个栈帧的底部
    3. 当前函数栈帧:ESP和EBP之间的内存空间
      1. 局部变量:为函数局部变量开辟内存空间
      2. 栈帧状态值:保存前栈帧的顶部和底部,用于本栈帧弹出后恢复上一个栈帧(实际只保存底部,顶部可以通过堆栈平衡计算得出)
      3. 函数返回地址:保存当前函数调用前的断点信息,也就是函数调用前的指令位置
    4. 另外的特殊寄存器:EIP(指令寄存器)存放下一条等待执行的指令地址
  3. 不同编译器调用方式差异

C SysCall StdCall BASIC FORTRAN PASCAL
参数入栈顺序 右->左 右->左 右->左 左->右 左->右 左->右
恢复栈平衡操作的位置 母函数 子函数 子函数 子函数 子函数 子函数
  1. 函数调用大致步骤:

    1. 参数入栈:按入栈顺序
    2. 返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈,供函数返回时继续执行
    3. 代码区跳转:处理器从当前代码区跳转到被调用函数的入口
    4. 栈帧调整:
      1. EBP入栈:保存当前栈帧状态值,以供后面恢复本栈帧时使用
      2. ESP装入EBP,更新栈帧底部:将当前栈帧切换到新栈帧
      3. 把ESP减去所需空间的大小,太高栈顶:给新栈帧分配空间
    1
    2
    3
    4
    5
    6
    7
    8
    ;假设函数有三个参数,依次入栈
    push canshu1
    push canshu2
    push canshu3
    call 函数地址 ;call完成两项工作:a.保存返回地址(入栈当前指令在内存中的位置) b. 跳转到函数的入口地址
    push ebp ;保存旧栈的栈底
    mov ebp ,esp ;栈帧切换:新栈帧底替换旧栈底
    sub esp ,xxx ;太高栈顶,为新栈帧开辟内存空间:设置新栈帧的栈顶
  2. 函数返回大致步骤:

    1. 保存返回值:通常保存在寄存器EAX
    2. 弹出当前栈帧,恢复上一个栈帧
      1. 在堆栈平衡的基础上,给ESP加上栈帧的大小,降低栈顶,回收空间
      2. 将(当前栈帧底部保存的)前栈帧EBP值 弹入 EBP寄存器,恢复出上一个栈帧
      3. 将函数返回地址弹给EIP寄存器
    3. 跳转:按照返回地址跳回母函数继续执行
    1
    2
    3
    add esp ,xxx    ;降低栈顶,回收当前栈帧
    pop ebp ;将上一个栈帧底部位置恢复到ebp
    retn ;两个功能:a. 弹出当前栈顶元素(栈帧中的返回地址) b.处理器跳转到弹出的返回地址,恢复调用之前的代码区

+. 扩充汇编知识书籍:《IBM X86汇编》或《Win32汇编》

2. 修改邻接变量

3. 修改函数返回地址

4. 代码植入

开发shellcode

MetaSploit开发Exploit

堆溢出利用

Windows异常处理机制

高级内存攻击技术

手机里的缓冲区溢出

其他软件漏洞利用技术

Windows安全机制

GS

SafeSEH

DEP

ASLR

SEHOP

堆保护与攻击

三、漏洞挖掘

四、漏洞分析