SQL注入是因为后台SQL语句拼接了用户的输入,而且Web应用程序对用户输入数据的合法性没有判断和过滤,前端传入后端的参数是攻击者可控的,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。比如查询、删除,增加,修改数据等等,如果数据库的用户权限足够大,还可以对操作系统执行操作。
SQL注入可以分为平台层注入和代码层注入。前者由不安全的数据库配置或数据库平台的漏洞所致;后者主要是由于程序员对输入未进行细致地过滤。SQL注入是针对数据库、后台、系统层面的攻击!
mysql中注释符:# 、/**/ 、 --
依据注入点类型分类
数字类型的注入
字符串类型的注入
搜索型注入
依据提交方式分类
GET注入
POST注入
COOKIE注入
HTTP注入(XFF注入、UA注入、REFERER注入)
XFF:X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。
UA:用户代理(User Agent,简称 UA),是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
REFERER:HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。
依据获取信息的方式分类
基于布尔的盲注
基于时间的盲注
基于报错的注入
联合查询注入
堆查询注入(可同时执行多条语句)
工具扫描:网站漏扫工具、AWVS、AppScan、OWASP-ZAP、Nessus等
手动测试:
单双引号、括号;进行组合测试,看是否报错
对于数字型:?id=3-1 ?id=2#
如果显示的是?id=2时的正常页面,可判断注入点是数字型注入;如果返回不正常,则可判断非数字型注入
对于字符型:?id=2a ?id=2'#
Mysql 中,等号两边如果类型不一致,会发生强制类型转换。当数字与字符串进行比较时, 首先先将字符串转换成数字,然后再进行比较。
对于布尔盲注:
盲注:就是在服务器没有错误回显时完成的注入攻击。服务器没有错误回显,对于攻击者来说缺少了非常重要的信息,所以攻击者必须找到一个方法来验证注入的SQL语句是否得到了执行。
?id=1' and '1 ?id=1' and 'a
这里没有使用注释符号进行后面的单引号闭合,使用的是手工单引号闭合
或者, ?id=1' and 1=1# ?id=1' and 1=2#
两者的页面截然不同,一个正常回显,一个没有回显的话,就可判断是布尔盲注。
对于时间盲注:
?id=1' and sleep(3)#
在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。 Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。
因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要 长,通过时间长短的变化,可以判断注入语句是否执行成功。这是一种边信道攻击,这个技巧在 盲注中被称为Timing Attack,也就是时间盲注。
常见SQL注入功能点
只要是存在数据库交互的地方都有可能出现 SQL 注入。
常出现在 登录页面、订单页面、文章或新闻展示页面、修改密码页面(二次注入)、涉及获 取 HTTP 头(XFF等)的功能点等。
必备
元数据库 information_schema
元数据库 information_schema 中: 存放数据库信息的表:schemata schemata 表中 字段 schema_name 存放所有数据库名; 存放表信息的表:tables tables 表中 字段 table_name 存放所有表名 字段 table_schema 存放所有表所在的数据库名; 存放所有字段信息的表:columns columns 表中 字段 column_name 存放所有字段名, 字段 table_name 存放所有字段所在的表名, 字段 table_schema 存放所有字段所在的数据库名;
语句分类
1.DQL(数据查询语言):查询语句,所有的 select 语句 2.DML(数据操作语言):insert , delete , update , 对表中的 数据 进行 增删改 3.DDL(数据定义语言):create , drop , alter 对表 结构 的 增删改 4.TCL(事务控制语言):commit 提交数据,rollback 回滚数据 Transaction 5.DCL(数据控制语言):grant 授权,revoke 撤销权限等
基本语句
# 查库: show databases; select schema_name from information_schema.schemata; # 建库: create database + 库名; # 删库: drop database + 库名; # 进入数据库: use + 库名; # 查表: show tables; select table_name from information_schema.tables where table_schema='security' select table_name from information_schema.tables where table_schema=database # 查列: select * from users; select column_name from information_schema.columns where table_name='users' # 查字段: select username,password from security.users;
基本函数
#数据库安装、路径,用户 信息 version(); Mysql 数据库版本 database(); 当前 数据库名 user(); 数据库的用户名 current_user(); 当前用户名 session_user(); 连接到数据库的用户名 system_user(); 系统用户名 @@datadir(); 数据库文件的存放路径 @@version_compile_os; 操作系统版本 @@basedir; 数据库的安装目录 #字符串长度、截取 length(); 返回字符串的长度 substring(a,b,c); 截取字符串 substr(a,b,c); mid(a,b,c); 三个参数:a.截取的字符串 b.截取的起始位置 c.长度 left(a,b); 从左侧截取a的前b位,正确返回1,错误返回0 #字符串配对连接 concat(a,0x5e,b); 字符串配对连接 concat_ws('~',A,B); 含有分隔符的连接字符串 group_concat(); 将字符串连接为一个组,可将不同列分到同一行中 #字符串特殊处理 ord(); 返回ASCII码 ascii('a'); 将字母 a 转换为ascii值 rand(); 返回0~1之间的随机浮点数 round(); 返回最近的整数值 md5(); 返回MD5值 hex(); 将字符串转换为十六进制 unhex(); hex()的反向操作 floor(x); 返回不大于x的最大整数 load_file(); 读取文件,返回文件内容作为一个字符串 sleep(a); 沉睡a秒 if(true,t,f); 判断语句为true ,执行第一个,否则第二个 find_in_set(); 返回字符串在字符串列表中的位置 benchmark(); 指定语句执行的次数 name_const(); 返回表作为结果
导入数据
当希望导入一个 较大 的文件或者是想要批量的执行sql语句时,可以使用 mysql 中的 source 使用方法:source + 文件路径(直接拖拽)
语句
# insert insert into 表名(字段名1,字段名2,字段名3......) values(值1,值2,值3......); # delete delete from 表名 where 条件;//可回滚 对于大表: truncate table 表名;//不可回滚,将会永久丢失 # update update 表名 set 字段名1=值1,字段名2=值2,......where 条件;
# select select 字段1,字段2,...... from + 表名 where + 条件;
# between and select * from users where id between 2 and 8; select * from users where id >=2 and id <=8;
# in not in select password from users where id not in(5,8); 指查找出 id不等于5 和 id不等于8 的用户的密码 注:不是 5~8,in之后不是一个区间
# like 1.% 代表任意多个字符 2._ 代表任意一个字符 select username from users where username like '%b%'; 指查找出用户名中带有字母b的用户名 select username from users where username like '_a%'; 指查找出用户名中带第二个字母为a的用户名 select username from users where username like '%b'; 指查找出用户名中带最后一个字母为b的用户名 select username from users where username like '%\_%'; 指查找出用户名中带有下划线_的用户名 注:特殊字符需要转义
# order by select username from users order by 字段名; 注:默认为升序排列 指定升序:asc select username from users order by 字段名 asc; 指定降序:desc select username from users order by 字段名 desc; 双重需求: select username from users order by 字段名1 desc,字段名2 asc;
# 分组函数 select sum(grade) from users; select avg(grade) from users; select max(grade) from users; select min(grade) from users;
# 空处理函数 select sum(ifnull(salary,0)*12), from crew; 求一年的薪水之和,当薪水为NULL时,被当作0来处理
# group by 与 having group by:按照某个字段或某些字段进行分组 having:对分组之后的数据进行再次过滤,即having 必须跟在 group by 后面使用 select max(grade) from students group by classes; 先根据班级分组,再查出各个班级的成绩最高学生的成绩 1.分组函数一般与 group by 联合使用,并且任何一个分组函数(count,sum,avg,max,min)都是堆一组数据进行操作的 2.当一条sql语句没有 group by 时,整张表会自成一组 3.当sql语句中使用group by时,select之后只能跟参与分组的字段或者分组函数
# distinct 去重 distinct 关键字 去除重复记录 select distinct job from company; 查询该公司中的工作岗位
# 语句执行顺序 select 5号:挑选出满足条件的数据 from 1号:定表 where 2号:过滤原始数据 group by 3号:进行分组 having 4号:对数据进行再次过滤 order by 6号:进行排序
1.字符串数据 sum,avg 为 0,max,min 按字母大小取 2.分组函数会自动忽略 NULL 3.数学运算 中如果有NULL参与,结果为定为NULL 4.分组函数不能直接出现在 where 后面,原因是 group by 是在where语句执行结束之后执行的 5.分组函数可组合使用
# inner join select a.ename,b.dname from emp a join dept b on a.deptno=b.deptno; # left/right join select dname,ename from dept a left join emp b on a.deptno=b.deptno;
or 语句:当前面语句不符合情况或者出现错误时执行or后面的内容