缓冲区溢出是一种很常见也很古老的安全漏洞。早在上个世纪80年代,缓冲区溢出就已经为人所知,但时至今日,大量的缓冲区溢出
数据库系统是在操作系统平台之上的最重要的系统软件,数据库系统的安全可以说是十分重要的。曾经有句话这样说:如果网络遍地是金钱,那么金钱就在数据库服务器中。随着无纸化业务环境的不断扩大,人们在数据库中存储着越来越多的敏感信息:银行账户、医疗记录、政府文件、军事机密等等,数据库系统就成为越来越有价值的攻击目标,因此确保数据库系统的安全也越来越重要。
作为一种大型的系统软件,数据库系统中也存在着各种各样的安全漏洞,其中危害性较大的有缓冲区溢出、堆溢出和SQL注入等。
1.缓冲区溢出
缓冲区溢出是一种很常见也很古老的安全漏洞。早在上个世纪80年代,缓冲区溢出就已经为人所知,但时至今日,大量的缓冲区溢出漏洞仍被发现。最著名的Morris蠕虫就是利用Unix系统上fingerd程序的缓冲区溢出漏洞。在Oracle 9i发布之初,Oarcle公司曾宣称他的数据库是“ unbreakable ”的,但不到几个月的时间,就暴出Oracle 9i中oracle.exe、XDB等程序存在多个缓冲区溢出漏洞。
在C语言中最常见的缓冲区就是字符数组,而操纵字符数组的函数有gets、strcpy、sprintf等。这些函数在执行字符串拷贝的过程中没有对字符串进行长度检查,这样就很容易发生超长的字符串溢出缓冲区的情况。当初这样设计是出于效率的考虑,但现在看来,这些函数的使用已成为C语言软件脆弱的一个重要因素。如果程序员没有良好的编程习惯,时刻注意函数调用过程中是否拷贝了超过缓冲区长度的字符串,那么缓冲区溢出就不可避免。对于一个有缓冲区溢出漏洞的程序,当普通用户输入超长字符串时,,通常只会使该程序崩溃。例如对于下面一小段代码:
以下是引用片段:
/* vulprog */
#include
int main(int argc , char * argv[])
{
char buff[8];
strcpy(buff, argv[1]);
}
如果用户执行 ./vulprog AAAAAAAAAAAAAAAA,在Linux上会出现段错误,因为用户输入了超长的字符串,除了填满了缓冲区,还覆盖了其他一些程序正常退出所需要的数据。为了研究这个问题,就需要了解Linux系统中进程的内存空间。
进行函数调用时系统所作的“序幕”工作就是将函数的返回地址和EBP压栈,再将ESP赋给EBP使其成为局部基指针,最后ESP减去一定的值为局部变量留出空间。这样当程序将过长的字符串拷贝到缓冲区时就会依次覆盖EBP和返回地址。当用AAAA覆盖返回地址,函数退栈时系统就将0x41414141(A的16进制ASCII码)赋给EIP去执行,由于是一个非法的内存地址,故程序崩溃。但如果用一个实际存在的地址覆盖返回地址,那么程序就转而去执行该地址处的指令,通常黑客会在这个地址植入所谓的shellcode,由shellcode产生一个shell,如果被攻击程序设置了suid位,那么产生的shell就是root shell,黑客也就获得了系统的最高控制权,这一过程就是基本的缓冲区溢出攻击。
覆盖函数的返回地址是比较常见的攻击方式,但缓冲区溢出攻击的手法是灵活多样的,往往在编程中的一个小小纰漏就可能导致被攻击,下面简单介绍一下几种较为高级的攻击方式。
(1)通过覆盖函数指针进行攻击:
以下是引用片段:
/* vulprog */
int main(int argc , char * argv[])
{
void (* fp)(char *) = (void (*)(char *))&puts;
char buff[256];
strcpy(buff,argc[1]);
fp(argc[2]);
exit(1);
}
上面这个程序在执行拷贝时没有检查边界,这样用户数据就有可能覆盖函数指针fp,如果用shllcode的地址去覆盖fp,那么函数指针调用时就会去执行shellcode。