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

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

1.实践内容

1.1软件安全概述

  • 软件安全漏洞:可以被攻击者利用并导致危害得安全缺陷。不限于软件安全漏洞,还包括硬件、个人与组织管理中存在得、能够被攻击者利用来破坏安全策略得弱点。包括三个基本元素:系统的脆弱性,攻击者对缺陷的可访问性可利用性
  • 软件安全困境:
    • 复杂性:软件规模变得越来越复杂
    • 可扩展性:为了更好地满足用户需求,提供扩展和交互渠道
    • 连通性:互联网地世界,更多的软件连通在一起
  • 软件安全漏洞类型:从技术上分为
    • 内存安全违规类:在软件开发过程中处理RAM内存访问时引入的俺去缺陷。如:
      • 缓冲区溢出漏洞
      • Double Free等不安全指针(在计算机程序中存在的并没有指向适当类型对象的非法指针)
    • 输入验证类:软件程序在对用户输入进行数据验证存在的错误,没有保证输入数据的正确性、合法性和安全性,从而导致可能被恶意攻击与利用。根据输入位置、恶意输入内容被程序软件程序的使用方式不同,包括:格式字符串SQL注入代码注入远程文件包含XXS等技术形式。
    • 竞争条件类:系统或进程中一类比较特殊的错误,通常在涉及多进程或多线程处理的程序中出现,是指处理进程的输出或结果无法预测,并依赖于其他进程事件发生的次序或时间时,所导致的错误。如:
      • TOCTTOU(程序检查一个谓词条件之后,通过另一进程对谓词条件进行修改从而改变条件状态,使检查时刻和使用时刻的条件状态并不一致。)
      • 符号链接竞争问题(由于程序以不安全的方式创建文件所导致的竞争条件类漏洞,恶意用户可以创建一个符号链接,指向无权访问的文件,当存在漏洞的特权程序创建或写操作与符号链接同名的文件时,将会对已存在文件进行修改,从而插入恶意用户所期望的内容。)
    • 权限混淆与提升类:指计算机程序由于自身编程疏忽或被第三方欺骗,从而滥用其权限,或赋予第三方不该给予的权限。如:
      • FTP反弹技术(利用FTP协议的设计缺陷,绕过FTP的权限控制、让FTP服务器作中间代理)
      • 权限提升
      • 越狱

