内容纲要

Return2libc --- 修改函数返回地址 , 让其指向内存中的一段指令

该类攻击方法的主要任务是 : 在内存中确定某个函数的地址 , 并用其覆盖掉返回地址 .

由于 libc 动态链接库中的函数被广泛使用 , 所以大概率可以在内存中找到该动态库 , 同时由于该库包含了一些系统级函数( 比如 system() ... ) , 因此可以使用这些系统级函数来获得当前进程的控制权

 Libc : C standard library( C标准函数库 ) , 是在C语言程序设计中 , 所有匹配标准的头文件的集合 , 以及常用的函数库实现程序 , 几乎所有的C语言程序都是由标准库的函数来创建的

 Libc泛指C标准函数库 , 而应用最广泛 , 功能最强大的当属 GNU Libc( glibc ) . 它属于GNU 系统的标准C库 , 其中定义了用C语言编写程序时所需的系统调用和其他基本功能 , 它不仅处理与内核通信的低级功能( 比如进程管理和文件管理 ) , 也处理更高级别的功能( 比如字符串操作或者命令行参数处理 )

 libc 的动态库文件叫做 libc.so , 通常路径是 /usr/lib/../libc.so , so文件是Linux下的共享库文件 , 其文件格式被称为 ELF 文件格式 . 

就拿系统级函数 system() 为例 , 大多数要执行的函数都需要参数 , 比如调用 system()函数打开 shell 的完整形式为 : system("/bin/bash") . 所以溢出数据中必须包含必要的参数


下面以执行 system("/bin/bash") 为例 , 研究溢出数据的组成部分 , 以及在栈中它们是如何被填充的

  • 溢出数据组成分析

    在函数调用发生后 , 栈中的结构是这样的

    png

    这里溢出数据的组成部分有所不同 , 如下图所示

    png

     padding1 : 这里的数据可以任意填充 , 但注意填充数据中不要包含" \x00 " , 否则会截断后面的数据 . 数据长度应该刚好覆盖函数的基地址
    
     address of system() : 这里填写 system() 函数在内存中地址 , 用来覆盖 callee 的返回地址
    
      padding2 : 数据长度是变化的( 比如32位机这里的数据长度为4 ) , 对应调用 system() 函数时的返回地址 , 因为这里只需要打开shell就可以了 , 而不用关心 shell 退出后的事件 , 所以这里padding2可以用任意数据填充
    
      address of "/bin/bash" : "/bin/bash" 在内存中的地址 , 也就是传递给 system() 的参数
    
  • 需要解决的问题
    • 返回地址之前的数据 padding1 应该有多长
      可以用调试工具( gdb , objdump , ... )查看汇编代码来确定这个距离 , 也可以在运行程序时不断修改输入长度来试探( 如果返回地址被无效地址( 比如 "AAAA" )覆盖 , 则程序会报错并终止 )

      这与 ShellCode 技术使用的方法相同 , 填充任意字符直到程序因返回地址被覆盖而报错

    • system() 函数地址应该是多少?
      这与程序是如何调用动态链接库( 比如 libc )中的函数了 , 若指定函数要被动态链接至程序中 , 运行的程序会先判断动态链接库在内存的起始地址 , 再加上需要的函数在动态链接库中的相对偏移量 , 最终才能得到函数在内存中的绝对地址

      那么就需要确定动态链接库的内存地址 , 这里同样要考虑 ASLR( 地址空间布局随机化 )技术 , 该项技术会将动态库加载的起始地址做随机化处理 . , 因此如果操作系统开启了 ASLR , 那么程序每次运行时动态链接库的起始地址都会随机变化 , 也就无法确定目标函数相对于内存空间的绝对地址

      所以 , Return2libc 仅能在操作系统关闭 ASLR 的前提下攻击成功 .

      在操作系统关闭 ASLR 的前提下 , 可以通过调试工具在程序运行过程中直接查看 system() 函数的绝对地址 . 也可以先查看动态链接库在内存中起始地址 , 再查看 system 函数在动态链接库中的相对偏移量 , 计算得到该函数的绝对地址

    • "/bin/bash" 的地址在哪
      可以在动态库中搜索这个字符串 , 如果存在就可以按照 动态链接库的起始地址 + 相对偏移量 来确定该字符串的绝对地址

      若在动态链接库中找不到这个字符串 , 可以把这个字符串加到环境变量中 , 再通过 getenv() 等函数来确定字符串绝对地址


后续

该方法是通过覆盖 callee 的返回地址来执行动态链接库中的函数的 . 该方法与 ShellCode 类似 , 都需要目标操作关闭 ASLR 防御机制的

那么有没有方法可以绕过 ASLR( 内存空间布局随机化 )的方法呢 ? 接下来你就会看到 ~

最后修改日期:2019年9月17日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。