分析XSSstrike源码

#用于学习web安全自动化工具#

我能收获什么?

1.XSS漏洞检测机制

  • 学习如何构造和发送XSS payload
  • 如何识别响应中的回显,WAF,过滤规则等
  • 如何使用词典,编码策略,上下文探测等绕过过滤器

2.Python安全工具开发技巧

  • 使用requests,urllib等模块构造请求
  • 多线程异步扫描
  • 数据结构组织方式
  • 命令行界面交互的设计思路

3.源码工程结构与模块划分

  • 如何将工具拆分为功能模块
  • 如何设计配置文件,命令参数,插件式架构

4.反WAF与XSS绕过技巧

  • 内置的绕过payload和算法
  • DOM与反射型XSS的区分探测方式

学习步骤

  1. 快速了解工具的功能和使用方式(阅读README文档,运行XSSstrike,观察常见命令行参数,输出内容,执行流程)
  2. 通过项目结构,理解各个模块的职责(梳理模块用途,建立模块依赖关系图)
  3. 选择一个典型流程深入分析
  4. 学习其中用到的关键技术

项目概述

理解XSSstrike运作原理,学习其中的技术

模块 功能说明 是否有独立文件/目录
智能 Payload 生成器 根据上下文动态构造有效 Payload,而非使用固定词典 core/payloads.py
HTML/JS 解析器 手工编写的解析器,能理解上下文 core/parsers/ 下可能包含
Fuzzing 引擎 自动注入参数 + 分析响应 + 变异构造 core/fuzzer.py
爬虫引擎 多线程爬虫(基于 Photon) core/crawler.py
参数发现工具 自动挖掘 URL 参数(可能集成 Arjun) core/parameter.py
WAF 探测与绕过 检测是否被 WAF 拦截并尝试绕过 core/waf.py
DOM XSS 扫描 分析 JavaScript 中触发的 XSS(可能用到 headless 浏览器) core/dom_scanner.py
盲 XSS 支持 支持回显不可见的注入测试 可能集成 external webhook
Payload 编码器 支持 URL、Unicode、HTML 编码等 utils/encoder.py
配置模块 支持高度定制,可能有配置文件或命令参数 config.pycore/config.py

学习流程

一.运行XSSstrike+跟踪主入口

进行调试:我使用的是vscode,launch.json是其中的调试配置文件,用于告诉vscode要调试哪个程序(program),使用什么语言(python),传入哪些命令参数(args),是否使用终端,是否附加已有进程等等

添加断点,进行调试,观察运行过程

二.分析主程序入口(xsstrike.py

功能概述:这是主程序入口,所有的功能模块都是从这里开始被调用

内容:

1.基础引入和环境检测

2.参数解析:argparse

参数 长参数形式 说明
-h --help 显示帮助信息并退出
-u --url TARGET 目标 URL
--data PARAMDATA POST 数据
-e --encode ENCODE 对 payload 进行编码
--- --fuzzer 启动 fuzz 模式
--- --update 检查并安装更新
--- --timeout TIMEOUT 设置请求超时时间
--- --proxy 使用代理
--- --crawl 启用爬虫功能
--- --json 将 POST 数据作为 JSON 格式处理
--- --path 在 URL 路径中注入 payload
--- --seeds ARGS_SEEDS 从文件加载爬虫种子 URL
-f --file ARGS_FILE 从文件加载 payload 列表
-l --level LEVEL 设置爬虫的深度级别
--- --headers [ADD_HEADERS] 添加自定义请求头
-t --threads THREADCOUNT 设置线程数量
-d --delay DELAY 请求之间的延迟时间
--- --skip 不询问是否继续
--- --skip-dom 跳过 DOM XSS 检测
--- --blind 爬虫过程中注入 Blind XSS payload
--- --console-log-level {DEBUG,INFO,RUN,GOOD,WARNING,ERROR,CRITICAL,VULN} 设置控制台日志级别
--- --file-log-level {DEBUG,INFO,RUN,GOOD,WARNING,ERROR,CRITICAL,VULN} 设置日志文件的日志级别
--- --log-file LOG_FILE 指定日志文件名称

3.配置与全局变量初始化:将命令行参数作为全局配置传入globalVariables,方便各模块共享使用,处理headers和初始化关键模块

复制代码
if type(args.add_headers) == bool:
    headers = extractHeaders(prompt())  # 手动输入
elif type(args.add_headers) == str:
    headers = extractHeaders(args.add_headers)  # 解析命令行输入

from core.config import blindPayload
from core.encoders import base64
from core.photon import photon
from core.prompt import prompt
from core.utils import extractHeaders, reader, converter
#这些是 XSStrike 自研的模块,用于数据处理、payload 编码、用户输入交互、爬虫等。

4.程序执行主逻辑(主控制流)

1)单次fuzz模式

复制代码
if fuzz:
    singleFuzz(target, paramData, encoding, headers, delay, timeout)

2)非递归扫描模式

复制代码
elif not recursive and not args_seeds:
    if args_file:
        bruteforcer(target, paramData, payloadList, encoding, headers, delay, timeout)
    else:
        scan(target, paramData, encoding, headers, delay, timeout, skipDOM, skip)

解释:scan()是常规XSS扫描的主函数,bruteforcer是自定义的payload扫描

3)爬虫+全站扫描模式

复制代码
else:
    if target:
        seedList.append(target)
    for target in seedList:
        logger.run('Crawling the target')
        scheme = urlparse(target).scheme
        logger.debug('Target scheme: {}'.format(scheme))
        host = urlparse(target).netloc
        main_url = scheme + '://' + host
        crawlingResult = photon(target, headers, level,
                                threadCount, delay, timeout, skipDOM)
        forms = crawlingResult[0]
        domURLs = list(crawlingResult[1])
        difference = abs(len(domURLs) - len(forms))
        if len(domURLs) > len(forms):
            for i in range(difference):
                forms.append(0)
        elif len(forms) > len(domURLs):
            for i in range(difference):
                domURLs.append(0)
        threadpool = concurrent.futures.ThreadPoolExecutor(max_workers=threadCount)
        futures = (threadpool.submit(crawl, scheme, host, main_url, form,
                                     blindXSS, blindPayload, headers, delay, timeout, encoding) for form, domURL in zip(forms, domURLs))
        for i, _ in enumerate(concurrent.futures.as_completed(futures)):
            if i + 1 == len(forms) or (i + 1) % threadCount == 0:
                logger.info('Progress: %i/%i\r' % (i + 1, len(forms)))
        logger.no_format('')

