20199128 2019-2020-2 《网络攻防实践》第十周作业

20199128 2019-2020-2 《网络攻防实践》第十周作业

这个作业属于哪个课程 《网络攻防实践》
这个作业的要求在哪里 《网络攻防实践》第十周作业
这个作业在哪个具体方面帮助我实现目标 学习缓冲区溢出相关知识
作业正文.... 见正文
其他参考文献 见参考文献

1.实践内容

1.1软件安全概述

  • 安全漏洞的基本要件:系统的脆弱性或缺陷、攻击者对缺陷的可访问性,以及攻击者对缺陷的可利用性
  • 软件安全漏洞:在软件的需求规范、开发阶段和配置过程中引入的缺陷实例,其执行会违反安全策略
  • 软件安全“困境三要素”:复杂性、可扩展性和连通性
  • 软件安全漏洞类型TOP10:
    1. 注入
    2. 失效的身份认证
    3. 敏感信息泄露
    4. XML外部实体(XXE)
    5. 失效的访问控制
    6. 安全配置错误
    7. 跨站脚本(XSS)
    8. 不安全的反序列化
    9. 使用含有已知漏洞的组件
    10. 不足的日志记录和监控

1.2缓冲区溢出基础概念

  • 缓冲区溢出是计算机程序中存在的一类内存安全违规类漏洞,在计算机程序向特定缓 冲区内填充数据时,超出了缓冲区本身的容量,导致外溢数据覆盖了相邻内存空间的合法数据,从而改变程序执行流程破坏系统运行完整性。
  • 寄存器功能介绍
寄存器名 说明 功能
eax 累加器 加法乗法指令的缺省寄存器,函数返回值
ecx 计数器 REP&LOOP指令的内定计数器
edx 除法寄存器 存放整数除法产生的余数
ebx 基址寄存器 在内存寻址时存放基地址
esp 栈顶指针寄存器 SS:ESP当前堆栈的栈项指针
ebp 栈底指针寄存器 SS:EBP当前堆栈的栈底指针
esi,dei 源、目标索引寄存器 在字符串操作指令中,DS:ESI指向源串,ES:EDI指向目标串
eip 指令寄存器 CS:EIP指向下一条指令的地址
eflags 标志寄存器 标志寄存器
cs 代码段寄存器 当前执行的代码段
ss 堆栈段寄存器 stack segment,当前堆栈段
ds 数据段寄存器 data segment,当前数据段
  • 进程内存管理:程序在执行时,系统在内存中会为程序创建一个虚拟的内存地址空间,在32位机上即4GB的空间大小,用于映射物理内存,并保存程序的指令和数据;3GB 以下为用户态空间,3GB-4GB为内核态空间;操作系统将可执行程序加载到新创建的内存空间中,程序一般包含.text, .bss和.data三种类型的段,.text段包含程序指令,在内存中被映射为只读,.data段土要包含静态初始化的数据,而.bss段则主要包含未经初始化的数据,两者都被映射至可写的内存空间中;加载完成后,系统紧接若就开始为程序初始化“栈”和“堆”,Linux程序运行的环境变量env、运行参数argv、 运行参数数argc都被放置在“栈”底,然后是主函数及调用“栈”中各个函数的临时保存信息。“堆”则用于保存程序动态分配的数据和变量;然而程序并不能正确地区分指令和数据,所以当我们通过修改内存空间中影响程序执行逻衍的敏感位置,并将恶意数据作为指令提交给处理器时,它仍会很高兴地执行这些“指令”,正是冯-诺伊曼体系的本质缺陷和软件中存在的安全漏洞,才使得破解目标程序控制其执行流程成为可能。
  • 函数调用过程:
    1. 调用:调用者将函数调用参数、函数调用下一条指令的返回地址压栈,并跳转至被调用函数入口地址。
    2. 序言:被调用函数开始执行首先会进入序言阶段,将对调用函数的栈基址进行压栈保存,并创建自身函数的栈结构,具体包括将ebp寄存器赋值为当前栈基址,为本地函数局部变量分配栈地址空间,更新esp 寄存器为当前栈顶指针等。
    3. 返回: 被调用函数执行完功能将指令控制权返回给调用者之前,会进行返回阶段的操作,通常执行leave和ret指令,即恢复调用者的栈顶与栈底指针,并将之前压栈的返回地址装载至指令寄存器eip中,继续执行调用者在函数调用之后的下一条指令。
  • 栈溢出:栈溢出是指存储在栈上的一些缓冲区变量由于存在缺乏边界保护问题,能够被溢出并修改栈上的敏感信息(通常是返回地址),从而导致程序流程的改变。
  • 堆溢出:堆溢出则是存储在堆上的缓冲区变量缺乏边界保护所遭受溢岀攻击的安全问题。
  • 内核溢出:内核溢出漏洞存在于一些内核模块或程序中,是由于进程内存空间内核态中存储的缓冲区变量被溢出造成的。
  • 取消linux系统对缓冲区溢出的防范措施
    1. 取消“栈上数据不可执行”保护:echo 0 >/proc/sys/kernel/exec-shield。
    2. 取消“地址空间随机化”保护:echo 0 > /proc/sys/kernel/randomize_va_space。
    3. 编译时取消“/GS”保护:加上gcc编译选项-fno-stack-protecto。

