Python脚本实现Web漏洞扫描工具
这是去年毕设做的一个Web漏洞扫描小工具,主要针对简单的SQL注入漏洞、SQL盲注和XSS漏洞,代码是看过github外国大神(听说是SMAP的编写者之一)的两个小工具源码,根据里面的思路自己写的。以下是使用说明和源代码。
一、使用说明:
1.运行环境:
Linux命令行界面+Python2.7
2.程序源码:
Vimscanner//建立一个名为scanner的文件
Chmoda+xscanner//修改文件权限为可执行的
3.运行程序:
Pythonscanner//运行文件
若没有携带目标URL信息,界面输出帮助信息,提醒可以可输入的参数。
参数包括:
--h输出帮助信息
--url扫描的URL
--dataPOST请求方法的参数
--cookieHTTP请求头Cookie值
--user-agentHTTP请求头User-Agent值
--random-agent是否使用浏览器伪装
--referer目标URL的上一层界面
--proxyHTTP请求头代理值
例如扫描“http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=&Submit=Submit”
Pythonscanner--url="http://127.0.0.1/dvwa/vulnerabilities/sqli/?id=&Submit=Submit"--cookie="security=low;PHPSESSID=menntb9b2isj7qha739ihg9of1"
输出扫描结果如下:
结果显示:
存在XSS漏洞,漏洞匹配漏洞特征库“”>.XSS.<””,属于嵌入标签外的类型。
存在SQL注入漏洞,目标网站服务器的数据库类型为MySQL。
存在BLINDSQL注入漏洞。
二、源代码:
代码验证过可以运行,我个人推荐用DVWA测试吧。
#!-*-coding:UTF-8-*-
importoptparse,random,re,string,urllib,urllib2,difflib,itertools,httplib
NAME="ScannerforRXSSandSQLI"
AUTHOR="Lishuze"
PREFIXES=("",")","'","')","\"")
SUFFIXES=("","---","#")
BOOLEAN_TESTS=("AND%d=%d","ORNOT(%d=%d)")
TAMPER_SQL_CHAR_POOL=('(',')','\'','"''"')
TAMPER_XSS_CHAR_POOL=('\'','"','>','<',';')
GET,POST="GET","POST"
COOKIE,UA,REFERER="Cookie","User-Agent","Referer"
TEXT,HTTPCODE,TITLE,HTML=xrange(4)
_headers={}
USER_AGENTS=(
"Mozilla/5.0(X11;Linuxi686;rv:38.0)Gecko/20100101Firefox/38.0",
"Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/45.0.2454.101Safari/537.36",
"Mozilla/5.0(Macintosh;U;IntelMacOSX10_7_0;en-US)AppleWebKit/534.21(KHTML,likeGecko)Chrome/11.0.678.0Safari/534.21",
)
XSS_PATTERNS=(
(r"<!--[^>]*%(chars)s|%(chars)s[^<]*-->","\"<!--.'.xss.'.-->\",insidethecomment",None),
(r"(?s)<script[^>]*>[^<]*?'[^<']*%(chars)s|%(chars)s[^<']*'[^<]*</script>","\"<script>.'.xss.'.</script>\",enclosedby<script>tags,insidesingle-quotes",None),
(r'(?s)<script[^>]*>[^<]*?"[^<"]*%(chars)s|%(chars)s[^<"]*"[^<]*</script>',"'<script>.\".xss.\".</script>',enclosedby<script>tags,insidedouble-quotes",None),
(r"(?s)<script[^>]*>[^<]*?%(chars)s|%(chars)s[^<]*</script>","\"<script>.xss.</script>\",enclosedby<script>tags",None),
(r">[^<]*%(chars)s[^<]*(<|\Z)","\">.xss.<\",outsideoftags",r"(?s)<script.+?</script>|<!--.*?-->"),
(r"<[^>]*'[^>']*%(chars)s[^>']*'[^>]*>","\"<.'.xss.'.>\",insidethetag,insidesingle-quotes",r"(?s)<script.+?</script>|<!--.*?-->"),
(r'<[^>]*"[^>"]*%(chars)s[^>"]*"[^>]*>',"'<.\".xss.\".>',insidethetag,insidedouble-quotes",r"(?s)<script.+?</script>|<!--.*?-->"),
(r"<[^>]*%(chars)s[^>]*>","\"<.xss.>\",insidethetag,outsideofquotes",r"(?s)<script.+?</script>|<!--.*?-->")
)
DBMS_ERRORS={
"MySQL":(r"SQLsyntax.*MySQL",r"Warning.*mysql_.*",r"validMySQLresult",r"MySqlClient\."),
"MicrosoftSQLServer":(r"Driver.*SQL[\-\_\]*Server",r"OLEDB.*SQLServer",r"(\W|\A)SQLServer.*Driver",r"Warning.*mssql_.*",r"(\W|\A)SQLServer.*[0-9a-fA-F]{8}",r"(?s)Exception.*\WSystem\.Data\.SqlClient\.",r"(?s)Exception.*\WRoadhouse\.Cms\."),
"MicrosoftAccess":(r"MicrosoftAccessDriver",r"JETDatabaseEngine",r"AccessDatabaseEngine"),
"Oracle":(r"ORA-[0-9][0-9][0-9][0-9]",r"Oracleerror",r"Oracle.*Driver",r"Warning.*\Woci_.*",r"Warning.*\Wora_.*")
}
def_retrieve_content_xss(url,data=None):
surl=""
foriinxrange(len(url)):
ifi>url.find('?'):
surl+=surl.join(url[i]).replace('',"%20")
else:
surl+=surl.join(url[i])
try:
req=urllib2.Request(surl,data,_headers)
retval=urllib2.urlopen(req,timeout=30).read()
exceptException,ex:
retval=getattr(ex,"message","")
returnretvalor""
def_retrieve_content_sql(url,data=None):
retval={HTTPCODE:httplib.OK}
surl=""
foriinxrange(len(url)):
ifi>url.find('?'):
surl+=surl.join(url[i]).replace('',"%20")
else:
surl+=surl.join(url[i])
try:
req=urllib2.Request(surl,data,_headers)
retval[HTML]=urllib2.urlopen(req,timeout=30).read()
exceptException,ex:
retval[HTTPCODE]=getattr(ex,"code",None)
retval[HTML]=getattr(ex,"message","")
match=re.search(r"<title>(?P<result>[^<]+)</title>",retval[HTML],re.I)
retval[TITLE]=match.group("result")ifmatchelseNone
retval[TEXT]=re.sub(r"(?si)<script.+?</script>|<!--.+?-->|<style.+?</style>|<[^>]+>|\s+","",retval[HTML])
returnretval
defscan_page_xss(url,data=None):
print"StartscanningRXSS:\n"
retval,usable=False,False
url=re.sub(r"=(&|\Z)","=1\g<1>",url)ifurlelseurl
data=re.sub(r"=(&|\Z)","=1\g<1>",data)ifdataelsedata
try:
forphasein(GET,POST):
current=urlifphaseisGETelse(dataor"")
formatchinre.finditer(r"((\A|[?&])(?P<parameter>[\w]+)=)(?P<value>[^&]+)",current):
found,usable=False,True
print"Scanning%sparameter'%s'"%(phase,match.group("parameter"))
prefix=("".join(random.sample(string.ascii_lowercase,5)))
suffix=("".join(random.sample(string.ascii_lowercase,5)))
ifnotfound:
tampered=current.replace(match.group(0),"%s%s"%(match.group(0),urllib.quote("%s%s%s%s"%("'",prefix,"".join(random.sample(TAMPER_XSS_CHAR_POOL,len(TAMPER_XSS_CHAR_POOL))),suffix))))
content=_retrieve_content_xss(tampered,data)ifphaseisGETelse_retrieve_content_xss(url,tampered)
forsampleinre.finditer("%s([^]+?)%s"%(prefix,suffix),content,re.I):
#printsample.group()
forregex,info,content_removal_regexinXSS_PATTERNS:
context=re.search(regex%{"chars":re.escape(sample.group(0))},re.sub(content_removal_regexor"","",content),re.I)
ifcontextandnotfoundandsample.group(1).strip():
print"!!!%sparameter'%s'appearstobeXSSvulnerable(%s)"%(phase,match.group("parameter"),info)
found=retval=True
ifnotusable:
print"(x)nousableGET/POSTparametersfound"
exceptKeyboardInterrupt:
print"\r(x)Ctrl-Cpressed"
returnretval
defscan_page_sql(url,data=None):
print"StartscanningSQLI:\n"
retval,usable=False,False
url=re.sub(r"=(&|\Z)","=1\g<1>",url)ifurlelseurl
data=re.sub(r"=(&|\Z)","=1\g<1>",data)ifdataelsedata
try:
forphasein(GET,POST):
current=urlifphaseisGETelse(dataor"")
formatchinre.finditer(r"((\A|[?&])(?P<parameter>\w+)=)(?P<value>[^&]+)",current):
vulnerable,usable=False,True
original=None
print"Scanning%sparameter'%s'"%(phase,match.group("parameter"))
tampered=current.replace(match.group(0),"%s%s"%(match.group(0),urllib.quote("".join(random.sample(TAMPER_SQL_CHAR_POOL,len(TAMPER_SQL_CHAR_POOL))))))
content=_retrieve_content_sql(tampered,data)ifphaseisGETelse_retrieve_content_sql(url,tampered)
for(dbms,regex)in((dbms,regex)fordbmsinDBMS_ERRORSforregexinDBMS_ERRORS[dbms]):
ifnotvulnerableandre.search(regex,content[HTML],re.I):
print"!!!%sparameter'%s'couldbeerrorSQLivulnerable(%s)"%(phase,match.group("parameter"),dbms)
retval=vulnerable=True
vulnerable=False
original=originalor(_retrieve_content_sql(current,data)ifphaseisGETelse_retrieve_content_sql(url,current))
forprefix,boolean,suffixinitertools.product(PREFIXES,BOOLEAN_TESTS,SUFFIXES):
ifnotvulnerable:
template="%s%s%s"%(prefix,boolean,suffix)
payloads=dict((_,current.replace(match.group(0),"%s%s"%(match.group(0),urllib.quote(template%(1if_else2,1),safe='%'))))for_in(True,False))
contents=dict((_,_retrieve_content_sql(payloads[_],data)ifphaseisGETelse_retrieve_content_sql(url,payloads[_]))for_in(False,True))
ifall(_[HTTPCODE]for_in(original,contents[True],contents[False]))and(any(original[_]==contents[True][_]!=contents[False][_]for_in(HTTPCODE,TITLE))):
vulnerable=True
else:
ratios=dict((_,difflib.SequenceMatcher(None,original[TEXT],contents[_][TEXT]).quick_ratio())for_in(True,False))
vulnerable=all(ratios.values())andratios[True]>0.95andratios[False]<0.95
ifvulnerable:
print"!!!%sparameter'%s'couldbeerrorBlindSQLivulnerable"%(phase,match.group("parameter"))
retval=True
ifnotusable:
print"(x)nousableGET/POSTparametersfound"
exceptKeyboardInterrupt:
print"\r(x)Ctrl-Cpressed"
returnretval
definit_options(proxy=None,cookie=None,ua=None,referer=None):
global_headers
_headers=dict(filter(lambda_:_[1],((COOKIE,cookie),(UA,uaorNAME),(REFERER,referer))))
urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler({'http':proxy}))ifproxyelseNone)
if__name__=="__main__":
print"----------------------------------------------------------------------------------"
print"%s\nBy:%s"%(NAME,AUTHOR)
print"----------------------------------------------------------------------------------"
parser=optparse.OptionParser()
parser.add_option("--url",dest="url",help="TargetURL")
parser.add_option("--data",dest="data",help="POSTdata")
parser.add_option("--cookie",dest="cookie",help="HTTPCookieheadervalue")
parser.add_option("--user-agent",dest="ua",help="HTTPUser-Agentheadervalue")
parser.add_option("--random-agent",dest="randomAgent",action="store_true",help="UserandomlyselectedHTTPUser-Agentheadervalue")
parser.add_option("--referer",dest="referer",help="HTTPRefererheadervalue")
parser.add_option("--proxy",dest="proxy",help="HTTPproxyaddress")
options,_=parser.parse_args()
ifoptions.url:
init_options(options.proxy,options.cookie,options.uaifnotoptions.randomAgentelserandom.choice(USER_AGENTS),options.referer)
result_xss=scan_page_xss(options.urlifoptions.url.startswith("http")else"http://%s"%options.url,options.data)
print"\nScanresults:%svulnerabilitiesfound"%("possible"ifresult_xsselse"no")
print"----------------------------------------------------------------------------------"
result_sql=scan_page_sql(options.urlifoptions.url.startswith("http")else"http://%s"%options.url,options.data)
print"\nScanresults:%svulnerabilitiesfound"%("possible"ifresult_sqlelse"no")
print"----------------------------------------------------------------------------------"
else:
parser.print_help()
以上所述是小编给大家介绍的Python脚本实现Web漏洞扫描工具,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!