解释:基于Phonton进行自动爬虫,并结合HTML/JS解析器对表单/链接发起扫描和fuzz

总模块结构图:

复制代码
xsstrike.py
├── argparse 命令行处理
├── 核心配置加载 core/config
├── 日志模块初始化 core/log
├── 请求头处理 extractHeaders/prompt
├── 调用模式模块:
│   ├── modes/scan.py
│   ├── modes/singleFuzz.py
│   ├── modes/bruteforcer.py
│   └── core/photon.py + crawl.py (爬虫+分析)
└── payload/参数/headers/encoder 等辅助模块调用

三.modes/scan.py

功能概述:这个函数是XSStrike的核心扫描逻辑,其主要职责是对目标URL参数进行反射检查,判断是否存在XSS,分析过滤器绕过策略,并生成有效payload进行验证

内容:

1.URL构造和初始请求

复制代码
GET, POST = (False, True) if paramData else (True, False)

解释:如果指定了 paramData(POST 数据),则使用 POST,否则默认 GET。

复制代码
if not target.startswith('http'):
        try:
            response = requester('https://' + target, {},
                                 headers, GET, delay, timeout)
            target = 'https://' + target
        except:
            target = 'http://' + target

解释:自动补全协议头(如 example.comhttps://example.com

2.DOM XSS检测

复制代码
if not skipDOM:
        logger.run('Checking for DOM vulnerabilities')
        highlighted = dom(response)
        if highlighted:
            logger.good('Potentially vulnerable objects found')
            logger.red_line(level='good')
            for line in highlighted:
                logger.no_format(line, level='good')
            logger.red_line(level='good')

解释:使用core/dom.py模块进行静态DOM XSS检查,如果HTML中出现可能被动态执行的eval()或innerHTML拼接位置,会被标记

3.参数提取和WAF检测

复制代码
params = getParams(target, paramData, GET)

解释:从URL或POST data中提取参数

复制代码
WAF = wafDetector(url, {list(params.keys())[0]: xsschecker}, headers, GET, delay, timeout)

解释:使用core/wafDetector.py模块,向目标发送特征性payload并分析相应内容,检测是否存在WAF检测

4.反射检测+payload构造主循环

对每一个参数逐一进行 fuzz 和检测:

复制代码
for paramName in params.keys():
    paramsCopy = copy.deepcopy(params)
    ...

1)参数注入和反射检测

复制代码
if encoding:
            paramsCopy[paramName] = encoding(xsschecker)
        else:
            paramsCopy[paramName] = xsschecker
        response = requester(url, paramsCopy, headers, GET, delay, timeout)
        occurences = htmlParser(response, encoding)

解释:注入payload,并分析响应中是否出现该值,htmlParser() 返回值如 {<位置>: <标签上下文>}

2)分析过滤器

复制代码
efficiencies = filterChecker(
            url, paramsCopy, headers, GET, delay, occurences, timeout, encoding)

解释:使用多个轻量payload模拟不同类型的XSS注入,检测哪些被过滤,返回每种payload的注入效率指标。

3)生成绕过payload

复制代码
vectors = generator(occurences, response.text)

解释:根据参数反射位置生成上下文对应的payload列表,含逃逸策略和双引号,尖括号编码等变体。

5.Payload验证循环

复制代码
for confidence, vects in vectors.items():
    for vect in vects:
        ...
        efficiencies = checker(...)

1)判断有效性

复制代码
bestEfficiency = max(efficiencies)

解释:如果payload达到效率100或>=95且以\开头,则认为是高危

2)是否继续扫描

复制代码
if not skip:
    choice = input('...Continue?').lower()
    if choice != 'y':
        quit()

模块间调用逻辑图:

复制代码
scan.py
├── requester()           → 发起请求
├── dom()                 → DOM XSS 静态检测
├── getParams()           → 参数提取
├── wafDetector()         → 检测是否有 WAF
├── htmlParser()          → 判断反射点(xsschecker 是否出现在响应中)
├── filterChecker()       → 判断输入被过滤的规则
├── generator()           → 根据反射点生成合适上下文 payload
└── checker()             → 逐个 payload 验证其注入效率

四.modes/singleFuzz.py(--fuzzer)

功能概述:这是XSStrike中一个用于快速fuzz单个参数的简化扫描模块,适用于手动分析或快速检测用途。相比主扫描逻辑scan.py,它不执行DOM分析,paylaod构造或效率计算,仅将一个标准payload插入目标参数并fuzz相应内容

(注释:什么是fuzzing?fuzzing指的是自动的或半自动的向程序输入大量随机,异常或畸形的数据,以观察程序是否会出现异常行为,比如崩溃,处理失败或产生漏洞等。)

内容:

1.函数定义

复制代码
def singleFuzz(target, paramData, encoding, headers, delay, timeout):
参数名 含义
target 目标 URL
paramData POST 数据(若为 None 则默认 GET 请求)
encoding 可选,对 payload 进行编码
headers 自定义请求头
delay 每个请求之间的延迟(防止 WAF)
timeout 请求超时时间

2.请求方法和URL预处理

复制代码
GET, POST = (False, True) if paramData else (True, False)
    # If the user hasn't supplied the root url with http(s), we will handle it
    if not target.startswith('http'):
        try:
            response = requester('https://' + target, {},
                                 headers, GET, delay, timeout)
            target = 'https://' + target
        except:
            target = 'http://' + target

3.日志输出和参数准备

复制代码
host = urlparse(target).netloc
url = getUrl(target, GET)
params = getParams(target, paramData, GET)

解释:解析出主机名,最终构造的URL和参数键值对,使用core/utils.py中的工具函数

4.WAF检测

