缓冲区溢出

缓冲区溢出和Shellcode

所属课程 网络攻防实践
课程要求 第八周作业

1. 实践内容

1.1 软件安全概述

  • 安全漏洞的基本元素:系统的脆弱性,对缺陷的可访问性,对缺陷的可利用性。
  • 软件安全困境三要素:复杂性,可扩展性,连通性。
  • 软件安全漏洞技术分类:
    1. 内存安全违规类 :不安全指针等。
    2. 输入验证类 :SQL注入,格式化字符串等。
    3. 竞争条件类 :进程间通信的同异步问题?
    4. 权限混淆与提升类 :越狱,FTP反弹攻击等。

1.2 缓冲区溢出基础概念

  • 缓冲区溢出基本概念 :内存安全违规类错误;C/C++程序在访问内存时未进行边界检查,可能导致缓冲区溢出,从而修改或覆盖相邻存储的关键指令,使得一些恶意指令攻击得以执行。
  • 缓冲区溢出攻击背景知识 :
    1. gcc编译。
    2. gdb调试。
    3. 汇编语言基础:
      • 寄存器:通用寄存器(eax 累加, ebx栈底指针, ecx 计数, edx除法)、段寄存器(存储段基址)、控制寄存器(指令指针寄存器,程序计数器?)和其他寄存器(扩展标志寄存器) 。
      • 基础汇编指令:PUSH,,POP,JMP(mov eip addr),CALL,LEAVE,RET(pop eip)。
    4. 进程内存管理:linux下将执行程序加载到新创建的内存空间中,程序一般包含 .text, .bss ,.data 三种段,前者包含程序指令,在内存中映射为只读,后两者包含未初始化的数据和初始化的静态数据,被映射为可写。加载完成后,初始化程序的参数栈和数据堆,其中栈的栈底为环境变量,运行参数及参数数量,然后是主函数及调用的临时信息;堆存储动态分配的数据。
    5. 函数调用:
      • 调用:将函数调用参数,函数调用下一条指令返回地址压栈,并跳转至被调函数入口地址。
      • 序言:被调函数将调用函数的栈基址进行压栈保存,并创建自身函数栈结构。
      • 返回:在被调函数执行玩指令后将指令控制权返回给调用者之前,恢复调用者的栈顶与栈底指针(ebp,esp),并将之前压栈的返回地址装在至指令寄存器eip中执行。
  • 缓冲区溢出攻击原理:
    1. 栈溢出,堆溢出,内核溢出。
    2. 取消linux系统对抗缓冲区溢出(缓冲区溢出实验):
      • 取消“栈上数据不可执行”保护。
      • 取消”地址空间随机化“保护。
      • 编译时取消‘’/GS‘’保护。
    3. 溢出攻击以获取权限的三个挑战:
      • 找出缓冲区溢出要覆盖和修改的敏感位置。
      • 将敏感位置修改为何值。
      • 攻击指令代码(payload,shellcode)。

1.3 Linux平台上的栈溢出与Shellcode

  • linux栈溢出攻击的三种模式:
    1. NSR:适用于被溢出的缓冲区变量比较大,足以容纳Shellcode的情况 。数据构造方式为从低地址到高地址分别是Nop+shellcode+覆盖返回地址的期望返回地址。
    2. RNS:一般用于被溢出的变量比较小,不足于容纳Shellcode的情况。 数据构造方式为从低地址到高地址分别是覆盖到RET返回的地址的跳转地址+Nop填充出着陆区+shellcode。
    3. RS:这种模式能精确定位出shellcode在目标漏洞程序进程空间中的起始地址,所以无需引入Nop指令填充出着陆区。将shellcode放置在漏洞程序执行的环境变量中,也就是在栈底,因而位置是固定的,返回位置为ret=0xc0000000-sizeof(void*)-sizeof(FILENAME)-sizeof(shellcode)。
    4. 前两种模式适合远程栈溢出,RS只能用于本地缓冲区溢出攻击。
  • shellcode实现技术(通常是溢出后通过调用execve()函数启动/bin/sh提供命令行):
    1. 使用高级语言(C)编写shellcode。
    2. 编译并反汇编调试该程序。
    3. 从汇编代码级别分析程序执行流程。
    4. 将获取的汇编代码嵌入C中进行测试。
    5. 提取汇编代码所对应的opcode二进制指令,创建shellcode数组。

1.4 windows上的栈溢出和shellcode

  • windows相对linux在栈溢出攻击上的差异:
    1. windows会对废弃栈进行随机数插入处理,而linux不做任何处理,故以linux栈溢出攻击方式攻击windows会有一定限制,导致溢出位置shellcode指令失效。
    2. 进程内存空间分布不同,导致linux下RNS模式攻击不可用。
    3. windows系统功能调用通过系统API及内核处理例程调用,而linux通过“int80”中断处理。
  • windows上栈溢出攻击通过系统核心DLL中的“JMP ESP”指令完成流程跳转,将溢出返回地址改写为只想“JMP ESP"的高位地址,并同时是ESP寄存器指向Nop和shellcode的位置。
  • windows shellcode实现
    1. shellcode需要找到所需的API函数(system(),exit()),生成函数调用表。
    2. 获得函数的内存加载地址。
    3. 确保推出。
  • windows远程shellcode
    1. 创建一个服务器端socket,并在指定的端口上监听 。
    2. 通过accept()接受客户端的网络连接 。
    3. 创建子进程,运行“cmd.exe”,启动命令行 。
    4. 创建两个管道,命令管道将服务器端socket接收(rccv)到的客户端通过网络输入的执行命令,连接至cmd.exe的标准输入;然后输出管道将cmd.exe的标准输出连接至服务器端socket的发送(send),通过网络将运行结果反馈给客户端 。

1.5 堆溢出攻击

  • 堆中并没有可以直接覆盖并修改指令寄存器指针的返回地址,故堆溢出更难。需要借助函数指针、C++类对象中的虚函数表等关键变量挖掘漏洞。
  • 指针改写:将函数指针指向shellcode入口地址(需要溢出的缓冲区临近全局函数指针存储地址,且在其低地址方向 )。
  • C++类对象虚函数表改写。
  • glibc库free()函数漏洞 。

1.6 缓冲区溢出攻击的防御

  • 代码漏洞查错(fuzz注入测试)。
  • 在编译器上引入边界检查。
  • 设置允许溢出但不执行保护。
  • 设置堆栈不可执行(一些堆栈上)保护。

2. 实践过程

3. 学习问题及解决

  1. gdb调试命令不太清楚。解决:慢慢实践。

4. 实践总结

参考

posted @ 2020-05-06 13:52  chlei233  阅读(662)  评论(0编辑  收藏  举报