Sqlmap速查表/功能移植/Python批量检测SQL注入


title: Sqlmap速查表与Python进行功能移植
copyright: true
top: 0
date: 2021-02-27 11:59:00
tags: [扫描注入,注入,sqlmap]
categories: 安全开发
permalink:
password:
keywords:
description: Sqlmap速查,对其WAF识别功能移植,对其Sql注入的payload进行移植,完成Python批量检测SQL注入。

今天的剑桥对我而言只是一百年前那个剑桥的幻影,但我还会不由自主地、一次又一 次地回那里去。站在那里我仍会觉得温暖,隐约闻到一百年前的气息,记忆中的白绸长 裙和牛津式白底高跟鞋又鲜明起来。

阅读提要

全文约9K字,大致阅读完约10分钟,包含主要知识点:Sqlmap常用命令python调用SqlmapApi进行批量扫描Python移植Sqlmap的WAF识别功能并拓展Python完成Sql注入漏洞扫描Python移植Sqlmap的Payload分析,其中关键部位文字使用橙色重点标注,网址使用绿色重点标注。

目录:

  • Sqlmap常用命令
  • SqlmapApi常用方法
  • 移植Sqlmap的WAF识别功能与拓展
  • 批量Sql注入识别之Python检测报错型
  • 批量Sql注入识别之sqlmap命令检测
  • 批量Sql注入识别之封装整个sqlmap验证
  • 批量Sql注入识别之移植sqlmap的payoad识别

SQLMAP常用命令

使用Sqli-Labs搭建SQL注入靶场进行练习,靶场练习下载地址,手工注入练习地址

基础检测语法

python sqlmap.py -u  http://127.0.0.1/sqli/Less-1/?id=1 

批量检测

将动态链接保存在文本中,然后使用sqlmap的命令进行批量的扫描

  • target.txt

python sqlmap.py -m target.txt

注意target.txt跟sqlmap在同一个目录下,或者额外指定路径也可以,另外批量检测需要手动确认,这个时候添加–batch命令即可自动确认。

站点爬取

python sqlmap.py -u http://www.langzi.fun --batch --crawl=3

使用sqlmap自带的爬虫功能对网址进行爬行后,自动判断注入,但是sqlmap的爬虫不是很值得信赖…当然知道这条命令肯定没错的啦

使用hex避免字符编码导致数据丢失

有些时候因为数据库或者穿输编码的问题,有些结果无法显示出来,这个时候可以进行编码后查看数据

python sqlmap.py -u "http://127.0.0.1/sqli/Less-1/?id=1" --banner –hex -v 3 –parse-errors  

模拟测试手机环境站点

某些时候服务器会对请求的数据请求头判断,只会接受来自手机移动端的数据,这个时候就可以使用命令模拟收集请求

python sqlmap.py -u "http://127.0.0.1/sqli/Less-1/?id=1" –mobile  

智能判断测试

自动智能测试,常用在批量识别注入的地方

python sqlmap.py -u "http://127.0.0.1/sqli/Less-1/?id=1" -–batch –smart 
python sqlmap.py -m target.txt  -–batch –smart 

结合burpsuite进行注入

有些注入点可能存在请求头中,比如浏览器头信息,链接的IP地址等等,这个时候对请求抓包后,保存在文本中,使用sqlmap对其进行注入检测。

python sqlmap.py -r 数据包.txt  

sqlmap 自动填写表单注入

如果网页由输入框,登录框等,可以使用自带的自动填写表单测试注入

python sqlmap.py -u URL –forms

延时注入

python sqlmap.py -u "http://127.0.0.1/sqli/Less-1/?id=1" --delay 0.5 --dbs

延迟0.5秒后发起请求

可以看到请求时间延长

sqlmap版本小坑

在批量扫验证的时候,发现不同版本号扫描的结果不一样,1.2.11.6版本可以扫出来数据,但是1.3.4版本就没办法,在网上有师傅指出问题出在:

经过分析,两坑如下:
(1)v1.2.11(/v1.2.10/v1.2.9/master)的boundaries.xml没有了针对模糊查询(%)的测试,而v1.2(/v1.1.12/1.1.4/1.2.2)则有。
(2)v1.2.11(/v1.2.10/1.2.9/master)必须手动设置json的某个参数为*才能对这个参数进行注入,否则payload直接跟在json后导致无法注入,而v1.2(/v1.1.12)则可以默认回车(y)即可对json的某个参数注入。

Python调用SqlmapApi进行自动化批量扫描

