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信息。

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

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

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

# -*- coding: utf-8 -*-
# @Author  : Langzi
# @Blog: [url]www.langzi.fun[/url]
# @File: dic.py
# @Software: PyCharm
import sys
import requests
import re
import time
def scan_waf(uul):
    url = uul+'/langzi52zh' if uul.startswith('http') else 'http://' + uul + '/langzi52zh'
    try:
        r = requests.get(url=url,timeout=5)
        page_get = str(r.content)
        headers_get = str(r.headers)
    except:
        print unicode('访问目标网址失败','utf-8')
        time.sleep(10)
    reload(sys)
    sys.setdefaultencoding('utf-8')
    waf_dic ={'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)'
    ],
    'aws':[
    'retval = re.search(r"\bAWS", headers_get,re.I)'
    ],
    'baidu':[
    'retval = re.search(r"fhl", headers_get, re.I)',
    'retval = re.search(r"yunjiasu-nginx", headers_get,re.I)'
    ],
    'barracuda':[
    'retval = re.search(r"\Abarra_counter_session=",headers_get, re.I)',
    'retval = re.search(r"(\A|\b)barracuda_",headers_get, re.I)'
    ],
    'bigip':[
    'retval = re.search(r"\ATS\w{4,}=",headers_get, re.I)',
    'retval = re.search(r"BigIP|BIGipServer",headers_get, re.I)',
    'retval = re.search(r"BigIP|BIGipServer", headers_get,re.I)',
    'retval = re.search(r"\AF5\Z", headers_get,re.I)'
    ],
    'binarysec':[
    'retval = re.search(r"BinarySec", headers_get,re.I)'
    ],
    'blockdos':[
    'retval = re.search(r"BlockDos\.net", headers_get,re.I)'
    ],
    'ciscoacexml':[
    'retval = re.search(r"ACE XML Gateway", headers_get,re.I)'
    ],
    'cloudflare':[
    'retval = re.search(r"cloudflare-nginx", headers_get,re.I)',
    'retval = re.search(r"\A__cfduid=",headers_get, re.I)',
    'retval = re.search(r"CloudFlare Ray ID:|var CloudFlare=", page_get)'
    ],
    'cloudfront':[
    'retval = re.search(r"cloudfront", headers_get,re.I)',
    'retval = re.search(r"cloudfront", headers_get,re.I)'
    ],
    'comodo':[
    'retval = re.search(r"Protected by COMODO WAF", headers_get,re.I)'
    ],
    'datapower':[
    'retval = re.search(r"\A(OK|FAIL)", headers_get, re.I)'
    ],
    'denyall':[
    'retval = re.search(r"\Asessioncookie=",headers_get, re.I)',
    'retval = re.search(r"\ACondition Intercepted", page_get, re.I)'
    ],
    'dotdefender':[
    'retval = "dotDefender Blocked Your Request" in (page_get)'
    ],
    'edgecast':[
    'retval = re.search(r"\AECDF", headers_get,re.I)'
    ],
    'expressionengine':[
    'retval = "Invalid GET Data" in (page_get)'
    ],
    'fortiweb':[
    'retval = re.search(r"\AFORTIWAFSID=",headers_get, re.I)'
    ],
    'hyperguard':[
    'retval = re.search(r"\AODSESSION=",headers_get, re.I)'
    ],
    'incapsula':[
    'retval = re.search(r"incap_ses|visid_incap",headers_get, re.I)',
    'retval = re.search(r"Incapsula", headers_get, re.I)',
    'retval = "Incapsula incident ID" in (page_get)'
    ],
    'isaserver':[
    'retval = "The server denied the specified Uniform Resource Locator (URL). Contact the server administrator." in (page_get)',
    'retval = "The ISA Server denied the specified Uniform Resource Locator (URL)" in (page_get)'
    ],
    'jiasule':[
    'retval = re.search(r"jiasule-WAF", headers_get,re.I)',
    'retval = re.search(r"__jsluid=",headers_get, re.I)',
    'retval = re.search(r"jsl_tracking",headers_get, re.I)',
    'retval = re.search(r"static\.jiasule\.com/static/js/http_error\.js", page_get, re.I)',
    'retval = "notice-jiasule" in (page_get)'
    ],
    'kona':[
    'retval = re.search(r"Reference #[0-9a-f.]+", page_get, re.I)',
    'retval = re.search(r"AkamaiGHost", headers_get,re.I)'
    ],
    'modsecurity':[
    'retval = re.search(r"Mod_Security|NOYB", headers_get,re.I)',
    'retval = "This error was generated by Mod_Security" in (page_get)'
    ],
    'netcontinuum':[
    'retval = re.search(r"\ANCI__SessionId=",headers_get, re.I)'
    ],
    'netscaler':[
    'retval = re.search(r"\Aclose", headers_get,re.I)',
    'retval = re.search(r"\A(ns_af=|citrix_ns_id|NSC_)",headers_get, re.I)',
    'retval = re.search(r"\ANS-CACHE",headers_get,re.I)'
    ],
    'newdefend':[
    'retval = re.search(r"newdefend", headers_get,re.I)'
    ],
    'nsfocus':[
    'retval = re.search(r"NSFocus", headers_get,re.I)'
    ],
    'paloalto':[
    'retval = re.search(r"Access[^<]+has been blocked in accordance with company policy", page_get, re.I)'
    ],
    'profense':[
    'retval = re.search(r"\APLBSID=",headers_get, re.I)',
    'retval = re.search(r"Profense", headers_get,re.I)'
    ],
    'radware':[
    'retval = re.search(r"Unauthorized Activity Has Been Detected.+Case Number:", page_get, re.I | re.S)'
    ],
    'requestvalidationmode':[
    'retval = "ASP.NET has detected data in the request that is potentially dangerous" in (page_get)',
    'retval = "Request Validation has detected a potentially dangerous client input value" in (page_get)'
    ],
    'safe3':[
    'retval = re.search(r"Safe3WAF",headers_get, re.I)',
    'retval = re.search(r"Safe3 Web Firewall", headers_get,re.I)'
    ],
    'safedog':[
    'retval = re.search(r"WAF/2\.0",headers_get, re.I)',
    'retval = re.search(r"Safedog", headers_get,re.I)',
    'retval = re.search(r"safedog",headers_get, re.I)'
    ],
    'secureiis':[
    'retval = re.search(r"SecureIIS[^<]+Web Server Protection", page_get)',
    'retval = "http://www.eeye.com/SecureIIS/" in (page_get)',
    'retval = re.search(r"\?subject=[^>]*SecureIIS Error", page_get)'
    ],
    'senginx':[
    'retval = "SENGINX-ROBOT-MITIGATION" in (page_get)',
    ],
    'sitelock':[
    'retval = "SiteLock Incident ID" in (page_get)'
    ],
    'sonicwall':[
    'retval = "This request is blocked by the SonicWALL" in (page_get)',
    'retval = re.search(r"Web Site Blocked.+\bnsa_banner", page_get, re.I)',
    'retval = re.search(r"SonicWALL", headers_get,re.I)'
    ],
    'sophos':[
    'retval = "Powered by UTM Web Protection" in (page_get)'
    ],
    'stingray':[
    'retval = re.search(r"\AX-Mapping-",headers_get, re.I)'
    ],
    'sucuri':[
    'retval = re.search(r"Sucuri/Cloudproxy", headers_get,re.I)',
    'retval = "Sucuri WebSite Firewall - CloudProxy - Access Denied" in (page_get)',
    'retval = re.search(r"Questions\?.+cloudproxy@sucuri\.net", (page_get))'
    ],
    'tencent':[
    'retval = "waf.tencent-cloud.com" in (page_get)'
    ],
    'teros':[
    'retval = re.search(r"\Ast8(id|_wat|_wlf)",headers_get, re.I)'
    ],
    'trafficshield':[
    'retval = re.search(r"F5-TrafficShield", headers_get,re.I)',
    'retval = re.search(r"\AASINFO=",headers_get, re.I)'
    ],
    'urlscan':[
    'retval = re.search(r"Rejected-By-UrlScan",headers_get, re.I)',
    'retval = re.search(r"/Rejected-By-UrlScan", page_get, re.I)'
    ],
    'uspses':[
    'retval = re.search(r"Secure Entry Server", headers_get,re.I)'
    ],
    'varnish':[
    'retval = re.search(r"varnish\Z",headers_get,re.I)',
    'retval = re.search(r"varnish", headers_get,re.I)',
    'retval = re.search(r"\bXID: \d+", page_get)'
    ],
    'wallarm':[
    'retval = re.search(r"nginx-wallarm", headers_get,re.I)'
    ],
    'webknight':[
    'retval = re.search(r"WebKnight", headers_get,re.I)'
    ],
    'yundun':[
    'retval = re.search(r"YUNDUN", headers_get,re.I)',
    'retval = re.search(r"YUNDUN", headers_get,re.I)'
    ],
    'yunsuo':[
    'retval = re.search(r"<img class=\"yunsuologo\"", page_get, re.I)',
    'retval = re.search(r"yunsuo_session",headers_get, re.I)'
    ]}

    dd = ''
    for k,v in waf_dic.iteritems():
        for x in v:
            try:
                exec(x)
                if retval:
                    dd = retval
                    return unicode('发现WAF : ','utf-8') + k
            except :
                pass
    if dd == '':
        print uul + unicode(' : 未能发现WAF', 'utf-8')

print scan_waf('http://butian.360.cn/')

好吧WAF指纹数量还是太少了,收集waf指纹这种工作还是需要团队来做才行,一个人忙不过来

1.0 批量检测

支持导入数据,校验WAF,所用功能都是基于sqlmap,因为个人能力有限没法收集更多的国产waf指纹,所以只能校验这么多了

自动生成两个结果,result.txt中是不存在waf的,log为日志文件

代码

代码已上传 GITHUB

坚持原创技术分享,您的支持将鼓励我继续创作!
------ 本文结束 ------

版权声明

LangZi_Blog's by Jy Xie is licensed under a Creative Commons BY-NC-ND 4.0 International License
由浪子LangZi创作并维护的Langzi_Blog's博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证
本文首发于Langzi_Blog's 博客( http://langzi.fun ),版权所有,侵权必究。

0%