1.2缓冲区溢出

  • 缓冲区溢出是计算机程序中存在的一类内存安全违规类漏洞,在计算机程序向特定缓冲区内填充数据时,超出了缓冲区本身的容量,导致外溢数据覆盖了相邻内存空间的合法数据,从而改变程序执行流程破坏系统运行完整性。

  • 原因:对复制的目标缓冲区普遍没有进行严格的边界安全保护;冯·诺依曼体系存在本质安全缺陷,计算机程序的数据和指令都在同一内存中进行存储,没有严格的分离。

  • 背景知识:

    • 编译器与调试器的使用:

      • C/C++等高级编程语言编写的源码,要通过编译器和连接器才能生成可执行程序代码;
      • C/C++编程语言,常用的编译与连接器是GCC。执行“gcc -c text.c”源码编译生成“text.o”,执行“gcc -o text text.o”连接,生成test可执行文件。
      • Linux上常使用GDB调试器;windows上使用VC++
    • 汇编语言基础知识:

      寄存器名 说明 功能
      eax 累加器 加法乘法指令的缺省寄存器, 函数返回值
      ecx 计数器 REP & LOOP指令的内定计数器
      edx 除法寄存器 存放整数除法产生的余数
      ebx 基址寄存器 在内存寻址时存放基地址
      esp 栈顶指针寄存器 ESP当前堆栈的栈顶指针
      ebp 栈底指针寄存器 EBP当前堆栈的栈底指针
      esi、dei 源、目标索引寄存器 在字符串操作指令中,ESI指向源串,EDI指向目标串
      eip 指令寄存器 EIP指向下一条指令的地址
      eflags 标志寄存器 标志寄存器
      cs 代码段寄存器 当前执行的代码段
      ss 堆栈段寄存器 当前堆栈段
      ds 数据段寄存器 当前数据段
    • 进程内存管理

      • linux的进程内存空间布局和管理机制:

        • 程序在执行时,系统在内存中会为程序创建一个虚拟的内存地址空间,在32位机上即4GB的空间大小,用于映射物理内存,并保存程序的指令和数据;

        • 3GB以下为用户态空间,3GB-4GB为内核态空间;

        • 操作系统将可执行程序加载到新创建的内存空间中,程序一般包含.text(包含程序指令,只读)、.bss (包含未经初始化的数据,可写)和.data(包含静态初始化的数据,可写)三种类型的段;

        • 加载完成后,系统开始为程序初始化“栈”(后进先出的数据结构)和“堆”(先进先出的数据结构)。

        • 程序执行时,就会按照程序逻辑执行.text中的指令,并在“堆”和“栈”中保存和读取数据,然而程序并不能正确地区分指令和数据,所以当我们修改内存空间中影响程序执行逻辑的敏感位置,并将恶意数据作为指令提交给处理器时,它仍会执行这些指令。

      • windows的进程内存空间布局和管理机制:

        • 2GB-4GB为内核态地址空间,用于映射Windows内核代码和一些核心态DLL,并用于存储一些内核态对象;
        • 0GB-2GB为用户态地址空间,高地址段映射了一些大量应用程序共用使用的系统DLL,在1GB位置装载进程本身所引用的DLL文件,可执行代码段从0x400000开始,静态内存空间用于保存全局变量与静态变量。
    • 函数调用过程

      • 栈溢出攻击就是针对函数调用过程中返回地址在栈中的存储位置,进行缓冲区溢出,从而改写返回地址,达到让处理器指令寄存器跳转至攻击者指定位置执行恶意代码的目的。
      • 是后进先出的抽象数据结构,主要用于实现程序中的函数或过程调用,在栈中会保存函数的调用参数、返回地址、调用者栈基址、函数本地局部变量等数据。
      • 步骤:
        • 调用:将函数调用参数、函数调用下一条指令的返回地址压栈,并跳转至被调用函数入口地址
        • 序言:被调用函数开始执行时首先进入序言阶段,对调用函数的栈基址进行压栈保存,创建自身函数栈结构
        • 返回:执行leave和ret指令(即恢复调用者的栈顶和栈底指针,将之前压栈的返回地址装载至eip,执行函数调用之后的下一条指令)

  • 缓冲区溢出攻击原理:

    • 根据缓冲区在进程内存空间中的位置分为:

      • 栈溢出:存储在栈上的一些缓冲区变量由于存在缺乏边界保护问题,能够被溢出并修改栈上敏感信息(如返回地址),导致程序流程改变
      • 堆溢出:存储在堆上的缓冲区变量缺乏边界保护遭受溢出攻击
      • 内核溢出:存在于内核模块或程序中,由于进程内存空间内核态中存储的缓冲区变量溢出
    • 缓冲区溢出攻击三个挑战:

      • 找出缓冲区溢出要覆盖和修改的敏感位置;
      • 修改敏感位置的值,常为恶意指令的起始位置;
      • 恶意指令代码,称为攻击的payload,通常会为攻击者给出一个远程Shell访问,称为Shellcode。