复制代码
WAF = wafDetector(url, {list(params.keys())[0]: xsschecker}, headers, GET, delay, timeout)

5.Fuzz主题逻辑

复制代码
for paramName in params.keys():
    logger.info('Fuzzing parameter: %s' % paramName)
    paramsCopy = copy.deepcopy(params)
    paramsCopy[paramName] = xsschecker
    fuzzer(url, paramsCopy, headers, GET, delay, timeout, WAF, encoding)

解释:逐个参数插入标准payload,调用core/fuzzer.py中的fuzzer()进行fuzz

与scan.py的区别:

功能 scan.py singlefuzz.py
DOM 检测
Payload 构造
自动反射分析
多参数扫描
标准 payload fuzz ✅(核心功能)
用途 自动扫描 + 精度分析 快速测试某个目标是否有反射型 XSS

五.modes/bruteforcer.py(-f ARGS_FILE)

功能概述:实现了一个基于payload列表的暴力测试器,用于向指定参数逐个注入Payload,并检测是否存在响应中,从而判断是否反射

内容:

1.主函数

复制代码
def bruteforcer(target, paramData, payloadList, encoding, headers, delay, timeout):
  • target:目标 URL。

  • paramData:POST 参数,如果为空则默认使用 GET。

  • payloadList:需要测试的 Payload 字符串列表。

  • encoding:是否使用编码函数处理 Payload(如 HTML 实体编码等)。

  • headers:请求头字典。

  • delay:请求间隔延迟。

  • timeout:请求超时时间。

2.请求方法和URL预处理

复制代码
GET, POST = (False, True) if paramData else (True, False)
    host = urlparse(target).netloc  # Extracts host out of the url
    logger.debug('Parsed host to bruteforce: {}'.format(host))
    url = getUrl(target, GET)
    logger.debug('Parsed url to bruteforce: {}'.format(url))
    params = getParams(target, paramData, GET)
    logger.debug_json('Bruteforcer params:', params)
    if not params:
        logger.error('No parameters to test.')
        quit()

3.外层循环:遍历参数名,内层循环:遍历payload列表

复制代码
for paramName in params.keys():
        progress = 1
        paramsCopy = copy.deepcopy(params)
        for payload in payloadList:
            logger.run('Bruteforcing %s[%s%s%s]%s: %i/%i\r' %
                       (green, end, paramName, green, end, progress, len(payloadList)))
            if encoding:
                payload = encoding(unquote(payload))
            paramsCopy[paramName] = payload
            response = requester(url, paramsCopy, headers,
                                 GET, delay, timeout).text
            if encoding:
                payload = encoding(payload)
            if payload in response:
                logger.info('%s %s' % (good, payload))
            progress += 1

六.modes/craw.py(--craw)

功能概述:负责处理表单爬取,漏洞检测,Blind XSS注入

函数:

复制代码
def crawl(scheme, host, main_url, form, blindXSS, blindPayload, headers, delay, timeout, encoding):
  • scheme : 协议名,如 "http""https"

  • host : 主机名,如 "example.com"

  • main_url: 起始页面的 URL,用于校验表单来源

  • form : 从页面中提取到的所有表单数据(是一个字典,通常由 htmlParser 提供)

  • blindXSS: 布尔值,是否启用 Blind XSS 模式

  • blindPayload: 如果启用 Blind XSS,这是注入的 payload

  • headers: 请求头

  • delay: 每次请求之间的延迟(秒)

  • timeout: 请求超时时间

  • encoding: payload 的编码方式(可选)

内容:

复制代码
    if form:
        for each in form.values():
            url = each['action']

解释:遍历页面中提取到的所有的form,每个表单是一个dict,含有action,method,inputs等信息,从中获取<form action="...">中的URL

1)构造完整的表单提交URL

复制代码
            if url:
                if url.startswith(main_url):
                    pass
                elif url.startswith('//') and url[2:].startswith(host):
                    url = scheme + '://' + url[2:]
                elif url.startswith('/'):
                    url = scheme + '://' + host + url
                elif re.match(r'\w', url[0]):
                    url = scheme + '://' + host + '/' + url

2)初始化记录,避免重复检测

复制代码
                if url not in core.config.globalVariables['checkedForms']:
                    core.config.globalVariables['checkedForms'][url] = []

解释:全局变量 checkedForms 用来记录已经检测过的表单和参数,避免重复。

3)提交表单参数+构造参数

复制代码
method = each['method']
GET = True if method == 'get' else False
inputs = each['inputs']
paramData = {}
for one in inputs:
    paramData[one['name']] = one['value']

解释:获取表单的提交方式(GET/POST),提取所有输入框的吗name/value作为参数字典paramData。

4)遍历每一个参数并开始测试

复制代码
for paramName in paramData.keys():
    if paramName not in core.config.globalVariables['checkedForms'][url]:
        core.config.globalVariables['checkedForms'][url].append(paramName)

解释:只测试没有检测过的参数

5)注入XSS测试载荷,然后发送请求

复制代码
paramsCopy = copy.deepcopy(paramData)
paramsCopy[paramName] = xsschecker
response = requester(url, paramsCopy, headers, GET, delay, timeout)

解释:拷贝参数,向当前参数注入默认XSS检测payload,并发送请求

6)相应解析和位置提取

复制代码
occurences = htmlParser(response, encoding)
positions = occurences.keys()

解释:使用htmlParser查找payload是否出现在响应中,并提取位置

7)进一步过滤+生成payload

复制代码
occurences = filterChecker(url, paramsCopy, headers, GET, delay, occurences, timeout, encoding)
vectors = generator(occurences, response.text)

解释:filterChecker用于检查是否有字符被过滤,generator根据上下文和过滤情况生成最适合的XSS payload

8)如果找到可利用的payload,输出结果

复制代码
if vectors:
    for confidence, vects in vectors.items():
        try:
            payload = list(vects)[0]
            logger.vuln('Vulnerable webpage: %s%s%s' % (green, url, end))
            logger.vuln('Vector for %s%s%s: %s' % (green, paramName, end, payload))
            break
        except IndexError:
            pass

