zoukankan      html  css  js  c++  java
  • 20199322 2019-2020-2 《网络攻防实践》第十周作业

    一些问题 简单的解答
    这个作业属于哪个课程 网络攻防实践
    这个作业的要求在哪里 作业要求
    参考文献 一些网络资源

    知识梳理和总结

    软件安全概述

    • 软件安全困境
      复杂性:软件规模越来越大,越来越复杂,比如现在很多的专业软件动不动就几个G,十几个G,随着重复造轮子的风气弥漫,以后一个基础软件几十个G不是梦。
      可扩展性:现代软件的软件架构优化更好,客户使用感受更好,往往都会提供一些扩展和交互渠道。
      连通性:连通性使得网络缺陷被放大;网络的连通性使得不需要人为干涉的自动化攻击成为可能。
    • 软件安全漏洞威胁
      安全漏洞:安全漏洞的范畴不限于软件安全漏洞,还包括硬件、个人与组织管理中存在的、能够被攻击者利用来破坏安全策略的弱点。
      三个基本元素:系统的脆弱性或缺陷、攻击者对缺陷的可访问性、攻击者对缺陷的可利用性。一个安全脆弱性或缺陷真正被称为安全漏洞,必须是攻击者具备至少一种攻击工具或技术能够访问和利用到这一缺陷。
      软件安全漏洞构成了目前安全漏洞最为主要的部分,也是计算机安全应急响应阻止所关注的重点。
      软件缺陷与安全漏洞除了造成经济损失外,还可能直接危及到人类的生命安全。
    • 软件安全漏洞类型
      内存安全违规类:在软件开发过程中在处理RAM内存访问时所引入的安全缺陷 缓冲区溢出漏洞是一种最基础的内存安全问题。
      输入验证类:输入验证类安全漏洞是指软件程序在对用户输入进行数据验证存在的错误,没有保证输入数据的正确性、合法性和安全性,从而导致可能被恶意攻击与利用。XSS、SQL注入、远程文件包含、HTTP Header注入等。
      竞争条件类:竞争条件类缺陷是系统或进程中一类比较特殊的错误,通常在涉及多进程或多线程处理的程序中出现,是指处理进程的输出或结果无法预测,并依赖于其他进程事件发生的次序或时间时,所导致的错误。
      权限混淆与提升类:权限混淆与提升漏洞是指计算机程序由于自身编程疏忽或被第三方欺骗,从而滥用其权限,或赋予第三方不该给予的权限。跨站请求伪造、FTP反弹攻击、权限提升、“越狱"等。

    缓冲区溢出基础概念

    • 缓冲区溢出的基本概念
      缓冲区溢出定义:程序企图在预分配的缓冲区之外写数据。
      漏洞危害:用于更改程序执行流,控制函数返回值,执行任意代码。
      漏洞产生原因:不可避免,由于程序存储数据(buffer)和程序(return address)都在栈上,当存储数据覆盖了控制数据,就会发生缓冲区溢出的可能。
      缓冲区溢出攻击原理:缓冲区溢出是一种系统攻击的手段,通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其他指令,以达到攻击的目的。据统计,通过缓冲区溢出进行的攻击占所有系统攻击总数的80%以上。
    • 汇编语言基础知识
      进程内存管理: 所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等。不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内存是事先静态分配和统一回收的,而有些却是按需要动态分配和回收的。对任何一个普通进程来讲,它都会涉及到5种不同的数据段。稍有编程知识的朋友都能想到这几个数据段中包含有“程序代码段”、“程序数据段”、“程序堆栈段”等。不错,这几种数据段都在其中,但除了以上几种数据段之外,进程还另外包含两种数据段。下面我们来简单归纳一下进程对应的内存空间中所包含的5种不同的数据区。
      代码段:代码段是用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像。代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作——它是不可写的。
      数据段:数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配的变量和全局变量。
      BSS段:BSS段包含了程序中未初始化的全局变量,在内存中 bss段全部置零。
      堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等> > 函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
      栈:栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
      Linux操作系统采用虚拟内存管理技术,使得每个进程都有各自互不干涉的进程地址空间。该空间是块大小为4G的线性虚拟空间,用户所看到和接触到的都是该虚拟地址,无法看到实际的物理内存地址。利用这种虚拟地址不但能起到保护操作系统的效果(用户不能直接访问物理内存),而且更重要的是,用户程序可使用比实际物理内存更大的地址空间。
      Windwos操作系统的进程内存空间布局则与Linux系统有一些差异,如下图所示,2GB-4GB为内核态地址空间,用于映射Windows内核代码和一些核心态DLL,并用于存储一些内核态对象,0GB-2GB为用户态地址空间,高地址段映射了一些大量应用进程所共同使用的系统DLL,如Kernel32.dll、User32.dll等,在1GB地址位置用于装载一些应用进程本身引用的DLL文件,可执行代码区间从0x00400000开始,然后是静态内存空间用于保存全局变量与静态变量,“堆”同样是从低地址到高地址增长,用于存储动态数据,“栈”也是从高地址向低地址增长,在单线程进程中一般的“栈”底在0x0012xxxx的位置,而在多线程的进程内存空间中,则拥有多个“堆”和多个“栈”,分布来存储各个线程的执行数据。
      函数调用进程:栈结构与函数调用过程的底层细节是理解栈溢出攻击的重要基础,因为栈溢出攻击就是针对函数调用过程返回地址在栈中的存储位置,进行缓冲区溢出,从而改写返回地址,达到让处理器指令寄存器跳转到攻击者指定位置执行恶意代码的目的。程序进行函数调用的过程主要如下三个步骤:调用:调用者将函数调用参数、函数调用下一条指令的返回地址压栈,并跳转至被调用函数入口地址;序言:被调用函数开始执行首先会进入序言阶段,将对调用函数的栈基址进行压栈保存,并创建自身函数的栈结构,具体包括将ebp寄存器赋值为当前栈基址,为本地函数局部变量分配栈地址空间,更新esp寄存器为当前栈顶指针。返回:被调用函数执行完功能将指令控制权返回给调用者之前,会进行返回阶段的操作,通常执行level 和 ret指令,即恢复调用者的栈顶与栈底指针,并将之前压栈的返回地址装载至指令寄存器eip中,继续执行调用者在函数调用后的下一条指令。

    Linux平台的栈溢出与Shellcode

    • Linux平台栈溢出攻击技术
      Linux平台栈溢出攻击按照攻击数据的构造方式不同,主要有NSR、RNS和RS三种模式:
      NSR模式:NSR模式主要适用于被溢出的缓冲区变量比较大,足以容纳Shellcode的情况,其攻击数据从低地址到高地址的构造方式是一堆Nop指令(即空操作指令)之后填充Shelleode,再加上一些期望覆盖RET返回地址的跳转地址,从而构成了NSR攻击数据缓冲区,通过将这个攻击缓冲区作为vulnerablel.c漏洞程序输入,复制至其局部变量buf时,将溢出并改写main函数的返回地址,从而使得程序执行流程跳转至Nop指令所填充出来的“着陆区”中,无论跳转至哪个Nop指令上,程序都会继续执行,并最终运行Shellcode,向攻击者给出Shell。
      RNS模式:一般用于被溢出的变量比较小,不足于容纳Shellcode的情况,攻击数据从低地址到高地址的构造方式是首先填充一些期望覆盖RET返回地址的跳转地址,然后是一堆Nop指令填充出“着陆区”,最后再是Shellcode。在溢出攻击之后,攻击数据将在RET区段即溢出了目标漏洞程序的小缓冲区,并覆盖了栈中的返回地址,然后跳转至Nop指令所构成的“着陆区”,并最终执行Shellcode。
      RS模式:在这种模式下能够精确地定位出Shellcode在目标漏洞程序进程空间中的起始地址,因此也就无须引入Nop空指令构建“着陆区”。这种模式是将Shellcode放置在目标漏洞程序执行时的环境变量中,由于环境变量是位于Linux进程空间的栈底位置,因而不会受到各种变量内存分配与对齐因素的影响,其位置是固定的
    • Linux平台的Shellcode实现技术
      shellcode是一段弹出shell的可执行代码,Shellcode就是符合Intel32位指令规范的一串CPU指令,被用于溢出之后改变系统正常流程,转而执行Shellcode以完成渗透测试者的攻击目的。通常提供一个访问系统的本地或远程命令行访问。
      Linux本地Shellcode实现机制:
      先用高级编程语言,通常用C,来编写Shellcode程序;
      编译并反汇编调试这个Shellcode程序:
      从汇编语言代码级别分析程序执行流程;
      整理生成的汇编代码,尽量减小它的体积并使它可注入,并可通过嵌入C语言进 行运行测试和调试;
      提取汇编代码所对应的opcode二进制指令,创建Shellcode指令数组。
      Linux远程Shellcode实现机制
      Linux系统上的远程Shellcode需要让攻击目标程序创建socket监听指定的端口等待客户端连接,启动一个命令行Shell并将命令行的输入输出与socket绑定,这样攻击者就可以通过socket客户端连接目标程> 序所在主机的开放端口, 与服务端socket建立起通信通道, 并获得远程访问Shell

    Windows平台上的栈溢出与Shellcode

    • Windows平台栈溢出攻击技术
      Windows 平台栈溢出攻击技术机理:Windows 操作系统平台在很多方面与linux 操作系统具们显诸小回的实现机制
      对程序运行过程中废弃栈的处押方式差异:当一个函数调用完成返回至调用者,执行下一条指令之前,Windows平台会向废弃栈中写入一些随机的数据,而Linux则不进行任何的处理。
      进程内存空间的布局差异:Windows操作系统的进程内存空间布局与Linux存在着不同,Linux进程内存空间中栈底指针在0xc0000000之下,即一般栈中变量的位置都在0xbfff地址附近,在这些地址中没有空字节。Windows平台的栈位置处于0x00FFFFFF以下的用户内存空间,一般为0x0012地址附近,而这些内存地址的首字节均为0x00空字节。
      系统功能调用的实现方式差异:Windows平台上进行操作系统功能调用的实现方法较Linux更加复杂,Linux系统中通过int 80中断处理来调用系统功能,而Windows系统则是通过操作系统中更为复杂的API及内核处理例程调用链来完成系统功能调用,对应用程序直接可见的是应用层中如kernel32.dll、User32.dll等系统动态链接库中导出的一些系统API接口函数。
    • Windows平台Shellcode实现技术
      Windows本地Shellcode:在Windows 上, 典型的本地Shellcode 同样也是启动一个命令行Shell, 即"command.com” 或'cmd.exe", Windows 32的系统API中捉供了system()函数调用, 可以用于启动> 指定程序或运行特定命令,在调用system ("command.com” )之后即可启动命令行程序。
      在Windows平台上,典型的本地Shellcode同样也是启动一个命令行Shell, 即command.com或cmd.exe,Windows 32的系统 API 中提供了system()函数调用,可以用于启动指定程序或运行特定命令,在调用system(command.com)之后即可启动命令行程序。
      编写shellcode最简单的方式是使用硬编码的函数地址,比如system()函数在Windows XP特定版本的目标程序内存空间加载地址为0x77bf93c7,我们在shellcode中可以使用Call 0x77bf93c7指令来让EIP指令寄存器跳转至硬编码的函数入口地址执行,这种方法可以有效压缩编码长度。
      C语言版的Windows本地Shellcode程序,即使用LoadLibrary()函数加载msvert.dll动态链接库,通过GetProcAddress()函数获得system函数的加载入口地址,赋值给ProcAdd函数指针,然后通过函数指针调用system()函数,启动命令行Shell,最后还要调用exit()退出当前进程。
    • 堆溢出攻击
      堆溢出是缓冲区溢出中第二种类型的攻击方式,由于堆中的内存分配与管理机制较栈更复杂,不同操作系统平台的实现机制具有显著的差异。堆中没有可以直接覆盖的返回地址,因此堆溢出攻击比栈溢出更难。
      函数指针改写
      要求被溢出的缓冲区临近全局函数指针存储地址,且在其低地址方向上。此时向缓冲区填充数据,如果没有边界控制和判断,就可以覆盖函数指针所在的内存区,改写函数指针的指向地址,则程序在使用这个函数指针的时候就会执行shellcode。
      C++类对象虚函数表改写
      使用了虚函数机制的C++类,如果它的类成员变量中存在可被溢出的缓冲区,那么就可以进行堆溢出攻击,通过覆盖类对象的虚函数指针,使其指向一个特殊构造的虚函数表,从而转向执行攻击者恶意注入的指令。
      Linux下堆管理glibc库free()函数本身漏洞
      Linux操作系统的堆管理是通过glibc库来实现的,通过称为Bin的双向循环链表来保存内存空闲块的信息。glibc库中的free()函数在处理内存块回收时,会将被释放的空闲块和与之相邻的块合并,利用精心构造的块可以在合并时覆盖Bin前指针的内容。

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

    • 尝试杜绝溢出的防御技术:
      采取如高级差错程序fault injection,通过Fuzz注入测试来寻找代码的安全漏洞,或者在编译器上引入针对缓冲区的便捷保护检查机制如Jone & Kelly针对gcc的数组边界检查、Compaq C对编译器进行改进杜绝溢出。
    • 允许溢出但不让程序改变执行流程的防御技术:
      允许溢出发生,但对可能影响到程序流程的关键数据结构实施严密的安全保护,不让程序改变其执行流程,从而阻断溢出攻击。通过对编译器gcc加补丁,使得在函数入口处能够自动地在栈中返回地址的前面生成一个Canary检测标记,在函数调用结束检测该标记是否改变来阻止溢出改变返回地址,从而阻止缓冲区溢出攻击。
    • 无法让攻击代码执行的防御技术:
      通过堆栈不可执行限制来防御缓冲区溢出攻击,通过CPU硬件和各种操作系统内核补丁来支持堆栈不可执行。

    总结

    我觉得这也是重复造东西的一种体现。

  • 相关阅读:
    愚公移山
    唐雎不辱使命
    渡易水歌
    论语
    智子疑邻
    学弈
    SQL Merge 语法 单表查询
    大道之行也
    Java开发人员最常犯的10个错误
    模拟Spring手撕一个简单的IOC容器
  • 原文地址:https://www.cnblogs.com/vizen/p/12840814.html
Copyright © 2011-2022 走看看