1.3 Linux平台上的栈溢出与Shellcode

  • Linux平台中的栈溢出攻击按照攻击数据的构造方式不同,主要有NSR、RNS和RS三种模式。

    • NSR模式:主要适用于被溢出的缓冲区变量比较大,足以容纳Shellcode的情况,适用于远程栈溢出。
      • 其攻击数据从低地址到高地址的构造方式是一堆Nop指令(空操作指令)之后填充Shellcode,
      • 再加上一些期望覆盖RET返回地址的跳转地址,从而构成了NSR攻击数据缓冲区。
    • RNS模式:一般用于被溢出的变量比较小,不足于容纳Shellcode的情况,适用于远程栈溢出。
      • 攻击数据从低地址到高地址的构造方式是首先填充一些期望覆盖RET返回地址的跳转地址,
      • 然后是一堆Nop指令填充出“着陆区”,最后再是Shellcode。
    • RS模式:能够精确地定位出Shellcode在目标漏洞程序进程空间中的起始地址,因此也就无需引入Nop空指令构建“着陆区”。这种模式是将Shellcode放置在目标漏洞程序执行时的环境变量中,由于环境变量是位于Linux进程空间的栈底位置,因而不会受到各种变量内存分配与对齐因素的影响,其位置是固定的。
  • 在Linux平台中,本地栈溢出攻击,即渗透攻击代码的攻击目标对象是本地的漏洞程序,可以用于特权提升。

  • Linux平台上的远程栈溢出攻击的原理与本地缓冲区溢出是一样的,区别在于用户输入传递的途经不同,以及Shellcode的编写方式不同

    • 本地栈溢出的用户输入传递途径主要为:argv命令行输入、文件输入
    • 远程栈溢出的用户输入途经是通过网络
    • Shellcode编写区别:远程缓冲区溢出采用远程shell访问;本地缓冲区溢出是特权提升。
  • linux平台的shellcode实现技术

    • Linux远程shellcode实现机制:让攻击者目标程序创建socket连接,启动一个命令行,并将命令行的输入输出与socket绑定,攻击者就可通过socket客户端连接目标程序所在主机的开放端口,与服务端socket建立通信通道,并获得远程访问shell
    • shellcode产生的5个通用步骤:
      • 用高级语言(通常用C)编写shellcode程序
      • 编译并反汇编shellcode程序
      • 从汇编语言代码级别分析程序执行流程
      • 整理生成的汇编代码,尽量减小它的体积并使它可注入,并通过嵌入C语言进行运行测试和调试
      • 提取汇编代码所对应的opcode二进制指令,创建Shellcode指令数组
    • 典型的Linux系统本地Shellcode的C语言实现代码如下。通过execve()函数启动/bin/sh提供命令行
    #include <stdio.h>
    int main ()
    {
        char * name[2];
        name[0] = "/bin/sh";
        name[1] = NULL;
        execve( name[0], name, NULL );
        return 0;
    }
    
    • 将这段代码进行编译并查看其汇编代码 ,对应的汇编代码如下:

      int main()
      {
        	__asm__
          ("
           xor    %edx,%edx   //消除空字节
      		 push   %edx
      		 push   $0x68732f6e
      	   push   $0x69622f2f
      	   mov    %esp,%ebx
      	   push   %edx
      	   push   %ebx
      	   mov    %esp,%ecx
      	   mov    $0xb,%eax
      	   int    $0x80
           ")
      }
      
    • 将其转化为Opcode版本,将这些opcode二进制指令代码连接在一起,并保持在攻击数据缓冲区中,就是Shellcode。

      31 d2   // xor %edx,%edx
      52      // push %edx
      68 6e 2f 73 68   // push $0x68732f6e
      68 2f 2f 62 69   // push $0x69622f2f
      89 e3   // mov %esp,%ebx
      52      // push %edx
      53      // push %ebx
      89 e1   // mov %esp,%ecx
      8d 42 0b         // lea 0xb(%edx),%eax
      cd 80   //  int $0x80
      

1.4 Windows栈溢出与Shellcode

  • Windows平台栈溢出与Linux平台的差异

    • 对程序运行过程中废弃栈的处理方式差异:Windows平台会向废弃栈中写入一些随机的数据,而Linux则不进行任何的处理。导致实施栈溢出攻击时,windows平台中构建攻击缓冲区数据在栈中植入恶意指令时,会面临一些限制,导致NSR模式不适用于Windows平台。

    • 进程内存空间的布局差异:

      • Linux进程内存空间中栈底指针在0xc0000000之下,栈中变量一般在0xbfff****附近,在这些地址中没有空字节。
      • Windows平台的栈位置处于0x00FFFFFF以下的用户内存空间,一般在0x0012****附近,这些内存地址的首字节均为0x00空字节
      • 导致RNS模式不适用于Windows平台
      • RS模式也不适用于Windows平台
    • 系统功能调用的实现方式差异:

      • Linux系统中通过“int 80”中断处理来调用系统功能
      • Windows系统是通过操作系统中更为复杂的API及内核处理例程调用链来完成系统功能调用。
    • 解决方法:使用系统核心DLL的“JMP ESP”指令来完成控制流程的跳转

  • Windows远程栈攻击示例

    • 创建一个客户端socket,连接目标漏洞服务程序所监听的IP地址与端口
    • 精心设计一段用于溢出缓冲区的攻击数据
    • 攻击数据缓冲区的大小是1024,先填充了一段Nop指令;在事先计算好的返回地址位置上放置了一个指向“JMP ESP"指令的地址,该指令地址在不同的目标程序运行系统上是不一样的,是攻击者通过在不同的目标程序运行系统上调试获得的。
    • 调用send函数将攻击数据通过socket发给目标服务
    int main() { 
          WSADATA wsa; 
          SOCKET sockFD; 
          char Buff[1024],*sBO; 
    
          WSAStartup(MAKEWORD(2,2),&wsa); 
          sockFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
          struct sockaddr_in server; 
    
          server.sin_family = AF_INET; 
          server.sin_port = htons(3764); 
          server.sin_addr.s_addr=inet_addr("127.0.0.1"); 
    
          connect(sockFD,(struct sockaddr *)&server,sizeof(server)); 
          for(int i=0;i<56;Buff[i++]=0x90); 
          strcpy(Buff+56,(char *)eip); 
          strcpy(Buff+60,(char *)sploit); 
          sBO = Buff; send(sockFD,sBO,56+4+560,0); 
          closesocket(sockFD); 
          WSACleanup(); 
          return 1; 
    }
    
  • windows平台Shellcode实现技术

    • 编写Shellcode最简单的方式是使用硬编码的函数地址,如system()函数在windows xp特定版本的目标程序内存空间的加载地址为0x77bf93c7,那调用system则可使用call 0x77bf93c7

    • 实例分析

      • C语言版Windows本地Shellcode程序。使用LoadLibrary()加载msvcrt.dll动态链接库,通过GetProcAddress()函数获取system()函数的加载入口地址,赋值给ProcAdd函数指针,然后通过函数指针调用system()函数,启动命令行shell;最后使用exit退出当前进程
      #include <windows.h>
      #include <winbase.h>
      typedef void (*MYPROC)(LPTSTR);
      typedef void (*MYPROC2)(int);
      void main()
      {
              HINSTANCE LibHandle;
              MYPROC ProcAdd;
              MYPROC2 ProcAdd2;
              char dllbuf[11]  = "msvcrt.dll";
              char sysbuf[7] = "system";
              char cmdbuf[16] = "command.com";
              char sysbuf2[5] = "exit";
              LibHandle = LoadLibrary(dllbuf);
              ProcAdd = (MYPROC)GetProcAddress(
      			LibHandle, sysbuf);
              (ProcAdd) (cmdbuf);
      
              ProcAdd2 = (MYPROC2) GetProcAddress(
      			LibHandle, sysbuf2);
      		(ProcAdd2)(0);
      }
      
      • 汇编语言版。

        #include <windows.h>
        #include <winbase.h>
        void main()
        {
        	LoadLibrary("msvcrt.dll");
        	__asm{
        		mov esp,ebp    //把ebp的内容赋值为esp
        		push ebp       //保存ebp,esp-4
        		mov ebp,esp    //给ebp赋新值,作为局部变量的基指针
            xor edi,edi    
            push edi       //压入0,esp-4,构造字符串的结尾\0字符
            sub esp,08h    //一共12个字符,用来放command.com
            mov byte ptr [ebp-0ch],63h  
            mov byte ptr [ebp-0bh],6fh  
            mov byte ptr [ebp-0ah],6dh  
            mov byte ptr [ebp-09h],6Dh  
            mov byte ptr [ebp-08h],61h  
            mov byte ptr [ebp-07h],6eh  
            mov byte ptr [ebp-06h],64h  
            mov byte ptr [ebp-05h],2Eh  
            mov byte ptr [ebp-04h],63h  
            mov byte ptr [ebp-03h],6fh  
            mov byte ptr [ebp-02h],6dh  //生成串“command.com”
            lea eax,[ebp-0ch]
            push eax                    //串地址作为参数入栈
            mov eax, 0x77bf8044         //API入口地址 
            call eax                    //调用system
        		
        	}
        
        }
        
    • Windows远程shellcode实现步骤:

      • 创建一个服务器端socket,并在指定的端口上监听
      • 通过accept()接受客户端的网络连接
      • 创建子程序,运行“cmd.exe”,启动命令行
      • 创建两个管道,命令管道将服务器端socket接收到的客户端通过网络输入的执行命令,连接至cmd.exe的标准输入;然后输出管道将cmd.exe的标准输出连接至服务器端socket的发送,通过网络将运行结果反馈给客户端

1.5 堆溢出攻击

  • 由于堆中的内存分配与管理机制较栈更复杂,不同操作系统平台的实现机制具有显著的差异。
  • 堆中没有可以直接覆盖并修改指令寄存器指针的返回地址,因此往往需要利用在堆中一些会影响程序执行流程的关键变量。如:函数指针、C++类对象中的虚函数表等
  • 函数指针:需要被溢出的缓冲区临近全局函数指针存储地址,且在其低地址方向上。此时向缓冲区填充数据,如果没有边界控制和判断,就自然地覆盖函数指针所在的内存区,从而改写函数指针的指向地址,攻击者只要将该函数指针指向恶意构造地Shellcode入口地址,则程序在使用这个函数指针的时候就会执行shellcode。
  • C++类对象虚函数表改写:如果它的类成员变量中存在可被溢出的缓冲区,那么就可通过覆盖类对象的虚函数指针,使其指向一个特殊构造的虚函数表,从而转向执行攻击者恶意注入的指令。
  • Linux下堆管理glibc库free()函数本身漏洞:Linux操作系统中的堆管理是通过glibc库实现的,glibc库中的free()函数在处理内存块回收时,会将已被释放的空闲块和与之相邻的空闲块进行合并,将符合条件的空闲块从Bin链(双向循环链来存储内存空闲块信息)表中的unlink摘出来,合并之后再将新的空闲块插回链表中。

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

  • 尝试杜绝溢出的防御技术
    解决缓冲区溢出攻击最根本的办法是编写正确的、不存在缓冲区溢出安全漏洞的软件代码。

    • 开放一些工具和技术帮助经验不足的程序员编写正确的程序
    • 引入针对缓冲区的边界保护检查机制
  • 允许溢出但不让程序改变执行流程的防御技术

    允许溢出发生,但对可能影响到程序流程的关键数据结构实施严密的安全保护,不让程序改变其执行流程,从而阻断溢出攻击。如对编译器gcc加补丁。

  • 无法让攻击代码执行的防御技术
    尝试解决冯·诺伊曼体系的本质缺陷,通过堆栈不可执行限制来防御攻击。

2.实践过程

无实践内容!

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

  • 问题1:理论知识理解较慢
  • 问题1解决方案:慢慢理解,百度查看

4.实践总结

对于汇编语言,还是不太熟练。基本概率容易混淆搞忘。

参考资料

  • 《网络攻防技术与实践》(诸葛建伟著)
posted @ 2020-05-06 23:17  20199122肖玲  阅读(160)  评论(0编辑  收藏  举报