解释:成功生成 payload 则输出漏洞信息(URL + payload),break 表示只输出一个 payload 即可。

9)注入Blind XSS(如果启用)

复制代码
if blindXSS and blindPayload:
    paramsCopy[paramName] = blindPayload
    requester(url, paramsCopy, headers, GET, delay, timeout)

解释:如果开启了Blind XSS模式,则用blindPayload再次注入,这种payload不在当前页面回显,但可能在后台系统触发。

七.core/dom.py

功能概述:在响应的<script>标签中寻找潜在的XSS"source→sink"流,从而判断是否存在DOM XSS漏洞。

关键术语:

概念 解释
DOM XSS 通过 JavaScript 在客户端执行中,攻击者控制的输入流向危险的函数(如 innerHTML, eval),造成 XSS
Source 攻击者可控的输入点(如 document.location, window.name
Sink 可能执行恶意代码的危险函数(如 eval, innerHTML, document.write
变量追踪 判断 source 内容是否被赋值给某个变量,再被传入 sink

内容:

1)识别source和sink正则

复制代码
sources = r'''\b(?:document\.(URL|documentURI|...|referrer)|location\.(...))\b'''
sinks = r'''\b(?:eval|assign|innerHTML|...|document\.(write|writeln)|...)'''

2)用正则匹配<script>标签内容

复制代码
scripts = re.findall(r'(?i)(?s)<script[^>]*>(.*?)</script>', response)

3)主循环分析逻辑

复制代码
sinkFound, sourceFound = False, False
for script in scripts:
    script = script.split('\n')
    num = 1
    allControlledVariables = set()
  • sinkFoundsourceFound:用于标记是否发现漏洞路径。

  • 将每段 <script> 的内容按行分割,便于逐行分析与高亮。

  • allControlledVariables:记录由用户输入派生出的变量名。

4)逐行扫描JS内容

复制代码
for newLine in script:
    line = newLine
    parts = line.split('var ')
    controlledVariables = set()

解释:每行JS代码存在于newline中,用split('var ') 试图提取变量定义

5)检查source派生变量

复制代码
for part in parts:
    for controlledVariable in allControlledVariables:
        if controlledVariable in part:
            controlledVariables.add(re.search(r'[a-zA-Z$_][a-zA-Z0-9$_]+', part).group().replace('$', '\\$'))

解释:如果在某一行中,已有受控变量出现在某段变量定义中,就认为新的变量也被污染。(污点传播)

6)匹配source并高亮

复制代码
pattern = re.finditer(sources, newLine)
for grp in pattern:
    source = newLine[grp.start():grp.end()].replace(' ', '')
    if len(parts) > 1:
        for part in parts:
            if source in part:
                controlledVariables.add(re.search(r'[a-zA-Z$_][a-zA-Z0-9$_]+', part).group().replace('$', '\\$'))
    line = line.replace(source, yellow + source + end)

解释:使用正则在该行中查找source,将发现的source替换为黄色高亮,如果source出现在变量定义中,也将该变量添加为受控变量。

7)受控变量使用点检查

复制代码
for controlledVariable in allControlledVariables:
    matches = list(filter(None, re.findall(r'\b%s\b' % controlledVariable, line)))
    if matches:
        sourceFound = True
        line = re.sub(r'\b%s\b' % controlledVariable, yellow + controlledVariable + end, line)

解释:如果本行中使用了受控变量,也高亮显示,并标记sourceFound,说明受控输入正在传播

8)检测sink并高亮

复制代码
pattern = re.finditer(sinks, newLine)
for grp in pattern:
    sink = newLine[grp.start():grp.end()].replace(' ', '')
    if sink:
        line = line.replace(sink, red + sink + end)
        sinkFound = True

解释:匹配sink函数入innerHTML,eval,将其红色高亮,只要存在sink就标记sinkFound

9)保存高亮结果

复制代码
if line != newLine:
    highlighted.append('%-3s %s' % (str(num), line.lstrip(' ')))
num += 1
  • 如果当前行已被高亮处理(说明可能存在危险 source → sink 流),就保存。

  • 添加行号便于后续定位漏洞代码位置。

10)最终返回结果

复制代码
if sinkFound or sourceFound:
    return highlighted
else:
    return []

解释:如果整个<script>中发现了sink或source,就返回高亮行,狗则返回空列表。

小结:

复制代码
HTML Response
    ↓
提取 <script> 脚本
    ↓
逐行查找用户可控的 source(黄色高亮)
    ↓
变量污染分析:追踪 source → var a → var b
    ↓
查找危险 sink 函数(红色高亮)
    ↓
匹配成功 → 返回高亮源码(标记潜在 DOM XSS)

八.core/fuzzer.py

功能概述:这是XSStrike工具的模糊测试模块,对目标参数进行XSS payload模糊测试,观察web应用的响应行为,从而判断是否存在反射型XSS或WAF拦截

核心函数定义:

复制代码
def fuzzer(url, params, headers, GET, delay, timeout, WAF, encoding):
参数名 说明
url 目标 URL
params 请求参数字典(可用于 GET 或 POST)
headers 请求头
GET 是否为 GET 请求(布尔值)
delay 每次请求之间的延迟(防止被 WAF 拦截)
timeout 请求超时时间
WAF 是否启用 WAF 检测(保留参数,实际没用到)
encoding 可选的编码函数(如 html.escapeurlencode

内容:

1.遍历所有的XSS payloads

复制代码
for fuzz in fuzzes:

解释:fuzzes是配置文件中定义的测试用例列表,每个fuzz会依次注入到目标请求中,测试其反应。

2.设置延迟,避免触发WAF限制

复制代码
t = delay + randint(delay, delay * 2) + counter(fuzz)
sleep(t)

解释:在delay基础上加点浮动,增强抗检测性,counter(fuzz)是个技巧,使特定payload执行时有细微时间差,防止被频率规则拦截

3.替换注入点并发送请求

复制代码
if encoding:
    fuzz = encoding(unquote(fuzz))

data = replaceValue(params, xsschecker, fuzz, copy.deepcopy)
response = requester(url, data, headers, GET, delay/2, timeout)

解释:如果有encoding,则先对fuzz解码,再应用encoding,然后将parans中的xsschecker替换成fuzz,发送请求获取响应。

4.请求失败处理(可能会被WAF拦截)

复制代码
except:
    logger.error('WAF is dropping suspicious requests.')
    ...
    try:
        requester(url, params, headers, GET, 0, 10)
        logger.good('Pheww! Looks like sleeping for %s%i%s seconds worked!' % (
            green, ((delay + 1) * 2), end))
    except:
        logger.error('\nLooks like WAF has blocked our IP Address. Sorry!')
        break

解释:如果请求失败,执行退避等待,重新原始请求,判断IP是否真的被封,如果依然失败,则提示用户被封IP。

5.响应结果分类判断

复制代码
if encoding:
    fuzz = encoding(fuzz)

if fuzz.lower() in response.text.lower():
    result = ('%s[passed]  %s' % (green, end))
elif str(response.status_code)[:1] != '2':
    result = ('%s[blocked] %s' % (red, end))
else:
    result = ('%s[filtered]%s' % (yellow, end))

解释:passed:payload被完整反射到响应体中,blocked:服务端响应非2xx,说明可能被拦截,filtered:payload没有出现在响应中,但服务器没有报错,说明有过滤或清洗机制。

整体流程:

复制代码
for fuzz in fuzzes:
    - 等待随机延迟 t
    - 将 fuzz 注入参数中
    - 发送请求,捕获响应
    - 判断 fuzz 是否反射 or 被过滤 or 被拦截
    - 输出结果日志

九.core/generator.py

功能概述:上下文感知XSS payload 生成器,根据目标页面中注入点的上下文环境(HTML,属性,JS)动态生成更适合的payload

函数定义:

复制代码
def generator(occurences, response):
  • occurences: 注入点上下文分析结果(由 context_analyzer.py 生成)

  • response: 原始响应页面源码

内容:

1.主函数入口

复制代码
def generator(occurences, response):
    scripts = extractScripts(response)
    index = 0
    vectors = {11: set(), 10: set(), 9: set(), 8: set(), 7: set(),
               6: set(), 5: set(), 4: set(), 3: set(), 2: set(), 1: set()}

解释:vector是一个字典,key是优先级,11是最高的,value是payload集合

2.遍历所有注入点

复制代码
for i in occurences:
    context = occurences[i]['context']

解释:每一个注入点会根据其context分成几类:html,attribute,comment,script。后面的处理就是分情况生成payload。

3.HTML上下文处理

复制代码
if context == 'html':
    lessBracketEfficiency = occurences[i]['score']['<']
    greatBracketEfficiency = occurences[i]['score']['>']
    ends = ['//']
    badTag = occurences[i]['details']['badTag'] if 'badTag' in occurences[i]['details'] else ''
    if greatBracketEfficiency == 100:
        ends.append('>')
    if lessBracketEfficiency:
        payloads = genGen(fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, badTag)
        for payload in payloads:
            vectors[10].add(payload)
  • score 是个打分机制:某字符的使用是否被允许(100 表示可直接使用)

  • 如果 <> 可用,就构造以标签为核心的 payload

  • 使用 genGen() 自动构造 payload

4.属性上下文处理

复制代码
elif context == 'attribute':
    found = False
    tag = occurences[i]['details']['tag']
    Type = occurences[i]['details']['type']
    quote = occurences[i]['details']['quote'] or ''
    attributeName = occurences[i]['details']['name']
    attributeValue = occurences[i]['details']['value']
    quoteEfficiency = occurences[i]['score'][quote] if quote in occurences[i]['score'] else 100
    greatBracketEfficiency = occurences[i]['score']['>']
    ends = ['//']
    if greatBracketEfficiency == 100:
        ends.append('>')

数据结构:

  • tag:当前属性所属标签(如input,a,img)
  • Type:属性类型(name,value,event,protocal)
  • quote:原始属性值的引号(如")
  • attributeName:属性名
  • attributeValue:属性值内容
  • quoteEffeciency:当前quote是否可用

payload构造逻辑:

1)引号和>都可用:

复制代码
if greatBracketEfficiency == 100 and quoteEfficiency == 100:
    payloads = genGen(...)
    payload = quote + '>' + payload  # 提前闭合属性值,逃逸插入事件
    vectors[9].add(payload)

生成类似:"><svg οnlοad=alert(1)>

2)仅quote可用:构造onfoucus等

复制代码
if quoteEfficiency == 100:
    vector = quote + filling + r('autofocus') + filling + r('onfocus') + '=' + quote + function
    vectors[8].add(vector)

3)quoteEfficiency == 90 时:转义处理

复制代码
if quoteEfficiency == 90:
    vector = '\\' + quote + ... + '\\' + quote
    vectors[7].add(vector)

4)特殊属性处理:如 srcdochref="javascript:"

复制代码
if attributeName == 'srcdoc':
    ...
elif attributeName == 'href' and attributeValue == xsschecker:
    vectors[10].add('javascript:' + function)

5)on*事件属性

复制代码
elif attributeName.startswith('on'):
    closer = jsContexter(attributeValue)
    ...
    vector = quote + closer + filling + function + suffix

解释:构造事件处理器内部的JS注入,如

复制代码
<div onmouseover="';alert(1)//">

5.注释上下文处理

复制代码
elif context == 'comment':
    if greatBracketEfficiency == 100 and lessBracketEfficiency == 100:
        payloads = genGen(...)
        vectors[10].add(payload)

解释:如果 < > 没过滤,构造闭合 --> 再插入标签

6.script上下文处理

复制代码
elif context == 'script':
    script = scripts[index]
    closer = jsContexter(script)
    quote = occurences[i]['details']['quote']
    scriptEfficiency = occurences[i]['score']['</scRipT/>']
  • 先判断是否在字符串中

  • 是否可闭合脚本标签逃逸

  • 插入 payload 并逃逸上下文

1)>和<script>标签都可用:

复制代码
            if greatBracketEfficiency == 100:
                ends.append('>')
            if scriptEfficiency == 100:
                breaker = r('</script/>')
                payloads = genGen(fillings, eFillings, lFillings,
                                  eventHandlers, tags, functions, ends)
                for payload in payloads:
                    vectors[10].add(payload)

