0%

XSStrike源码-waf检测

Pre:

waf检测是为了之后的bypass.


源码:

该功能比较简单,所以直接贴源码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import json
import re
import sys

from core.requester import requester
from core.log import setup_logger

logger = setup_logger(__name__)


def wafDetector(url, params, headers, GET, delay, timeout):
with open(sys.path[0] + '/db/wafSignatures.json', 'r') as file:
wafSignatures = json.load(file)
# a payload which is noisy enough to provoke the WAF
noise = '<script>alert("XSS")</script>' # 明显的payload
params['xss'] = noise
# Opens the noise injected payload
response = requester(url, params, headers, GET, delay, timeout)
page = response.text # 返回包源码
code = str(response.status_code) # 状态码
headers = str(response.headers) # 头部
logger.debug('Waf Detector code: {}'.format(code))
logger.debug_json('Waf Detector headers:', response.headers)

if int(code) >= 400:
bestMatch = [0, None]
for wafName, wafSignature in wafSignatures.items():
score = 0
pageSign = wafSignature['page']
codeSign = wafSignature['code']
headersSign = wafSignature['headers']
if pageSign:
if re.search(pageSign, page, re.I):
score += 1
if codeSign:
if re.search(codeSign, code, re.I):
score += 0.5 # increase the overall score by a smaller amount because http codes aren't strong indicators # 状态码权重较低,因为不是一个特别准确的判断标识
if headersSign:
if re.search(headersSign, headers, re.I):
score += 1
# if the overall score of the waf is higher than the previous one
if score > bestMatch[0]: # 保留权重最高的
del bestMatch[:] # delete the previous one
bestMatch.extend([score, wafName]) # and add this one
if bestMatch[0] != 0:
return bestMatch[1]
else:
return None
else:
return None

主要流程

发送明显的恶意payload:

1
2
3
4
5
# a payload which is noisy enough to provoke the WAF
noise = '<script>alert("XSS")</script>' # 明显的payload
params['xss'] = noise
# Opens the noise injected payload
response = requester(url, params, headers, GET, delay, timeout)

发送一段足够明显的xss payload,连参数名都是xss,试图触发server的waf机制.


判断逻辑:

通过3个指标来正则匹配并计算匹配度得分,然后保留一个得分最高的作为最终的判定结果

  1. page 返回包源码

  2. code 状态码

  3. headers 返回包头部


正则匹配:

目前这个版本有66种waf的指纹、特征.

详细请看.https://github.com/s0md3v/XSStrike/blob/470f138db5fc0943e8a90a0de4052ddb7c03efab/db/wafSignatures.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"360 Web Application Firewall (360)" : {
"code" : "493",
"page" : "/wzws-waf-cgi/",
"headers" : "X-Powered-By-360wzb"
},
"aeSecure" : {
"code" : "",
"page" : "aesecure_denied.png",
"headers" : "aeSecure-code"
},
"Airlock (Phion/Ergon)" : {
"code" : "",
"page" : "",
"headers" : "AL[_-]?(SESS|LB)"
},
.... 省略
}

计算匹配度分数:

1
2
3
4
5
6
7
8
9
10
11
12
13
if pageSign:
if re.search(pageSign, page, re.I):
score += 1
if codeSign:
if re.search(codeSign, code, re.I):
score += 0.5 # increase the overall score by a smaller amount because http codes aren't strong indicators # 状态码权重较低,因为不是一个特别准确的判断标识
if headersSign:
if re.search(headersSign, headers, re.I):
score += 1
# if the overall score of the waf is higher than the previous one
if score > bestMatch[0]: # 保留权重最高的
del bestMatch[:] # delete the previous one
bestMatch.extend([score, wafName]) # and add this one

分别在返回包源码,状态码,返回包头部里正则匹配.

其中状态码的得分(权重)最低,因为状态码不是一个特别准确的判断标识

然后保留一个得分最高的,作为最终结果.