sqlmapapi使用的是bottle web框架,与flask类似,但是更加精简。

首先开启sqlmapapi服务

python sqlmapapi.py -s

输出结果大致如下:

C:\Users\Administrator\Desktop>sqlmapapi.py -s
[15:42:37] [INFO] Running REST-JSON API server at '127.0.0.1:8775'..
[15:42:37] [INFO] Admin ID: 1624e1c613cf56c1afe4241b28487b4d
[15:42:37] [DEBUG] IPC database: 'c:\users\administrator\appdata\local\temp\sqlmapipc-fh0y03'
[15:42:37] [DEBUG] REST-JSON API server connected to IPC database
[15:42:37] [DEBUG] Using adapter 'wsgiref' to run bottle
[15:42:41] [DEBUG] Created new task: '4ebbb121a16a47ab'

根据输出结果,可以明白bottle开启的服务地址为

http://127.0.0.1:8775

Admin ID 是用来管理 task 所用的,每次开启 sqlmapapi 都会改变,可以通过修改源码的方式将其固定,或是写入文件供其他程序读取。

这里只是开启了服务,进一步需要创建任务,每个注入点对应不同的id。

创建任务方法如下:

r = requests.get(url='http://127.0.0.1:8775/task/new')
print(r.json())

此时会返回一个json

{u'success': True, u'taskid': u'4ebbb121a16a47ab'}

代表创建任务成功,后面的id值就是创建任务的时候该任务对应的唯一id值。

注意:每次发送请求返回的id值都是不一样的。

然后发送一个 链接过去 ,sqlmapapi自动判断是否存在注入。

我这里先用phpstudy搭建apache环境,安装好了sqli labs

使用的链接是

url = 'http://127.0.0.1/sqli/Less-1/?id=1'

代码实现如下:

# -*- coding:utf-8 -*-
import requests, json, time
def scan_sql(url):
    r = requests.get(url='http://127.0.0.1:8775/task/new')
    task_id = r.json()['taskid']
    sqlmap_set = 'http://127.0.0.1:8775/option/%s/set' % task_id
    sqlmap_url = 'http://127.0.0.1:8775/scan/%s/start' % task_id
    sqlmap_status = 'http://127.0.0.1:8775/scan/%s/status' % task_id
    sqlmap_result = 'http://127.0.0.1:8775/scan/%s/data' % task_id
    set = requests.post(url=sqlmap_set, data=json.dumps({'url': url}), headers={'Content-Type': 'application/json'})
    scans = requests.post(url=sqlmap_url, data=json.dumps({'url': url}), headers={'Content-Type': 'application/json'})
    r = requests.get(sqlmap_status).json()['status']
    print('当前运行状态:{}'.format(r))
    while 1:
        if requests.get(sqlmap_status).json()['status'] == 'running':
            # 当前表示正在跑数据
            time.sleep(10)
            # 每十秒钟请求一次扫描状态
        else:
            print(requests.get(sqlmap_status).json()['status'])
            if 'terminated'==requests.get(sqlmap_status).json()['status']:
                re = requests.get(url=sqlmap_result)
                print('当前网址扫描完毕')
                print(re.json())
                return re.json()

scan_sql('http://127.0.0.1/sqli/Less-1/?id=1')

Python移植Sqlmap的WAF识别功能并拓展

在扫描器开发过程中,对传入的网址进行waf检测识别是很重要的,参考sqlmap源码后,直接移植其中的waf识别功能。

- 优点:直接移植,简单方便
- 缺点:sqlmap中大多数waf都是国外的
- 补充: 移植代码后,可拓展性非常高,阅读完此文小学生坐在马桶上都会

代码阅读

在sqlmap的waf目录下,有45个py文件,除了一个初始化文件其他的都是waf检测插件,随便打开几个看看。

分析代码

可以发现所有的函数都传入一个值get_page,然后定义retval为假。

上面这两个比较好理解,即传入一个网页,获取这个网页的内容和头部信息,然后retval这个值是用作判断是否存在这个waf,如果retval为真就说明存在此waf,如何才能让retval为真呢?自然是在网页的内容和头部信息中检测了,检测确认存在该waf的判别方式。

移植思路

在sqlmap中检测waf的方式是传入一个网址,获取网址内容与头部信息,然后检测是否存在该waf的特征值,如果存在,就让retval为真并且返回这个值。因为一个waf的检测方法有好几种,比如在网页中匹配特征码,或者在网页的头部信息中匹配特征码,那么对应的waf字典数据结构应该是这样的。