2)结束当前JS上下文,直接注入,若没有判断quote评分

复制代码
            if closer:
                suffix = '//\\'
                for filling in jFillings:
                    for function in functions:
                        vector = quote + closer + filling + function + suffix
                        vectors[7].add(vector)
            elif breakerEfficiency > 83:
                prefix = ''
                suffix = '//'
                if breakerEfficiency != 100:
                    prefix = '\\'
                for filling in jFillings:
                    for function in functions:
                        if '=' in function:
                            function = '(' + function + ')'
                        if quote == '':
                            filling = ''
                        vector = prefix + quote + closer + filling + function + suffix
                        vectors[6].add(vector)
            index += 1

十.core/photon.py

功能概述:主要负责基于一个初始URL的多线程爬虫任务,并收集表单,参数,潜在可利用的DOM结构等信息。

函数定义:

复制代码
def photon(seedUrl, headers, level, threadCount, delay, timeout, skipDOM):
参数名 含义
seedUrl 起始的 URL
headers 请求头信息
level 爬虫的深度(循环次数)
threadCount 并发线程数
delay 请求延迟
timeout 请求超时时间
skipDOM 是否跳过 DOM 解析(布尔值)

内容:

1.初始化部分

复制代码
forms = []          # 收集到的所有表单(GET + POST)
processed = set()   # 已经处理过的 URL
storage = set()     # 存储待处理的、属于同一主站的 URL
schema = urlparse(seedUrl).scheme
host = urlparse(seedUrl).netloc
main_url = schema + '://' + host
storage.add(seedUrl)
checkedDOMs = []    # 记录已经检查过的 DOM 内容,避免重复记录

解释:这部分是爬虫初始化,使用urlparse拆解URL,提取协议(http或https)和主机名,构造主站路径如https://example.com,用集合避免重复URL

2.内部递归函数rec

这个函数是实际负责抓取、分析、提取信息的核心逻辑,每个URL都会传入此函数处理

1)打印当前正在处理的URL

复制代码
processed.add(target)
printableTarget = '/'.join(target.split('/')[3:])

解释:将当前URL标记为已处理,并打印友好的日志信息

2)提取参数并识别GET表单

复制代码
url = getUrl(target, True)
params = getParams(target, '', True)
if '=' in target:
    inps = [{'name': name, 'value': value} for name, value in params.items()]
    forms.append({0: {'action': url, 'method': 'get', 'inputs': inps}})

解释:getUrl()用于提取主路径,getParams()返回参数字典,如果URL中含=,则认定为GET请求的形式表单,添加进forms里

3)发起请求+分析JS组件

复制代码
response = requester(url, params, headers, True, delay, timeout).text
retireJs(url, response)

解释:用封装的requester()发送请求,拿到相应内容,用retireJs()分析是否引入了有漏洞的JS库

4)检查DOM中潜在XSS点(可选)

复制代码
if not skipDOM:
    highlighted = dom(response)
    clean_highlighted = ''.join([re.sub(r'^\d+\s+', '', line) for line in highlighted])
    if highlighted and clean_highlighted not in checkedDOMs:
        checkedDOMs.append(clean_highlighted)
        logger.good('Potentially vulnerable objects found at %s' % url)
        ...

解释:如果没跳过DOM分析,就用dom()见擦汗HTML DOM中的可以点,下面就是避免重复输出相同内容

5)用zetanize()抓取HTML表单

复制代码
forms.append(zetanize(response))

解释:这是一个专用的HTML表单提取器,结果加入forms列表

6)用正则抓取页面中的链接(HREF)

复制代码
matches = re.findall(r'<[aA].*href=["\']{0,1}(.*?)["\']', response)

解释:对所有<a href=...>提取链接,准备加入爬虫列表

7)链接归一化并判断是否在范围内

复制代码
for link in matches:
    link = link.split('#')[0]
    if link.endswith(...):  # 跳过非网页资源
        pass
    else:
        if link[:4] == 'http':
            if link.startswith(main_url):
                storage.add(link)
        elif link[:2] == '//':
            if link.split('/')[2].startswith(host):
                storage.add(schema + link)
        elif link[:1] == '/':
            storage.add(main_url + link)
        else:
            storage.add(main_url + '/' + link)

解释:将相对路径、协议相对路径、绝对路径和完整路径规范化为完整URL,只处理和主站匹配的链接。

3.主循环(多线程抓取)

复制代码
for x in range(level):
    urls = storage - processed
    threadpool = concurrent.futures.ThreadPoolExecutor(max_workers=threadCount)
    futures = (threadpool.submit(rec, url) for url in urls)
    for i in concurrent.futures.as_completed(futures):
        pass

解释:按爬虫深度level重复抓取,每一轮用线程池执行rec()函数,逐个等待线程执行完成(为了异常捕获)

十一.core/wafDetector.py

功能概述:通过向目标URL注入一个典型的XSS payload,然后根据响应页面内容、状态码和响应头信息来判断目标是否启用了WAF,并尽可能识别出具体的WAF产品。

函数定义:

复制代码
def wafDetector(url, params, headers, GET, delay, timeout):
参数 含义
url 请求目标地址
params 请求参数(字典)
headers 请求头(字典)
GET 是否为 GET 请求(布尔值)
delay 请求延迟
timeout 请求超时时间

内容:

1.读取WAF特征库

复制代码
with open(sys.path[0] + '/db/wafSignatures.json', 'r') as file:
    wafSignatures = json.load(file)

解释:加载位于项目路径下的db/wafSinatures.json文件,该文件定义了多种WAF产品的特征信息,如页内容特征、HTTP状态码、响应头等,返回的数据是一个字典格式。

2.构造"噪声"请求

复制代码
noise = '<script>alert("XSS")</script>'
params['xss'] = noise

解释:往参数中插入一个典型的XSS payload,触发可能的WAF防护机制

3.发送请求并提取响应信息

复制代码
response = requester(url, params, headers, GET, delay, timeout)
page = response.text
code = str(response.status_code)
headers = str(response.headers)

