一、护网背景
本次复盘来自某省省会城市政府护网实战。材料覆盖7个有报告的IP资产,共整理出24份漏洞报告,报告自评包含2个严重、17个高危和5个中危问题。
这些资产覆盖文件管理、综合执法、智慧安防、综合治税、财政评审和业务共享平台,后台连接工单、案件、组织架构、流程审批、项目资料和系统配置。匿名访问、上传接口或异常路径一旦缺少权限控制,就可能直接触达真实业务数据。
验证时先确认系统用途和组件,再比较正常请求、无认证请求和变形请求的响应,最后用无害文件、随机字典项和测试流程确认读取、上传、写入及流程执行能力。涉及个人信息和业务数据的结果均只保留最小样本。
二、总体情况
归档的24份报告中,部分记录针对同一入口的不同验证结果,另有同一系统跨目录保存的材料。按入口和利用链归并后,可以整理为21个独立问题。
从风险类型看,主要有四类。第一类是认证绕过,包括路径归一化、白名单前缀和请求体参数拆分。第二类是权限缺失,包括匿名读取业务数据、客户端凭据取得管理权限和普通用户触达后台。第三类是高风险功能暴露,包括文件上传、流程模型导入与部署、字典增删。第四类是配置和接口泄露,包括数据库连接、监控面板、默认口令和批量个人信息。
这些问题集中在少数站点,实际影响差异较大。部分目标已经确认数据读取和代码执行,部分完成了受控写入,还有部分只证明接口可达。下面先按站点列出全部报告,再给出各问题的风险说明和测试过程。
三、发现成果
1XX.X.X.XX6 BXXXn文件管理系统
-
未授权上传JSP并由Tomcat解析执行,测试表达式返回49。
-
认证过滤器可被
app/..;路径绕过,匿名读取客户联系人和文件信息。 -
售后微信工单接口匿名返回15,067条工单总量及真实样本。
-
Druid监控台未授权,暴露数据库连接、SQL统计和服务器路径。
-
AfterSingle字典接口可匿名新增和删除字典项。
-
工单接口信任客户端提交的openid,可匿名创建和删除自建工单。
2XX.X.X.18:8088 财政投资评审系统
-
Flowable流程模型、定义和导出接口可匿名访问。
-
流程模型key存在路径穿越,可向静态上传目录写入受限文件。
-
匿名部署包含ScriptTask的流程后,定时器触发代码并写出标记。
1XX.X.X.X16:30180 综合执法系统
-
前端硬编码OAuth客户端凭据,可匿名换取令牌并读取用户、组织和执法案件。
-
filesApi可匿名上传文件并通过业务域名回读。
-
filesApi接受SVG上传,回读时保留SVG类型和脚本内容。
1XX.X.X.X05:9090 JEECG智慧安防平台
-
formate_data.queryData匿名返回约18,602,106条表记录总量和真实样本。 -
formate_data.uploadImage可匿名上传文本并返回落盘URL。 -
AuthInterceptor将白名单条目放在URL、真实action放入请求体,可绕过认证。
-
SystemController可通过同一绕过通道匿名新增和删除字典项。
1XX.X.X.X8:8082 FRQ综合治税系统
-
queryTreeByArrJson存在未授权Oracle时间盲注。 -
getDataCenters匿名返回内部数据库地址、库名、账号和明文口令配置。
2XX.X.X.XX2:8888 财政评审业务共享平台
-
大屏项目接口匿名返回41条项目联系人记录,每条包含156个字段。
-
通用配置getter匿名返回初始用户口令配置。
-
短信、注册和手机验证码登录接口可匿名到达业务处理逻辑。
1XX.X.X.X6:58443 大华ICC智能物联平台
-
六类接口无需认证即可读取账号状态、精确版本、内部组件和密码策略。
-
密保答案失败次数按出口IP计算,更换出口后可重新获得尝试次数。
-
OAuth登录验证码开关由客户端控制,失败锁定同样按出口IP隔离。
四、漏洞详情
1XX.X.X.XX6 BXXXn文件管理系统
资产概况
系统是该市某区的文件管理和文档流转平台,入口位于 /BXXXn/ ,后端使用SpringBoot、Shiro和Tomcat。公开入口同时承载工单、售后记录、文件上传、字典配置和运维监控。
1.未授权上传JSP
漏洞情况
afterSales/upload/uploadFile 允许匿名提交multipart文件,上传目录位于Tomcat可解析的Web路径内,服务端未限制JSP扩展名。测试文件中的EL表达式被成功执行。
该接口面向售后附件上传,正常业务应当绑定登录用户和工单记录。实际请求既没有校验会话,也没有检查扩展名、文件内容和最终存储路径。响应会返回可访问的文件名,Tomcat又把上传目录当作Web应用资源处理,因此普通附件上传能力直接变成了JSP写入能力。
危害
攻击者无需账号即可上传服务端可执行文件,并以应用进程权限运行代码,进一步读取配置、业务数据和服务器文件,或中断文件管理服务。
测试过程
1.先从售后页面提交附件时抓取到 afterSales/upload/uploadFile ,接口只根据multipart字段接收文件,没有在请求中附带工单标识或用户标识。为了判断上传是否必须依赖登录态,构造一个只包含 ${7*7} 的JSP文件,并去掉Cookie和Token重新提交。
POST /BXXXn/afterSales/upload/uploadFile HTTP/1.1
Host:1XX.X.X.XX6
Content-Type:multipart/form-data
upload=@probe.jsp
2.匿名请求返回上传成功和可直接访问的 /BXXXn/uploads/ 路径,没有出现登录跳转。上传目录位于Web根路径,因此继续访问返回地址,检查文件是作为普通静态文件下载,还是会被Tomcat解析。
GET /BXXXn/uploads/2026-10-19/06ddca247ec045b2abb14fac0bbba69b.jsp HTTP/1.1
Host:1XX.X.X.XX6
3.响应正文为 PENTEST_EL_49_END ,其中 49 由EL表达式计算得到。普通静态回显不会改变表达式内容,这个结果确认JSP已经进入Tomcat解析流程,匿名上传能力可以直接转化为服务端代码执行。
2.路径归一化绕过认证
漏洞情况
Shiro过滤器和后端Servlet对 ..; 路径的处理不一致。在 BXXXn 后插入 app/..; 后,请求仍能到达业务控制器,但不再经过原有的登录校验。
过滤器看到的路径以 BXXXn 下的静态目录为主,后端归一化后则进入 afterSales 控制器。这个差异不需要有效账号,也不需要构造复杂反序列化数据,只要保持原业务参数并改变路径形式即可触发。受影响的不仅是单个统计接口,联系人、附件和UEditor配置等共用同一过滤器链的入口都需要按同一问题排查。
危害
匿名用户可以访问统计、联系人、文件和UEditor等后台接口。测试已读取2,556条联系人记录,并可调用上传配置和文件上传动作。
测试过程
1.先直接请求后台统计接口,确认同一业务参数在正常路径下需要什么认证条件。
GET /BXXXn/afterSales/pc/ywjswtclztqktj?year=2024 HTTP/1.1
Host:1XX.X.X.XX6
2.响应为 {"msg":"invalidtoken","code":401} ,说明控制器本身可达,但请求被前置认证拦截。保留了原来的参数,只在 BXXXn 后加入 app/..; ,观察过滤器判断的路径和后端Servlet归一化后的路径是否一致。
GET /BXXXn/app/..;/afterSales/pc/ywjswtclztqktj?year=2024&probe=1 HTTP/1.1
Host:1XX.X.X.XX6
3.变形路径返回HTTP200和2024年工单统计,认证结果发生了变化。为了确认不是单个统计接口的配置疏漏,继续把同一路径形式套到共用 afterSales 控制器的联系人接口。
GET /BXXXn/app/..;/afterSales/gethistory?page=1&limit=1 HTTP/1.1
Host:1XX.X.X.XX6
4.响应返回2,556条联系人总数和真实样本,字段包括姓名、联系方式和历史记录。到这里已经可以判断差异出在过滤器与后端路由,继续请求UEditor配置和上传动作,检查同一绕过方式是否还能触达文件处理功能。
POST /BXXXn/app/..;/ueditor/config?action=config HTTP/1.1
Host:1XX.X.X.XX6
POST /BXXXn/app/..;/ueditor/config?action=uploadfile HTTP/1.1
Host:1XX.X.X.XX6
Content-Type:multipart/form-data
upfile=@probe.txt
3.售后工单未授权读取
漏洞情况
afterSales/wx 没有校验登录态和 fopenid 归属。参数留空时,接口直接返回全部工单及首批记录,工单详情和附件也可继续读取。
列表接口把 fopenid 当作筛选条件使用,没有把空值与当前微信身份绑定。响应直接包含工单总数和分页数据,详情接口继续使用可预测的工单编号查询,附件地址也没有二次鉴权。由此可以从一个匿名列表请求扩展到单条工单内容和附件文件。
危害
工单中的联系人、电话或微信、问题描述和附件可能被匿名获取,造成办事群众个人信息泄露,也可能暴露内部处理记录。
测试过程
1.正常工单列表通常会根据微信身份返回当前用户记录。为了确认服务端是否会自行绑定身份,不携带Cookie和Token,把 fopenid 留空后请求列表。
GET /BXXXn/afterSales/wx?fopenid= HTTP/1.1
Host:1XX.X.X.XX6
2.响应没有返回参数错误,而是给出工单总数和首批记录,首轮为15,042条,复测增长到15,067条。这个结果已经超过单个微信用户的数据范围,因此从响应中取一个工单 fid ,继续验证详情接口是否也缺少归属校验。
GET /BXXXn/afterSales/wx/2112113138844651522 HTTP/1.1
Host:1XX.X.X.XX6
3.详情响应包含联系人、电话或微信、问题内容和附件地址,记录内容与该 fid 对应。随后对返回的附件地址发送HEAD请求,响应为HTTP200,确认匿名读取不仅停留在列表字段,还能访问实际附件。
4.Druid监控台未授权
漏洞情况
Druid控制台及数据源、基础信息、SQL统计接口直接暴露在公网,没有增加额外认证。
首页可以正常加载说明监控组件已经部署并在当前访问路径生效, datasource.json 、 basic.json 和 sql.json 继续返回运行信息。数据源配置包含连接串和数据库账号,基础信息和SQL统计还会暴露框架版本、服务器路径及高频业务语句,为后续数据库攻击和接口枚举提供直接线索。
危害
攻击者可以获取数据库连接参数、账号名、应用路径和SQL执行情况,为进一步攻击数据库或寻找业务薄弱点提供条件。
测试过程
1.先访问Druid首页,确认监控组件是否部署在当前路径。
GET /BXXXn/druid/index.html HTTP/1.1
Host:1XX.X.X.XX6
2.首页正常返回,没有跳转到登录页。为了避免把静态欢迎页误判为未授权,继续请求会读取运行数据的 datasource.json 。
GET /BXXXn/druid/datasource.json HTTP/1.1
Host:1XX.X.X.XX6
3.数据源接口直接返回JDBC连接串,其中包含本机数据库、 root 账号和连接参数。能够读取动态JSON后,再请求 basic.json 和 sql.json ,核对组件版本、服务器路径和SQL统计是否同样开放,最终确认这是一个未认证的运行监控入口。
5.字典接口未授权写
漏洞情况
AfterSingle/type 的查询、新增和删除动作只依赖请求参数,没有对调用者做身份和角色校验。
该控制器把列表、保存和删除放在同一资源路径下,动作通过HTTP方法和参数区分。测试请求没有携带登录凭据,仍然可以完成新增、重新查询和删除的完整过程。字典项通常被工单分类、问题类型和统计逻辑共同引用,写入异常数据后会影响后续业务展示和查询结果。
危害
匿名用户可以增删业务字典,影响问题分类、流程选项和统计口径,造成业务数据不一致或流程错误。
测试过程
1.先匿名读取字典列表,记录当前总数和记录标识,作为后续增删对照。
GET /BXXXn/AfterSingle/type/list HTTP/1.1
Host:1XX.X.X.XX6
2.列表直接返回业务字典,没有出现登录提示。由于写操作和读取使用同一控制器路径,继续提交一个带随机标记的字典项,检查服务端是否对POST动作单独校验身份。
POST /BXXXn/AfterSingle/type HTTP/1.1
Host:1XX.X.X.XX6
Content-Type:application/json
{"fproblemValue":"zzpt_retest","fproblemSort":0,"fstatus":"1","fremark":"retest"}
3.新增请求未返回认证失败,重新读取列表后可以找到 zzpt_retest ,确认数据已经写入。为了进一步验证删除能力,使用返回的记录ID发送DELETE请求,再读取列表核对记录是否消失。
DELETE /BXXXn/AfterSingle/type?idList=<自建记录ID> HTTP/1.1
Host:1XX.X.X.XX6
4.删除后列表中不再出现自建项,总数回到写入前,完整确认匿名用户可以修改业务字典。
6.客户端openid导致匿名增删工单
漏洞情况
绑定和工单接口信任请求体中的 fopenid ,没有把它与微信登录态或服务端会话绑定。调用者可以自行构造身份标识并操作对应工单。
正常微信业务会从登录态取得openid,当前接口却把请求体字段直接作为身份依据。只要知道或枚举一个openid,就能创建绑定关系、提交工单并按该标识读取记录。删除动作同样没有再次校验创建者,测试中自建工单可以完成创建、回读和删除,说明身份与资源归属均未在服务端建立约束。
危害
攻击者可以批量创建虚假工单、冒用某个openid的身份,并删除可定位到的工单,影响售后受理秩序和业务记录完整性。
测试过程
1.微信绑定接口通常会从登录态取得openid。测试不携带微信会话,直接在请求体中填写一个自行构造的 fopenid ,观察服务端是否接受客户端身份。
POST /BXXXn/afterSales/binding HTTP/1.1
Host:1XX.X.X.XX6
Content-Type:application/json
{"fopenid":"ozzpt_probe","fcontentName":"retest","fcontentPhone":"<测试手机号>"}
2.绑定记录创建成功,响应没有要求重新登录。为了判断这个值是否还会决定后续工单归属,保持同一 fopenid ,调用工单创建接口提交一条测试工单。
POST /BXXXn/afterSales/wx HTTP/1.1
Host:1XX.X.X.XX6
Content-Type:application/json
{"fopenid":"ozzpt_probe","ftext":"retest","fcontentName":"retest"}
3.创建请求返回了工单标识。随后用同一 fopenid 查询列表,自建工单出现在结果中,说明列表同样按客户端提供的值筛选数据。
GET /BXXXn/afterSales/wx?page=1&limit=10&fopenid=ozzpt_probe HTTP/1.1
Host:1XX.X.X.XX6
4.按返回的工单 fid 发送删除请求,再次查询同一 fopenid 时结果为空。创建、读取和删除都只依赖客户端值,确认身份及资源归属没有在服务端建立约束。
2XX.X.X.18:8088 财政投资评审系统
资产概况
系统基于RuoYi-Vue、SpringSecurity和Flowable,承载财政项目评审和审批流程。对外入口为 /prod-api ,流程模型、部署管理、审批定义和业务附件属于高权限管理面。
1.匿名读取流程模型
漏洞情况
模型列表、模型JSON、流程定义和审批轨迹接口未纳入统一认证。无Cookie和Token的请求可以读取已存在的模型标识、流程节点和部署信息。
这些接口属于Flowable流程设计和管理面,通常会出现在管理员页面或内部工具中。当前通过 /prod-api 直接暴露,列表、详情和导出共用一个未受保护的控制器前缀。读取模型JSON可以还原节点、连线、表单标识和审批参与者,审批轨迹还能反映真实业务办理过程。
危害
财政审批流程的名称、节点、办理角色和表单配置可能被匿名获取,攻击者还可据此寻找可写入的流程入口或业务审批薄弱点。
测试过程
1.先从系统菜单和前端请求中确认流程模型接口位于 /prod-api/modeler 。为了判断管理面是否依赖登录态,不携带Cookie和Token请求模型列表。
GET /prod-api/modeler/list?pageNum=1&pageSize=2 HTTP/1.1
Host:2XX.X.X.18:8088
2.响应中的 total 为7,并返回真实模型 officialLetterProcess 的标识和名称,没有出现认证失败。因为列表已经给出模型ID,继续读取该模型的编辑器JSON,检查能否取得节点和表单等设计内容。
GET /prod-api/modeler/model/172602/json HTTP/1.1
Host:2XX.X.X.18:8088
3.响应约17KB,包含真实流程节点、连线和编辑器配置。模型设计数据可以匿名读取后,再请求已部署的定义列表,核对当前运行中的流程和审批轨迹是否同样暴露。
GET /prod-api/definition/list?pageNum=1&pageSize=15 HTTP/1.1
Host:2XX.X.X.18:8088
4.定义接口返回已部署流程,审批轨迹中包含12个节点及办理信息。列表、模型JSON和定义数据都能在无认证状态下取得,确认影响覆盖流程设计和管理信息。
2.模型key路径穿越
漏洞情况
创建模型时, key 参数未对 ../ 进行规范化。导出操作使用该值拼接文件名,使文件被写到 upload 静态目录,而不是正常的导出目录。
模型key原本用于标识流程模板,导出时却被直接拼进文件名和目录路径。编码后的点段在创建阶段没有被拒绝,导出阶段也没有把最终路径限制在导出目录内。文件虽然只是BPMN内容,但 upload 目录可以通过 /prod-api/profile 公开回读,使匿名用户获得了向可访问目录写文件的能力。
危害
匿名用户可以向公开可读目录写入BPMN文件,泄露流程定义,或占用、覆盖同目录下的业务文件。当前结果确认了文件写入和公开回读,未进一步验证覆盖生产文件。
测试过程
1.正常模型key通常只包含字母、数字和分隔符。观察导出功能会把key带入文件名和目录后,尝试在创建模型时把key设置为编码后的 ../upload/ 路径,检查合法性校验是否会拒绝点段。
POST /prod-api/modeler/create HTTP/1.1
Host:2XX.X.X.18:8088
Content-Type:application/json
{"name":"retest","key":"\u002e\u002e\u002fupload\u002fretest","description":"retest"}
2.创建请求没有拒绝该key,并返回了模型ID。继续调用导出接口,观察服务端最终生成的文件路径。
GET /prod-api/modeler/export/<模型ID> HTTP/1.1
Host:2XX.X.X.18:8088
3.响应 msg 为 ../upload/retest.bpmn.json ,路径已经跳出正常导出目录。为了确认文件实际写入位置,通过 /prod-api/profile 访问对应文件。
GET /prod-api/profile/upload/retest.bpmn.json HTTP/1.1
Host:2XX.X.X.18:8088
4.该地址返回BPMN文件内容。再用相同文件名请求正常 download 目录,结果为404。两个路径的差异排除了导出目录原本公开的可能,确认写入位置由模型key控制。
3.匿名部署脚本任务
漏洞情况
模型创建、BPMN导入和部署接口均可匿名访问。Flowable在部署包含定时器和ScriptTask的流程后,会按流程配置执行脚本。
这套接口把模型设计、资源导入和流程部署串在一起,任一环节缺少身份校验都足以让外部请求进入管理员操作面。测试使用的BPMN只包含延时启动和写出标记的无害脚本,目的是确认脚本引擎是否会在业务流程中执行,而没有向生产环境投放命令执行载荷。后续复测时创建接口仍开放,但导入和部署链路未再次完成。
危害
攻击者可在流程引擎权限范围内执行脚本并写出文件,进而读取应用资源或扩大服务器权限。受控测试只写出唯一标记,没有执行破坏性命令。
测试过程
1.前面已经确认模型创建接口允许匿名访问。为了让后续验证保持最小影响,先创建独立测试模型,名称只用于区分本轮测试。
POST /prod-api/modeler/create HTTP/1.1
Host:2XX.X.X.18:8088
Content-Type:application/json
{"key":"retest_process","name":"retest_process","description":"retest"}
2.创建请求返回模型ID,说明入口仍然可达。准备一个带定时器启动事件和ScriptTask的BPMN文件,脚本只写出唯一标记,然后把它导入刚创建的模型,检查资源导入是否也缺少权限控制。
POST /prod-api/modeler/input HTTP/1.1
Host:2XX.X.X.18:8088
Content-Type:multipart/form-data
file=@timer-script.bpmn
3.导入后继续调用部署接口。如果部署成功,定时器会触发ScriptTask,因此下一步从公开下载接口回读脚本输出的文件。
POST /prod-api/modeler/deploy HTTP/1.1
Host:2XX.X.X.18:8088
Content-Type:application/json
{"modelId":"<导入模型ID>"}
GET /prod-api/poserver.zz?pgop=opendiskdoc&id=<混淆ID> HTTP/1.1
Host:2XX.X.X.18:8088
4.等待定时器时间到达后,公开下载接口返回的文件内容与脚本设置的标记一致。该标记只由ScriptTask生成,确认流程部署后能够执行脚本并写出文件。
5.10月27日再次复测时,创建接口仍返回成功,但导入请求超时,部署接口返回错误,后续没有再次取得脚本输出。因此新增结果只能确认入口仍然开放,完整执行链以首次成功记录为准。
1XX.X.X.X16:30180 综合执法系统
资产概况
系统是长沙市综合执法业务平台,前端使用D2Admin,后端使用SpringBoot和OAuth2。系统保存用户、组织架构、执法案件和业务附件。
1.客户端凭据换取令牌
漏洞情况
前端JavaScript中硬编码了OAuth客户端标识和密钥,服务端允许使用 client_credentials 模式换取访问令牌,且该令牌能调用用户、组织和案件接口。
客户端凭据模式通常用于服务与服务之间的受控调用,不应把长期密钥下发到浏览器。当前凭据随打包文件公开,令牌签发后又缺少业务角色和数据范围绑定,任何取得前端资源的人都能重复换取令牌。令牌接口不依赖用户登录,失效前可多次调用,因而形成了稳定的匿名后台访问入口。
危害
任何访问过前端资源的人都能取得服务端令牌,读取管理员信息、完整组织树和执法案件。案件列表总量达到9,735条,属于直接业务数据泄露。
测试过程
1.先检查登录页加载的JavaScript,发现 client_id 和 client_secret 直接写在打包文件中。由于这两个值会随浏览器下载,继续使用客户端凭据模式请求令牌,确认服务端是否接受公开的前端密钥。
GET /api/oauthApi/oauth/token?grant_type=client_credentials&client_id=<前端值>&client_secret=<前端值>&scope=profile%20email%20read%20write HTTP/1.1
Host:1XX.X.X.X16:30180
2.响应返回 access_token 、 token_type=Bearer 和 expires_in=14400 ,说明无需用户登录即可取得访问令牌。为了判断令牌的实际权限,把它放入 Authorization 头,先调用用户详情接口。
GET /api/basicApi/user/getByUserId?userId=1000000000000000001 HTTP/1.1
Authorization:Bearer
Host:1XX.X.X.X16:30180
3.用户详情返回管理员信息,组织树接口返回完整部门数据。账号数据可以读取后,继续向案件列表提交分页条件,检查令牌是否还带有业务数据范围。
POST /api/questionApi/umEvent/listEvent HTTP/1.1
Authorization:Bearer
Content-Type:application/json
{"page":true,"current":1,"limit":1,"params":[],"descs":[],"ascs":[]}
4.响应头 page-total 为9,735,单条案件包含执法字段和真实业务内容。令牌来自公开前端凭据,又能读取管理员、组织树和案件数据,确认客户端密钥泄露已经形成完整的匿名后台访问链。
2.匿名上传与回读文件
漏洞情况
filesApi/files/upload 没有要求登录,上传后返回的文件名可通过同一业务域名直接读取。
上传接口和读取接口位于同一业务域名,文件保存后由服务端生成路径并返回。正常业务应当把附件与案件、用户或组织关联,当前匿名请求只提交文件即可落盘并回读。测试确认了普通文本的写入和读取,没有继续测试脚本执行,实际影响主要是未授权存储、可信域名托管和业务附件管理失控。
危害
攻击者可把目标系统当作公开文件存储使用,上传恶意文档或违规内容,并为后续钓鱼、脚本托管或数据暂存提供可信域名。
测试过程
1.先观察到文件读取接口与业务系统处于同一域名。为了判断上传是否必须先登录,不携带Cookie和Token,向 filesApi/files/upload 提交一个只含测试标记的文本文件。
POST /api/filesApi/files/upload HTTP/1.1
Host:1XX.X.X.X16:30180
Content-Type:multipart/form-data
file=@proof.txt
2.上传请求返回服务端生成的文件名,没有要求补充用户或案件信息。为了确认文件不是只返回名字而没有落盘,直接通过GET请求读取该文件名。
GET /api/filesApi/files/<返回的文件名> HTTP/1.1
Host:1XX.X.X.X16:30180
3.响应正文与上传的测试标记一致,文件可以在匿名状态下上传并回读。由于JSP没有在这组接口中执行,本次确认的影响限定为未授权存储、可信域名托管和附件管理失控。
3.同源SVG存储型XSS
漏洞情况
文件接口接受 image/svg+xml ,回读时保留SVG类型和其中的脚本内容。虽然上传响应为HTTP500,文件仍已生成并可访问。
服务端没有根据文件内容重新生成安全图片,也没有强制使用下载响应头。SVG中的脚本在回读域名下按同源页面解析,上传阶段的异常响应不影响文件落盘结果。影响取决于是否有已登录用户访问该文件,当前只验证了标题修改脚本,没有继续读取Cookie或执行后台操作。
危害
攻击者可构造同源主动内容页面。诱导已登录用户访问时,脚本可读取当前域可访问的数据或以用户身份发起操作。
测试过程
1.普通文本已经可以匿名上传,接下来检查服务端是否按文件内容限制主动格式。向同一接口提交SVG文件,文件中的脚本只修改页面标题,避免对访问者产生其他操作。
POST /api/filesApi/files/upload HTTP/1.1
Host:1XX.X.X.X16:30180
Content-Type:multipart/form-data
file=@proof.svg;type=image/svg+xml
2.上传响应为HTTP500,但同时返回了内部文件名。HTTP500可能意味着文件完全未保存,也可能只是响应封装异常,因此继续访问回读接口,检查文件是否已经落盘。
GET /api/filesApi/files/<返回的文件名> HTTP/1.1
Host:1XX.X.X.X16:30180
3.回读请求返回HTTP200,响应头为 Content-Type:image/svg+xml ,正文保留完整的