{'360':[
'retval = re.search(r"wangzhan\.360\.cn", headers_get, re.I)',
'retval = "/wzws-waf-cgi/" in (page_get)'
],
'airlock':[
'retval = re.search(r"\AAL[_-]?(SESS|LB)=",headers_get, re.I)'
],
'anquanbao':[
'retval = re.search(r"MISS", headers_get, re.I)',
'retval = "/aqb_cc/error/" in (page_get)'
],
'armor':[
'retval = "This request has been blocked by website protection from Armor" in (page_get)'
]}

即在字典中,waf的名字是键,对应的检测方法为值,并且把检测方法的结果赋值给retval,如果检测waf存在,那么retval就为真。

完成代码

其实看完waf检测的字典就清楚我的思路是什么,循环迭代键值,如果返回的值(retval)为真,就说明存在改waf,这个时候在返回字典的键也就是waf名字。

其中headers_get是传入网页的头部信息,page_get是传入网页的内容。

正常的页面中一般不可能出现waf关键词的,但是让页面报错的话,就能检测出waf的关键词,这就好比打开一个网站,随便输入一些错误的字符串,在返回的body或者headers会反馈waf信息。

比如在一个正常的网址后面加上一个很明显的payload

/list.php?k=1?aspx?id=1?"download.asp=manage.mdb" and 1=1 union select user from admin%23<script>alert(1)</script>

比如下面的案例中存在加速乐的防火墙,是根据关键词识别

对应指纹中:

一一对应则确认存在的防火墙与防火墙类型。

以及会在请求头中出现关键词

对应指纹库中的关键词对比,则判断出存在的防火墙

提及一下稍微有一个小知识点,python的exec与eval,都是把字符串当代码执行,但是前者可以进行一些深度的运算,比如计算数值加减,正则匹配等等,后者只能进行打印,即前者的权限比较大,什么都可以执行,后者只能执行一些普通的操作。

详细代码如下,如果要套进扫描器的话。可以把代码封装在一个函数里面,只接受一个参数(正常的网址)即可。

poc-T找到部分waf的相关返回结果,对代码重新整理一下。

# -*- coding:utf-8 -*-
# __author__:langzi
# __blog__:www.langzi.fun
import requests
import re