1.3Linux平台上的栈溢出与Shellcode

  • NSR模式:主要适用于被溢出的缓冲区变量比较大,足以容纳Shellcode的情况,其攻击数据从低地址到高地址的构造方式是一堆Nop指令(即空操作指令)之后填Shellcode, 再加上一些期望覆盖RET返回地址的跳转地址,从而构成NSR攻击数据缓冲区。
  • RNS模式:一般用于被溢出的变量比较小,不足以容纳Shellcode的情况。攻击数据从低地址到高地址的构造方式是首先填充一些期望覆盖RET返回地址的跳转地址,然后是一堆Nop指令填充出“着陆区”,最后再是 Shellcode。
  • RS模式:这种模式下可以精确地定位出Shellcode在目标漏洞程序进程空间中的起始地址,因此也就无须引入Nop空指令构建“着陆冈”。这种模式是将Shellcode放置在目标漏洞程序执行时的环境变量中,由于环境变量是位于Linux进程空间的栈底位置,因而不会受到各种变量内存分配与对齐因素的影响,其位置是固定的,公式如下:
    ret = 0xc0000000-sizeof(void *)-sizeof(FILENAME)-sizeof(Shellcode)
  • 本地Shellcode的产生过程
    1. 先用高级编程语言,通常用C,来编写Shellcode程序;
    2. 编译并反汇编调试这个Shellcode程序:
    3. 从汇编语言代码级别分析程序执行流程;
    4. 整理生成的汇编代码,尽量减小它的体积并使它可注入,并可通过嵌入C语言进行运行测试和调试;
    5. 提取汇编代码所对应的opcode二进制指令,创建Shellcode指令数组。

1.4Windows平台上的栈溢出与Shellcode

  • Windows平台与Linux平台实现机制(与栈溢出相关)差异:
    1. 对程序运行过程中废弃栈的处理方式差异:Windows平台会向废弃栈中写入一些随机的数据,而Linux则不进行任何的处理。这使得在Windows平台中构建攻击緩冲区数 据在栈中植入恶意指令时,会面临一些限制。
    2. 进程内存空间的布局差异:Linux进程内存空间中一般栈中变量所在地址中没有空字节。Windows平台的栈位置所在内存地址的首字节均为0x00空字节。这使得我们在RNS模式下攻击数据“R”的位置上就存在空字节,这样的攻击数据在漏洞程序中的一些字符串拷贝和操作函数中将被截断,丢弃掉空字节之后的nop和 Shellcode,致使无法成功地进行溢出攻击。 Windows平台上也没有Linux平台上通过SU1D/SGID程序能够提升当前用户执行权限的机制,所以RS模式也不适用。
    3. 系统功能调用的实现方式差异:Linux系统中通过“int 80”中断处理来调用系统功能,而Windows系统则是通过操作系统中更为复杂的API及内核处理例程调用链来完成系统功能调用。
  • Windows本地Shellcode:同样也是启动一个命令行Shell即“command.com”或“cmd.exe”
  • Windows远程Shellcode实现过程
    1. 创建一个服务器端socket,并在指定的端口上监听:
    2. 通过accept()接受客户端的网络连接;
    3. 创建子进程,运行“cmd.exe”,启动命令行;
    4. 创建两个管道,命令管道将服务器端socket接收(rccv)到的客户端通过网络输 入的执行命令,连接至cmd.exe的标准输入;然后输出管道将cmd.exe的标准输出连接至服务器端socket的发送(send),通过网络将运行结果反馈给客户端。

1.5堆溢出攻击

  • 更难的堆溢出:堆中并没有可以直接覆盖并修改指令寄存器指针的返回地址,因此往往需要利用在堆中一些会影响程序执行流程的关键变量,如函数指针、C++类对象中的虚函数表,或挖掘岀堆中进行数据操作时可能存在的向指定内存地址改写内容的漏洞机会。
  • 函数指针改写:如果需要被溢出的缓冲区临近全局函数指针存储地址,且在其低地址方向。那么当向缓冲区填充数据时,如果没有边界判断和控制的话,那么缓冲区溢出之后就会自然地覆盖函数指针所在的内存区,从而改写函数指针的指向地址。而攻击者只需将指针指向hellcode入口地址。
  • C++类对象虚函数表改写:使用虚函数机制的C++类的类成员变量中存在可被溢出的缓冲区,那么可以通过覆盖类对象的虚函数指针,使其指向一个特殊构造的虚函数表,从而执行注入指令。
  • Linux下堆管理glibc库free()函数本身漏洞:Linux操作系统中的堆管理是通过glibc库实现的,使用的内存管理算法被称为dlmalloc,使用了被称为Bin的双向循环链表来存储内存空闲块信息。glibc库中的free()函数提供了将4字节值写入任意内存地址的机会。free()函数在处理内存块回收时,需要将己被释放的空闲块和与之相邻的空闲块进行合并,因此将会把符合条件的空闲块从Bin链表中unlink摘出来,合并之后再将新的空闲块插回链表中。攻击者可以利用此特性构造空闲块,达成覆盖。

1.6缓冲区溢出攻击的防御技术

  • 尝试杜绝溢出的防御技术:根本方法编写正确的、不存在缓冲区溢出安全漏洞的软件代码。依靠fault injection等查错程序、Fuzz注入测试寻找漏洞、在编译器上引入针对缓冲区的边界保护检查机制。
  • 允许溢出但不让程序改变执行流程的防御技术:Canary、SafeSEH技术等。
  • 无法让攻击代码执行的防御技术:通过堆栈不可执行限制来防御。

2.实践过程

3.学习中遇到的问题及解决

  • 问题1:汇编的内容忘了不少
  • 问题1解决方案:查缺补漏

4.实践总结

假期快乐

参考资料

posted @ 2020-05-05 16:16  limbo3c  阅读(203)  评论(0编辑  收藏  举报