《网络攻防技术与实践》第十一周作业 SQL注入攻击与实践
1.研究缓冲区溢出的原理,至少针对两种数据库进行差异化研究
缓冲区溢出原理
在计算机内部,输入数据通常被存放在一个临时空间内,这个临时存放的空间就被称为缓冲区,缓冲区的长度事先已经被程序或者操作系统定义好了。向缓冲区内填充数据,如果数据的长度很长,超过了缓冲区本身的容量,那么数据就会溢出存储空间,而这些溢出的数据还会覆盖在合法的数据上,这就是缓冲区和缓冲区溢出的道理。
通常,在栈中分配某个字节数组来保存一个字符串,但是字符串的长度超出了为数组分配的空间。C对于数组引用不进行任何边界检查,而且局部变量和状态信息,都存在栈中。这样,对越界的数组元素的写操作会破坏存储在栈中的状态信息。当程序使用这个被破坏的状态,试图重新加载寄存器或执行ret指令时,就会出现很严重的错误。
void echo()
{
char buf[8] ;
gets(buf) ;
puts(buf) ;
}
由于栈是向地地址增长的,数组缓冲区是向高地址增长的。故,长一些的字符串会导致gets覆盖栈上存储的某些信息。
随着字符串变长,下面的信息会被破坏:
输入的字符数量 被破坏的状态
0---7 无
8---11 保存的%ebx的值
12---15 保存的%ebp的值
16---19 返回地址
20+ caller中保存的状态
如果破坏了存储%ebp的值,那么基址寄存器就不能正确地恢复,因此调用者就不能正确地引用它的局部变量或参数。
如果破坏了存储的返回地址,那么ret指令会使程序跳转到完全意想不到的地方。
缓冲区溢出的一个更加致命的使用就是让程序执行它本来不愿意执行的函数。这是一种最常见的通过计算机网络攻击系统安全的方法。通常,输入给程序一个字符串,这个字符串包含一些可执行代码的字节编码,称为攻击代码,另外还有一些字节会用一个指向攻击代码的指针覆盖返回地址。那么,执行ret指令的效果就是跳转到攻击代码。
通常,使用gets或其他任何能导致存储溢出的函数,都不是好的编程习惯。不幸的是,很多常用库函数,包括strcpy、strcat、sprintf,都有一个属性——不需要告诉它们目标缓冲区的大小,就产生一个字节序列。
对抗缓冲区溢出攻击
1、栈随机化
为了在系统中插入攻击代码,攻击者不但要插入代码,还要插入指向这段代码的指针,这个指针也是攻击字符串的一部分。产生这个指针需要知道这个字符串放置的栈地址。在过去,程序的栈地址非常容易预测,在不同的机器之间,栈的位置是相当固定的。
栈随机化的思想使得栈的位置在程序每次运行时都有变化。因此,即使许多机器都运行相同的代码。它们的栈地址都是不同的。
实现的方式是:程序开始时,在栈上分配一段0--n字节之间的随机大小空间。程序不使用这段空间,但是它会导致程序每次执行时后续的栈位置发生了变化。
在Linux系统中,栈随机化已经变成了标准行为。(在linux上每次运行相同的程序,其同一局部变量的地址都不相同)
2、栈破坏检测
在C语言中,没有可靠的方法来防止对数组的越界写,但是,我们能够在发生了越界写的时候,在没有造成任何有害结果之前,尝试检测到它。
最近的GCC版本在产生的代码中加入了一种栈保护者机制,用来检测缓冲区越界,其思想是在栈中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀值。这个金丝雀值是在程序每次运行时随机产生的,因此,攻击者没有简单的办法知道它是什么。
在恢复寄存器状态和从函数返回之前,程序检查这个金丝雀值是否被该函数的某个操作或者函数调用的某个操作改变了。如果是,那么程序异常终止。
3、限制可执行代码区域
限制那些能够存放可执行代码的存储器区域。在典型的程序中,只有保存编译器产生的代码的那部分存储器才需要是可执行的,其他部分可以被限制为只允许读和写。
现在的64位处理器的内存保护引入了”NX”(不执行)位。有了这个特性,栈可以被标记为可读和可写,但是不可执行,检查页是否可执行由硬件来完成,效率上没有损失。
2.针对不同数据类型,研究SQL注入点的发现与注入技术
SQL注入产生原因及威胁:
刚刚讲过当我们访问动态网页时, Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。
这种网站内部直接发送的Sql请求一般不会有危险,但实际情况是很多时候需要结合用户的输入数据动态构造 Sql 语句,如果用户输入的数据被构造成恶意 Sql 代码,Web 应用又未对动态构造的 Sql 语句使用的参数进行审查,则会带来意想不到的危险。
Sql 注入带来的威胁主要有如下几点:
- 猜解后台数据库,这是利用最多的方式,盗取网站的敏感信息。
- 绕过认证,列如绕过验证登录网站后台。
- 注入可以借助数据库的存储过程进行提权等操作
2.1 判断SQL注入点
通常情况下,可能存在 Sql 注入漏洞的 Url 是类似这种形式 :http://xxx.xxx.xxx/abcd.php?id=XX
对 Sql 注入的判断,主要有两个方面:
- 判断该带参数的 Url 是否存在 Sql 注入?
- 如果存在 Sql 注入,那么属于哪种 Sql 注入?
可能存在 Sql 注入攻击的 ASP/PHP/JSP 动态网页中,一个动态网页中可能只有一个参数,有时可能有多个参数。有时是整型参数,有时是字符串型参数,不能一概而论。总之只要是带有参数的 动态网页且此网页访问了数据库,那么就有可能存在 Sql 注入。如果程序员没有足够的安全意识,没有进行必要的字符过滤,存在SQL注入的可能性就非常大。
2.2 判断是否存在SQL注入漏洞
最为经典的单引号判断法:
在参数后面加上单引号,比如:
http://xxx/abc.php?id=1'
如果页面返回错误,则存在 Sql 注入。
原因是无论字符型还是整型都会因为单引号个数不匹配而报错。
注:如果未报错,不代表不存在 Sql 注入,因为有可能页面对单引号做了过滤,这时可以使用判断语句进行注入
2.3 判断SQL注入漏洞的类型
通常 Sql 注入漏洞分为 2 种类型:
- 数字型
- 字符型
- 搜索型
其实所有的类型都是根据数据库本身表的类型所产生的,在我们创建表的时候会发现其后总有个数据类型的限制,而不同的数据库又有不同的数据类型,但是无论怎么分常用的查询数据类型总是以数字与字符来区分的,所以就会产生注入点为何种类型。
2.3.1数字型判断:
当输入的参 x 为整型时,通常 abc.php 中 Sql 语句类型大致如下:
select * from <表名> where id = x
这种类型可以使用经典的 and 1=1
和 and 1=2
来判断:
Url 地址中输入 http://xxx/abc.php?id= x and 1=1
页面依旧运行正常,继续进行下一步。
Url 地址中继续输入 http://xxx/abc.php?id= x and 1=2
页面运行错误,则说明此 Sql 注入为数字型注入。
原因如下:
当输入 and 1=1
时,后台执行 Sql 语句:
select * from <表名> where id = x and 1=1
没有语法错误且逻辑判断为正确,所以返回正常。
当输入 and 1=2
时,后台执行 Sql 语句:
select * from <表名> where id = x and 1=2
没有语法错误但是逻辑判断为假,所以返回错误。
我们再使用假设法:如果这是字符型注入的话,我们输入以上语句之后应该出现如下情况:
select * from <表名> where id = 'x and 1=1'
select * from <表名> where id = 'x and 1=2'
查询语句将 and 语句全部转换为了字符串,并没有进行 and 的逻辑判断,所以不会出现以上结果,故假设是不成立的。
2.3.2字符型判断:
当输入的参 x 为字符型时,通常 abc.php 中 SQL 语句类型大致如下:
select * from <表名> where id = 'x'
这种类型我们同样可以使用 and '1'='1
和 and '1'='2
来判断:
Url 地址中输入 http://xxx/abc.php?id= x' and '1'='1
页面运行正常,继续进行下一步。
Url 地址中继续输入http://xxx/abc.php?id= x' and '1'='2
页面运行错误,则说明此 Sql 注入为字符型注入。
原因如下:
当输入 and '1'='1时,后台执行 Sql 语句:
select * from <表名> where id = 'x' and '1'='1'
语法正确,逻辑判断正确,所以返回正确。
当输入 and '1'='2时,后台执行 Sql 语句:
select * from <表名> where id = 'x' and '1'='2'
语法正确,但逻辑判断错误,所以返回正确。
2.3.3搜索型注入点:
emsp;这是一种特殊的注入类型。这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有“keyword=关键字”,有的不显示的链接地址,而是直接通过搜索框表单提交。
此类注入点提交的 SQL 语句,其原形大致为:
select * from 表名 where 字段 like '%关键字%'
当我们提交注入参数为“keyword='and[查询条件] and '%'=',则向数据库提交的完事SQL语句为:
select * from 表名 where 字段 like '%' and [查询条件] and '%'='%'
总结:
通过查找资料我对SQL注入有了一个大概得了解,也清楚了SQL注入的强大。sql注入常用技术有段还包括:
- 采用非主流通道技术
- 避开输入过滤技术
- 使用特殊的字符
- 强制产生错误
- 使用条件语句
- 利用存储过程
- 推断技术
- ........
3.研究缓冲区溢出的防范方法,至少针对两种编程语言进行差异化研究
检测方法及防范措施;
根据缓冲区溢出攻击的步骤, 可将常用的缓冲区溢出攻击检测技术分为以下 3 种类型:
- 基于输入字符串的检测方法
- 基于保护堆栈中的返回地址的检测方法
- 基于监视系统调用的检测方法。
3.1 基于输入字符串的检测方法
对输入的字符串进行检测,确定其为溢出攻击字符串时采取阻拦措施,使攻击者无法注入攻击代码。一般有以下3种方法构建溢出攻击字符串。如下图所示:
缓冲区大于 ShellCode 长度:
缓冲区小于 ShellCode 长度:
将 ShellCode 放在环境变量里:
第 1 种溢出攻击字符串适用于缓冲区大于 ShellCode 长度的情况; 第 2 种溢出攻击字符串一般用于缓冲区小于 ShellCode 长度的情况; 第 3 种方法是将 ShellCode 放在环境变量里,是目前较为常用的方法。
在第 1 种和第 2 种类型的溢出攻击字符串中 ShellCode 前都加了若干的 NOP指令, 因为这 2 种情况下 ShellCode 的地址无法确定, 但只要返回地址指向 ShellCode 前的任一条NOP 指令, ShellCode 就可以执行,大大增加了 ShellCode 执行的可能性。这些 NOP指令称为 sledge 。其他单字节指令如 AAA 等也可构成 sledge 。因此缓冲区溢出攻击检测系统可以通过检查输入的字符串中是否含有大量 NOP等可构成 sledge 的指令来判断此字符串是否是溢出攻击字符串。不过这种方法并不适用于检测第 3 种类型的攻击。但这 3 种类型的攻
击字符串中都含有 ShellCode 。因此,确定出 ShellCode 的基本特征 , 如不含有“ 0x00”,含有某些特殊的系统调用等, 然后利用人工智能、 模式匹配、 规则匹配等方法检查输入字符串中是否包含 ShellCode 也可检测出是否有缓冲区溢出攻击发生。这些检测都可以在入侵检测等外围防御系统中实现, 优点是实现较为简单, 不会增加被保护系统的开销; 缺点是漏报率较高,无法检测出无明显特征的溢出攻击字符串。
3.2 基于保护堆栈中返回地址的检测方法
缓冲区溢出攻击最关键的步骤是要通过修改函数返回地址来改变程序的流程, 因此, 在函数调用返回前, 通过检查返回地址是否被修改可以判断是否有缓冲区溢出攻击发生。 该检测的实现可以通过在源码中插入一些约束和判断的模块, 然后在编译后的程序运行期间对有关变量和堆栈区域进行监控,检测是否有攻击发生。 StackGuard 和StackShield 就是这一类型的工具,它们都是 gcc 编译器的扩展工具,用于监控调用的函数返回地址是否正常。StackGuard 主要是在内存中的返回地址及缓冲区之间插入一个 “Canary ” 字, 如图所示。
在函数调用返回前通过检查 “Canary” 字来判断返回地址是否已经被修改, 如果这个 Canary的值被改变了, 说明可能有人正进行缓冲区溢出攻击, 程序会立刻响应, 发送一则入侵警告消息, 然后停止工作。为防止攻击者构造 Canary”字, StackGuard 选用“终止符”和 “随机数”作为“ Canary”字的值。但由于“ Canary ”字所在的位置是固定的,因此也可能被绕过StackShield 对此作了改进, 创建了一个新的堆栈用于备份被保护函数的返回地址。 它在被保护函数开始处增加一段代码, 用来将函数返回地址拷贝到一张特殊的表中; 同样在被保护函数的结尾处也增加一段代码, 用来将函数返回地址从表中拷贝回堆栈。 从而保证函数正确返回。
3.3 基于监视系统调用的检测方法
如果攻击者成功注入攻击代码,并改变了程序的执行流程使指令的执行指针指向了ShellCode 的入口地址。 按照一次缓冲区攻击的 3 个步骤, 还须执行 ShellCode 来完成攻击目的。因此,通过检测是否有 ShellCode 运行可以检测是否发生缓冲区溢出攻击。攻击者既希望 ShellCode 利用获得的权限启动一个交互式的 shell 进程来完成尽量多的事情,又希望 ShellCode 尽量短小从而更加隐蔽,所以绝大多数 ShellCode 都会调用系统函数。 由于监视所有系统调用会耗费大量系统资源, 因此只对 ShellCode 常用的系统调用进行监视, 根据某些特征判断受监视的系统调用是否为非法调用就可确定被保护系统是否遭到缓冲区溢出攻击。例如,如果发现系统调用的返回地址为堆栈,则可认为其为非法调用,因为很少有程序在堆栈上运行代码。
缓冲区漏洞的防范措施
上面三种方法是针对如何检测已经发生的缓冲区漏洞, 方法虽然多, 但是相对比较麻烦, 所以我们最好能从根本上防范它,防止缓冲区漏洞的发生。首先在编写程序过程中, 程序员有责任和义务养成安全编程的思想, 应该熟悉那些可能会产生漏洞或需慎用的函数,清楚那些在编程中要小心使用的函数 ( 特别是在使用 C语言时 ) ,例如: gets() 、 strcpy() 等等。在软件测试阶段,要专门对程序中的每个缓冲区作边界检查和溢出检测。但是,由于程序编写者的经验不足和测试工作不够全面、充分,目前还不可能完全避免缓冲区溢出漏洞,因此这些漏洞在已经使用以及正在开发的软件中还是有存在的可能,还需要在使用软件时,对它做实时的监测。
其次是使用安全语言编写程序, 应使用 Java等安全的语言编写程序, 因为 Java在对缓冲区进行操作时,有相应的边界检查,所以可以有效地防止缓冲区溢出漏洞的产生。但是, Java也并非绝对安全, Java的解释器是用 C语言编写的,而 C并不是一种安全的语言,所以 Java解释器还是可能存在缓冲区溢出漏洞并受到攻击。最后可以通过改进编译器,它的主要思想是在编译器中增加边界检查以及保护堆栈的功能,使得含有漏洞的程序和代码段无法通过编译。 针对 gcc编译器的很多补丁就提供了这些功能,比如说 Stackguard 等等。
4.数据库注入攻击工具
BSQL Hacker
BSQL Hacker是由Portcullis实验室开发的,BSQL Hacker 是一个SQL自动注入工具(支持SQL盲注),其设计的目的是希望能对任何的数据库进行SQL溢出注入。 BSQL Hacker的适用群体是那些对注入有经验的使用者和那些想进行自动SQL注入的人群。BSQL Hacker可自动对Oracle和MySQL数据库进行攻击,并自动提取数据库的数据和架构。
Sqlmap
Sqlmap是一个自动SQL 注入工具。其可胜任执行一个广泛的数据库管理系统后端指纹,
检索DBMS数据库、usernames、表格、列、并列举整个DBMS信息。Sqlmap提供转储数据库表以及MySQL、PostgreSQL、SQL Server服务器下载或上传任何文件并执行任意代码的能力。
sqlsus
sqlsus是一个开放源代码的MySQL注入和接管工具,sqlsus使用perl编写并基于命令行界面。sqlsus可以获取数据库结构,注入你自己的SQL语句,从服务器下载文件,爬行web站点可写目录,上传和控制后门,克隆数据库等。