解释:使用requester模块向目标地址发起请求,并收集:

  • page: 响应内容 HTML

  • code: 状态码(如 403、406)

  • headers: 响应头

4.日志输出

复制代码
logger.debug('Waf Detector code: {}'.format(code))
logger.debug_json('Waf Detector headers:', response.headers)

解释:输出调试信息到终端,帮助开发者观察请求过程和响应头

5.检测逻辑核心:识别匹配

复制代码
if int(code) >= 400:
    bestMatch = [0, None]

解释:只有当返回码>=400(意味着可能被拒绝)才认为存在WAF干预的可能

6.遍历所有特征进行匹配打分

复制代码
for wafName, wafSignature in wafSignatures.items():
    score = 0
    pageSign = wafSignature['page']
    codeSign = wafSignature['code']
    headersSign = wafSignature['headers']

    if pageSign and re.search(pageSign, page, re.I):
        score += 1
    if codeSign and re.search(codeSign, code, re.I):
        score += 0.5
    if headersSign and re.search(headersSign, headers, re.I):
        score += 1

    if score > bestMatch[0]:
        del bestMatch[:]  # 删除之前得分更低的匹配项
        bestMatch.extend([score, wafName])
  • 每个 WAF 有三类特征(页内容、响应码、响应头)

  • 使用正则表达式逐个匹配

  • score 表示匹配得分,页内容和响应头各 +1,状态码较弱只加 +0.5

  • bestMatch 保留当前得分最高的 WAF 名称

7.返回检测结果

复制代码
if bestMatch[0] != 0:
    return bestMatch[1]
else:
    return None

解释:如果至少有一种特征匹配,则返回WAF名称,否则返回None,表示未探测到

总结:

复制代码
    ↓ 目标 URL
+---------------------+
| 插入 XSS payload    |
+---------------------+
           ↓
+---------------------+
| 发起请求            |
+---------------------+
           ↓
+---------------------+
| 若状态码 >= 400     |
|  进行匹配打分       |
+---------------------+
           ↓
+---------------------+
| 返回匹配度最高的 WAF|
+---------------------+

十二.core/utils

1.converter函数

复制代码
def converter(data, url=False):
    if 'str' in str(type(data)):
        if url:
            dictized = {}
            parts = data.split('/')[3:]
            for part in parts:
                dictized[part] = part
            return dictized
        else:
            return json.loads(data)
    else:
        if url:
            url = urlparse(url).scheme + '://' + urlparse(url).netloc
            for part in list(data.values()):
                url += '/' + part
            return url
        else:
            return json.dumps(data)
  • 用于在字符串与字典之间相互转换,结合 URL 格式处理。

  • 如果 url=True:将路径段转为字典,或将字典拼接为 URL。

  • 否则用于字符串和 JSON 的互相转换。

2.counter函数

复制代码
def counter(string):
    string = re.sub(r'\s|\w', '', string)
    return len(string)
  • 移除字符串中的所有空格和字母数字字符,只保留符号。

  • 返回剩余字符数量,常用于检测 payload 噪音强度。

3.closest函数

复制代码
def closest(number, numbers):
    difference = [abs(list(numbers.values())[0]), {}]
    for index, i in numbers.items():
        diff = abs(number - i)
        if diff < difference[0]:
            difference = [diff, {index: i}]
    return difference[1]
  • 返回 numbers 中与给定 number 最接近的键值对。

  • 通常用于匹配相似位置或长度。

4.fillHoles函数

复制代码
def fillHoles(original, new):
    filler = 0
    filled = []
    for x, y in zip(original, new):
        if int(x) == (y + filler):
            filled.append(y)
        else:
            filled.extend([0, y])
            filler += (int(x) - y)
    return filled
  • 用于根据原数组和新数组间的差异填充"0"作为占位。

  • 目的是对齐结构或长度。

5.stripper函数

复制代码
def stripper(string, substring, direction='right'):
    done = False
    strippedString = ''
    if direction == 'right':
        string = string[::-1]
    for char in string:
        if char == substring and not done:
            done = True
        else:
            strippedString += char
    if direction == 'right':
        strippedString = strippedString[::-1]
    return strippedString
  • 从字符串中移除第一个 substring(从左或右)。

  • 常用于构造 payload,避免某些字符干扰。

6.extractHeaders函数

复制代码
def extractHeaders(headers):
    headers = headers.replace('\\n', '\n')
    sorted_headers = {}
    matches = re.findall(r'(.*):\s(.*)', headers)
    for match in matches:
        header = match[0]
        value = match[1]
        try:
            if value[-1] == ',':
                value = value[:-1]
            sorted_headers[header] = value
        except IndexError:
            pass
    return sorted_headers
  • 从原始头部字符串中提取成结构化字典。

  • 清除多余的转义和末尾逗号。

7.replaceValue

复制代码
def replaceValue(mapping, old, new, strategy=None):
    anotherMap = strategy(mapping) if strategy else mapping
    if old in anotherMap.values():
        for k in anotherMap.keys():
            if anotherMap[k] == old:
                anotherMap[k] = new
    return anotherMap
  • 在字典中替换旧值为新值,支持浅拷贝或深拷贝策略。

  • 用于参数值动态注入。

8.getUrl

复制代码
def getUrl(url, GET):
    if GET:
        return url.split('?')[0]
    else:
        return url

提取 URL 的 base(不包含 query string)

  1. extractScripts

    def extractScripts(response):
    scripts = []
    matches = re.findall(r'(?s)<script.?>(.?)</script>', response.lower())
    for match in matches:
    if xsschecker in match:
    scripts.append(match)
    return scripts

提取所有内联 <script> 内容,筛选出包含 xsschecker 的脚本段。

10.randomUpper

复制代码
def randomUpper(string):
    return ''.join(random.choice((x, y)) for x, y in zip(string.upper(), string.lower()))
  • 将输入字符串的大小写随机混合。

  • 常用于绕过 WAF 的 case-sensitive 检测。

11.flattenParams