def scan_waf(uul):
    urls = uul + '/list.php?k=1?aspx?id=1?"download.asp=manage.mdb" and 1=1 union select user from admin%23<script>alert(1)</script>' if uul.startswith(
        'http') else 'http://' + uul + '/list.php?k=1" manage.mdb" and 1=1 union select user from admin%23<script>alert(1)</script>'
    print('检测WAF:{}'.format(urls))
    try:
        r = requests.get(url=urls, timeout=5)
        # encoding = requests.utils.get_encodings_from_content(r.text)[0]
        # page_get = r.content.decode(encoding, 'replace')
        page_get = r.content
        headers_get = str(r.headers)
    except Exception as e:
        print(e)
    waf_dic = {'360': [
        're.search(b"wangzhan\.360\.cn", headers_get, re.I)',
        '"/wzws-waf-cgi/" in (page_get)',
        '"360.cn" in (page_get)',
        '"360.cn" in headers_get'
    ],
        'airlock': [
            're.search(b"\AAL[_-]?(SESS|LB)=",headers_get, re.I)'
        ],
        'anquanbao': [
            're.search(b"MISS", headers_get, re.I)',
            '"/aqb_cc/error/" in (page_get)'
        ],
        'armor': [
            '"This request has been blocked by website protection from Armo" in (page_get)'
        ],
        'aws': [
            're.search(b"\bAWS", headers_get,re.I)'
        ],
        'baidu': [
            're.search(b"fhl", headers_get, re.I)',
            're.search(b"yunjiasu-nginx", headers_get,re.I)'
        ],
        'barracuda': [
            're.search(b"\Abarra_counter_session=",headers_get, re.I)',
            're.search(b"(\A|\b)barracuda_",headers_get, re.I)'
        ],
        'bigip': [
            're.search(b"\ATS\w{4,}=",headers_get, re.I)',
            're.search(b"BigIP|BIGipServe",headers_get, re.I)',
            're.search(b"BigIP|BIGipServe", headers_get,re.I)',
            're.search(b"\AF5\Z", headers_get,re.I)'
        ],
        'binarysec': [
            're.search(b"BinarySec", headers_get,re.I)'
        ],
        'blockdos': [
            're.search(b"BlockDos\.net", headers_get,re.I)'
        ],
        'ciscoacexml': [
            're.search(b"ACE XML Gateway", headers_get,re.I)'
        ],
        'cloudflare': [
            're.search(b"cloudflare-nginx", headers_get,re.I)',
            're.search(b"\A__cfduid=",headers_get, re.I)',
            're.search(b"CloudFlare Ray ID:|var CloudFlare=", page_get)'
        ],
        'cloudfront': [
            're.search(b"cloudfront", headers_get,re.I)',
            're.search(b"cloudfront", headers_get,re.I)'
        ],
        'comodo': [
            're.search(b"Protected by COMODO WAF", headers_get,re.I)'
        ],
        'datapower': [
            're.search(b"\A(OK|FAIL)", headers_get, re.I)'
        ],
        'denyall': [
            're.search(b"\Asessioncookie=",headers_get, re.I)',
            're.search(b"\ACondition Intercepted", page_get, re.I)'
        ],
        'dotdefender': [
            '"dotDefender Blocked Your Request" in (page_get)'
        ],
        'edgecast': [
            're.search(b"\AECDF", headers_get,re.I)'
        ],
        'expressionengine': [
            '"Invalid GET Data" in (page_get)'
        ],
        'fortiweb': [
            're.search(b"\AFORTIWAFSID=",headers_get, re.I)'
        ],
        'hyperguard': [
            're.search(b"\AODSESSION=",headers_get, re.I)'
        ],
        'incapsula': [
            're.search(b"incap_ses|visid_incap",headers_get, re.I)',
            're.search(b"Incapsula", headers_get, re.I)',
            '"Incapsula incident ID" in (page_get)'
        ],
        'isaserver': [
            '"The server denied the specified Uniform Resource Locator (URL). Contact the server administrator." in (page_get)',
            '"The ISA Server denied the specified Uniform Resource Locator (URL)" in (page_get)'
        ],
        'jiasule': [
            're.search(b"jiasule-WAF", headers_get,re.I)',
            're.search(b"__jsluid=",headers_get, re.I)',
            're.search(b"jsl_tracking",headers_get, re.I)',
            're.search(b"static\.jiasule\.com/static/js/http_error\.js", page_get, re.I)',
            '"notice-jiasule" in (page_get)'
        ],
        'kona': [
            're.search(b"Reference #[0-9a-f.]+", page_get, re.I)',
            're.search(b"AkamaiGHost", headers_get,re.I)'
        ],
        'modsecurity': [
            're.search(b"Mod_Security|NOYB", headers_get,re.I)',
            '"This error was generated by Mod_Security" in (page_get)'
        ],
        'netcontinuum': [
            're.search(b"\ANCI__SessionId=",headers_get, re.I)'
        ],
        'netscaler': [
            're.search(b"\Aclose", headers_get,re.I)',
            're.search(b"\A(ns_af=|citrix_ns_id|NSC_)",headers_get, re.I)',
            're.search(b"\ANS-CACHE",headers_get,re.I)'
        ],
        'newdefend': [
            're.search(b"newdefend", headers_get,re.I)'
        ],
        'nsfocus': [
            're.search(b"NSFocus", headers_get,re.I)'
        ],
        'paloalto': [
            're.search(b"Access[^<]+has been blocked in accordance with company policy", page_get, re.I)'
        ],
        'profense': [
            're.search(b"\APLBSID=",headers_get, re.I)',
            're.search(b"Profense", headers_get,re.I)'
        ],
        'radware': [
            're.search(b"Unauthorized Activity Has Been Detected.+Case Number:", page_get, re.I | re.S)'
        ],
        'requestvalidationmode': [
            '"ASP.NET has detected data in the request that is potentially dangerous" in (page_get)',
            '"Request Validation has detected a potentially dangerous client input value" in (page_get)'
        ],
        'safe3': [
            're.search(b"Safe3WAF",headers_get, re.I)',
            're.search(b"Safe3 Web Firewall", headers_get,re.I)'
        ],
        'safedog': [
            're.search(b"WAF/2\.0",headers_get, re.I)',
            're.search(b"Safedog", headers_get,re.I)',
            're.search(b"safedog",page_get, re.I)',
            '"safedog.cn" in (page_get)'
        ],
        'secureiis': [
            're.search(b"SecureIIS[^<]+Web Server Protection", page_get)',
            '"http://www.eeye.com/SecureIIS/" in (page_get)',
            're.search(b"\?subject=[^>]*SecureIIS Erro", page_get)'
        ],
       
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪子燕青啦啦啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值