sql注入的基础知识
相关知识
information_schema库
MYSQL在5.0版本后,默认会在数据库中存放一个叫”information_schema”的数据库。这个数据库保存了MYSQL中所有数据库的信息,数据库名、数据库的表名、数据库中的表的列名以及访问权限等。
这里需要知道的表有三个: SCHEMATA、TABLES和COLUMNS
其中SCHEMATA表中的SCHEMA_NAME记录了所有数据库的名字
TABLES表中的TABLE_SCHEMA和TABLE_NAME两个字段分别记录了数据库的库名和表名。
COLUMNS表中存储该用户创建的所有数据库的库名、表名和字段名,TABLE_SCHEMA记录了库名、TABLE_NAME记录了表名、COLUMN_NAME记录了字段名。
MYSQL的查询语句
不知道任何条件时
1
select column_name from schema_name.table_name;
其中
column_name
是要查询的字段名,schema_name
是库名,table_name
是表名知道一条已知条件时
1
select column_name from schema_name.table_name where column_name1=’some_value’;
其中
column_name1
是已知条件的字段名知道两条已知条件时
1
select column_name from schema_name.table_name where column_name1 = ‘some_value’ and column_name2 = ‘some_value’;
常用函数
database()
: 返回当前数据库名user()
:返回MYSQL当前用户名version()
:返回MYSQL的版本concat()
:联合数据,用于联合两条数据结果。concat(userid,0x3a,username)
group_concat()
:和concat()
类似,用于将多条数据一次注入出来hex()
和unhex()
:用于hex编码和解码load_file()
:以文本方式读取文件
注释
行间注释:– 和 #
1 | select * from user;- |
行内注释:/*注释内容*/
和 /*! MYSQL专属*/
其中MYSQL专属的内联注释可以用于整个SQL语句中,其中的SQL代码也会被执行。
1 | select table_schema,table_name,column_name from columns /*! union* / select 1,2,3; |
limit
limit会返回前面几条或者中间几条数据
1 | select * from user limit m,n |
其m指记录从0开始的第m+1条记录, n指从第m+1条开始取n条记录
对sql注入的一些理解
加单引号和加 and 1=2有什么区别?
有区别,单引号是为了闭合语句,而and 1=2是为了让union前面的语句无查询结果无输出,然后直接输出拼接进去union后面的那个语句的查询结果;
and 是什么意思?
and 为和的意思,一个语句中,当前一个正确,后一个错误时,如果是and连接整个语句返回的是False;
or是什么意思?
or 为和的意思,一个语句中,当前一个正确,后一个错误时,如果是or连接整个语句返回的是True
and 和 or 选择使用有什么讲究?
and 语句执行时,如果and 前的语句返回False,那么and后面的语句根本不执行;
limit的作用
limit在注入中用于排序然后输出,limit a,b中。a代表从哪个位置(从0开始),b代表从那位开始显示几条数据
sql的注释
注释后面的语句,防止sql注入点后原本的sqk语句对sqk注入进行干扰。
%23
编码为#,mysql数据库特有的。把后面的语句全部注释掉
--+
把后面的语句全部注释掉
/**/
内联注释,注释指定部分。需要一前一后闭合,所以在传参那里几乎不做注释语句用,而是用于过滤空格等bypass
1 | ?id=-1'/**/union/**/select/**/1,2,database()--+ //过滤空格,用/**/代替空格 |
闭合是什么?
在sql查询中,代码比较严谨,括号和引号都得成双成对,引号内的默认是字符串不会当作SQL语句执行,所以必须闭合然后才能注入,当然有些SQL语句直接拼接,也就不用什么闭合了;
mysql数据库常用函数与参数
>, >=, <, <=, = | 比较运算符 |
---|---|
and, or | 逻辑运算符 |
version() | mysql数据库版本 |
database() | 当前数据库名 |
sleep() | 睡眠时间为指定的秒数 |
if(true,t,f) | if判断 |
length() | 返回字符串的长度 |
substring() , substr() , mid() | 截取字符串.三个函数作用相同 有三个参数 mid(“1”,2,3) 1.截取的字符串 2.截取起始位置,从1开始计数 3.截取长度 |
left() | 从左侧开始取指定字符个数的字符串 |
concat() | 没有分隔符的连接字符串 |
concat_ws() | 含有分割符的连接字符串 |
group_conat() | 连接一个组的字符串 |
ascii() , ord() | 返回ASCII码 |
hex() | 将字符串转换为十六进制 |
unhex() | hex的反向操作 |
md5() | 返回MD5值 |
floor() | 返回不大于x的最大整数 |
round() | 返回参数x接近的整数 |
rand() | 返回0-1之间的随机浮点数 |
load_file() | 读取文件,并返回文件内容作为一个字符串 |
find_in_set() | 返回字符串在字符串列表中的位置 |
benchmark() | 指定语句执行的次数 |
name_const() | 返回表作为结果 |
user() | 用户名 |
current_user() | 当前用户名 |
system_user() | 系统用户名 |
@@datadir | 数据库路径 |
@@version_compile_os | 操作系统版本 |
判断注入点
0. 判断闭合
在参数后面加单引号报错,并且如果加上注释的话可以正常显示,就是单引号闭合的。
1 | ?id=1' //报错 |
+号的含义,使用 – (有个空格),在传输过程中空格会被忽略,同样导致无法注释,所以在get请求传参注入时才会使用 –+ 的方式来闭合,因为 + 会被解释成空格。
1. 字符型
加单引号
在参数后面直接添加单引号,显示数据库错误信息或者页面回显不同说明存在注入点。
同时我们可以看到我们提交的参数两边是有单引号包裹的,所以我们可以判断出注入点的类型是字符型,单引号闭合。
1 | ?id=1' |
出错位置在 ''1''LIMIT 0,1'
2. 数字型
如果传入的参数没有在报错信息中显示,则是数字型。
出错位置在'' LIMIT 0,1'
还可以通过在id后添加运算符,比如-1,+2,这样来观察页面的内容是否会变成对应的id 来判断注入的类型。
注意运算符要进行URL编码
1 | ?id=1%2B1 //1+1 |
可以发现,id=1+1
和 id=2
显示的页面是一样的
判断显示位
知道了当前表的列数我们就开始判断第几列的内容会显示到页面中来。
需要显示位的注入方式: union联合查询注入
没有回显时可以用的注入方式: 报错注入、布尔注入、时间盲注
构建union select语句时,当前面的查询语句为假,也就是数据不存在时,union select之后查询出的结果就会显示在页面中。这里我们可以通过在前面查询语句中添加 and 1=2 使语句变假,也可以直接将id传入一个负数,来使语句变假。
1 | ?id=-1' union select 1,2,3 --+ |
修改显示位的个数,直到能正常显示。
说明显示位是第2位和3位。
(后续就可以利用这两个显示位,把数字2,3换成其他查询语句,获取自己想要的内容,比如database(), version() )
逻辑运算
利用布尔盲注。有时需要一些语句的真假逻辑,这时可以利用 and 1=1
表示真。and 1=2
表示假。
添加了逻辑运算符之后提交,因为1=1恒为真,而1=2恒为假,所以如果我们的输入带入了数据库,一定会影响到SQL语句的布尔状态,如果两次查询返回的页面不同,说明页面存在布尔状态,此处存在注入漏洞,可以考虑使用布尔盲注进行注入。
判断字段数
输入1’ order by 1 --+
,显示正常
输入1’ order by 2 --+
显示正常
输入1’ order by 3 --+
,查询失败
说明字段数只有两列。
寻找注入点
get请求注入
提交数据的方式是GET请求,注入点的参数位于GET参数部分。
1
http://www.demo/com/index.php?id=1
post请求注入
提交数据的方式是POST请求,注入点位于POST数据内,通常发生在表单里
cookie注入
注入点的参数位于cookie中
http头注入
注入点位于HTTTP请求头部中的某个字段,例如User-Agent字段中。
常见http注入的参数:
1
2
3
4
5
6
7
8
9
10HTTP_CLIENT_IP
'HTTP_X_FORWARDED_FOR'
'HTTP_X_FORWARDED'
‘HTTP_X_CLUSTER_CLIENT_IP’
‘HTTP_FORWARDED_FOR’
‘HTTP_FORWARDED’
‘REMOTE_ADDR
User-agent
Referer
X-Forwarded-For
sql注入防御
- SQL语句预编译和绑定变量
- 设置好数据库用户的权限
- 使用严格的过滤
- str_replace()替换过滤
- addslashes()函数,添加转义字符
- 过滤常见危险字符串
- htmlspecialchars()函数实体化过滤