复制代码
def flattenParams(currentParam, params, payload):
    flatted = []
    for name, value in params.items():
        if name == currentParam:
            value = payload
        flatted.append(name + '=' + value)
    return '?' + '&'.join(flatted)

将字典格式参数拼接为 URL query string,替换指定参数为 payload。

12.genGen

(生成 XSS payload 的核心函数)

复制代码
def genGen(fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, badTag=None):
    vectors = []
    r = randomUpper
    for tag in tags:
        bait = xsschecker if tag in ['d3v', 'a'] else ''
        for eventHandler in eventHandlers:
            if tag in eventHandlers[eventHandler]:
                for function in functions:
                    for filling in fillings:
                        for eFilling in eFillings:
                            for lFilling in lFillings:
                                for end in ends:
                                    if tag in ['d3v', 'a'] and '>' in ends:
                                        end = '>'
                                    breaker = '</' + r(badTag) + '>' if badTag else ''
                                    vector = breaker + '<' + r(tag) + filling + r(eventHandler) + eFilling + '=' + eFilling + function + lFilling + end + bait
                                    vectors.append(vector)
    return vectors
  • 自动构造基于标签、事件、函数的混合型 XSS payload。

  • 用于 fuzzing 和绕过防护的攻击向量生成。

13.getParams

复制代码
def getParams(url, data, GET):
    params = {}
    if '?' in url and '=' in url:
        data = url.split('?')[1]
        if data[:1] == '?':
            data = data[1:]
    elif data:
        if getVar('jsonData') or getVar('path'):
            params = data
        else:
            try:
                params = json.loads(data.replace('\'', '"'))
                return params
            except json.decoder.JSONDecodeError:
                pass
    else:
        return None
    if not params:
        parts = data.split('&')
        for part in parts:
            each = part.split('=')
            if len(each) < 2:
                each.append('')
            try:
                params[each[0]] = each[1]
            except IndexError:
                params = None
    return params
  • 从 URL 或请求体中提取参数并返回字典。

  • 支持 query string、JSON、路径型参数。

14.writer / reader

复制代码
def writer(obj, path):
    kind = str(type(obj)).split('\'')[0]
    if kind == 'list' or kind == 'tuple':
        obj = '\n'.join(obj)
    elif kind == 'dict':
        obj = json.dumps(obj, indent=4)
    savefile = open(path, 'w+')
    savefile.write(str(obj.encode('utf-8')))
    savefile.close()


def reader(path):
    with open(path, 'r') as f:
        result = [line.rstrip(
                    '\n').encode('utf-8').decode('utf-8') for line in f]
    return result

用于文件读写。支持列表、字典自动格式转换。

15.js_extractor

复制代码
def js_extractor(response):
    """Extract js files from the response body"""
    scripts = []
    matches = re.findall(r'<(?:script|SCRIPT).*?(?:src|SRC)=([^\s>]+)', response)
    for match in matches:
        match = match.replace('\'', '').replace('"', '').replace('`', '')
        scripts.append(match)
    return scripts

从响应中提取外链 JS 文件。

16.handle_anchor

复制代码
def handle_anchor(parent_url, url):
    scheme = urlparse(parent_url).scheme
    if url[:4] == 'http':
        return url
    elif url[:2] == '//':
        return scheme + ':' + url
    elif url.startswith('/'):
        host = urlparse(parent_url).netloc
        scheme = urlparse(parent_url).scheme
        parent_url = scheme + '://' + host
        return parent_url + url
    elif parent_url.endswith('/'):
        return parent_url + url
    else:
        return parent_url + '/' + url

构造规范化 URL,用于处理锚点相对路径。

17.deJSON

复制代码
def deJSON(data):
    return data.replace('\\\\', '\\')

修复被双转义的 JSON 字符串。

18.getVar / updateVar

复制代码
def getVar(name):
    return core.config.globalVariables[name]

def updateVar(name, data, mode=None):
    if mode:
        if mode == 'append':
            core.config.globalVariables[name].append(data)
        elif mode == 'add':
            core.config.globalVariables[name].add(data)
    else:
        core.config.globalVariables[name] = data

全局变量管理器,封装对 core.config.globalVariables 的读写。

19.isBadContext

复制代码
ef isBadContext(position, non_executable_contexts):
    badContext = ''
    for each in non_executable_contexts:
        if each[0] < position < each[1]:
            badContext = each[2]
            break
    return badContext

判断当前位置是否位于不可执行上下文

20.equalize

复制代码
def equalize(array, number):
    if len(array) < number:
        array.append('')

用于列表补全长度,不足则填充字符串

21.escaped

复制代码
def escaped(position, string):
    usable = string[:position][::-1]
    match = re.search(r'^\\*', usable)
    if match:
        match = match.group()
        if len(match) == 1:
            return True
        elif len(match) % 2 == 0:
            return False
        else:
            return True
    else:
        return False

判断指定位置前是否存在奇数个反斜杠,从而判断是否被转义。

相关推荐
独行soc18 分钟前
2025年渗透测试面试题总结-腾讯[实习]安全研究员(题目+回答)
linux·安全·web安全·面试·职场和发展·渗透测试
weixin_4349362824 分钟前
你工作中涉及的安全方面的测试有哪些怎么回答
安全
钟离墨笺1 小时前
Go语言学习-->编译器安装
开发语言·后端·学习·golang
钟离墨笺2 小时前
Go语言学习-->从零开始搭建环境
开发语言·后端·学习·golang
我是坑货3 小时前
Spring学习笔记:Spring的基于注解的XML的详细配置
笔记·学习·spring
开开心心就好4 小时前
高效视频倍速播放插件推荐
python·学习·游戏·pdf·计算机外设·电脑·音视频
行云流水剑5 小时前
【学习记录】Element UI导入报错 * element-ui/lib/theme-chalk/index.css in ./src/main.js
css·学习·ui
DFminer7 小时前
【仿生机器人系统设计】涉及到的伦理与安全问题
安全·机器人
守城小轩7 小时前
机器人现可完全破解验证码:未来安全技术何去何从?
自动化·rpa·指纹浏览器·浏览器开发
爱意随风起风止意难平7 小时前
003 flutter初始文件讲解(2)
学习·flutter