数据库安全漏洞浅析之缓冲区溢出漏洞(4)
作者:安华金和 发布时间:2017-01-27

通过对过往的数据库安全事件进行技术分析,我们列举了两种通过栈溢出漏洞进行数据库攻击的手段。前文中,我们介绍了第一种漏洞攻击方式,即通过改变程序逻辑,跳过密码验证,获取数据库账户权限。本文我们将介绍另一种攻击方式:直接劫持程序,运行攻击代码。

事实上,直接劫持程序的方法只是在改变程序逻辑的方法基础上更进一步。前文中我们提到通过缓冲区溢出,可以覆盖掉一些关键变量导致函数流程被改变,那么如果继续向下溢出就有可能覆盖函数返回地址。改变函数返回地址到攻击者需要返回的地方。本程序可以设计成在buffer内存入一个脚本,然后用w填满buffer中脚本到返回地址这中间的空缺。最后把buffer的首地址覆盖到函数返回地址。让函数返回时,返回到buffer的初始地址,执行buffer内存储的脚本。

为了达到这个目标,首先要确定函数返回的地址和buffer的地址。已经得到了buffer的地址,看图可知函数返回的地址。也就是需要从溢出点buffer到函数返回地址之间覆盖我们的信息。函数返回地址在12FB74buffer初始地址是12FB40,咱们需要覆盖掉这56个字节。

20170127.png

构造一个shellcode(介绍shellcode不再本文范围之内)+填充数据+0012FB40。这样当函数发生retn时,不会跳到0041064,而是跳转到设定好的0012FB40中。后面就会按步执行存储于0012FB40中的shellcode。至此就完成了整个溢出过程,通过缓冲区溢出劫持整个程序的方法除了这种直接的覆盖返回值地址外,还有覆盖SEH。

SEH是windows下的异常处理机制的重要数据结构(c++的_try的异常处理其实本质就是调用的SEH)。保证windows在出现各种错误操作后给函数或系统一次call back的机会。SEH结构非常复杂,这里只说和缓冲溢出有关的部分。每个SEH包含两个DWORD指针:SEH链表指针和异常处理函数句柄,共8个字节存储于栈中。当线程初始化时,会自动向栈中安装1个SEH,作为线程默认的异常处理。如果程序调用了-try()等异常处理机制。编译器就是向当前函数栈中安装1个SEH来处理异常的。栈中同时可以存在多个SEH。整个栈中的SEH通过链表指针形成一个贯穿整个栈的单向链表。当异常出现,操作系统中断程序,沿着整个SEH链表依次查询看是是否有能处理这个异常的SEH。如果程序加载的SEH都不能处理,则会到系统级的SEH,由他探出错误窗口,强制关闭程序。

SEH存在于栈中,所以栈缓冲区溢出有机会覆盖掉SEH。和覆盖返回地址一样,如果覆盖后异常处理的函数入口被修改成上面的buffer的入口那么就可以,通过shellcode+填充数据+buffer地址的手法。达到攻击的目的,但是要注意的是需要在填充数据中触发异常来保证SEH被触发。

至此windows下缓冲区溢出的主要原理已经介绍完毕。安华金和数据库安全实验室通过对此类典型漏洞攻击进行实例还原,从技术角度呈现攻击过程。攻与防的较量永远相辅相成,只有透彻了解了攻击手段,才能构建准确的漏洞特征库,由数据库防火墙数据库审计系统实现恶意攻击的有效识别,并实施阻断、拦截及告警。