某省会城市护网实战复盘(一)
原创
星宇Sec
星宇Sec
星宇Sec
2026年11月5日 00:21
山东
去阅读
一、护网背景
本次复盘来自某省省会城市政府护网实战。材料覆盖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
[email protected]
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
[email protected]
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
[email protected]
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 <token>
Host:1XX.X.X.X16:30180
3.用户详情返回管理员信息,组织树接口返回完整部门数据。账号数据可以读取后,继续向案件列表提交分页条件,检查令牌是否还带有业务数据范围。
POST /api/questionApi/umEvent/listEvent HTTP/1.1
Authorization:Bearer <token>
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
[email protected]
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
[email protected];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,正文保留完整的<script>内容。上传阶段的状态码没有代表存储结果,文件在当前业务域名下仍会按SVG解析,确认存在同源主动内容风险。
1XX.X.X.X05:9090 JEECG智慧安防平台
资产概况
平台基于JEECG6.3.30,包含部门、在线客户端、数据字典和安防业务数据。系统通过formate_data.do和systemController.do暴露多个通用数据接口。
1.匿名读取业务表
漏洞情况
formate_data.queryData未要求登录,分页参数经过URL编码后仍可正常解析,接口直接返回业务表总量和当前页记录。
该接口位于通用数据访问控制器中,使用请求参数选择数据表和分页条件。后缀形式和编码后的参数名仍能进入queryData动作,说明认证拦截和业务路由没有对同一接口形成一致判断。响应中的总量和样本足以证明匿名读取能力,继续修改页码可扩大读取范围。
危害
单次请求已返回约1,860万条记录总量,并可继续翻页读取实际字段内容。该能力可造成大规模业务数据泄露。
测试过程
1.先观察通用数据接口通过queryData动作和分页参数取数。为了检查认证过滤器是否会漏掉编码后的参数名,不携带Cookie和Token,把page和rows写成URL编码形式后请求第一页。
GET /http/formate_data.do?queryData&%70age=1&%72ows=1 HTTP/1.1
Host:1XX.X.X.X05:9090
2.响应中的total为18,602,106,records正常返回当前页记录,说明编码后的参数仍会被业务层还原。为了排除只返回统计总数的可能,把页码改为下一页并保持其他参数不变,检查是否能够继续取得不同记录。
3.改变页码后返回了新的记录,总量和字段结构保持不变。匿名请求既能取得数据规模,又能按页读取业务内容,确认queryData存在未授权数据访问。
2.匿名上传文件
漏洞情况
formate_data.uploadImage允许匿名提交multipart文件,文件写入webStatic/uploadImage并可直接访问。JSP上传没有成功执行。
上传动作只关注multipart文件字段,没有要求业务身份,也没有根据扩展名限制保存类型。普通文本文件被写入可公开访问的静态目录并可通过返回路径回读。JSP尝试没有成功,说明目标环境没有把该目录交给可执行容器处理,当前影响应限定为文件写入和托管。
危害
攻击者可写入任意普通文件并借助业务域名分发。当前确认的是文件存储和回读,没有确认命令执行。
测试过程
1.先向uploadImage提交一个普通文本文件,业务参数留空,检查上传动作是否先要求登录或有效业务单据。
POST /http/formate_data.do?uploadImage HTTP/1.1
Host:1XX.X.X.X05:9090
Content-Type:multipart/form-data
[email protected]
2.响应返回HTTP200、上传成功和/webStatic/uploadImage/日期/文件名,文件路径位于公开静态目录。为了确认文件确实保存,直接访问返回路径,正文与上传文本一致。
3.普通文件落盘后,再用同样方式提交JSP文件,检查静态目录是否会被应用容器执行。JSP请求连续返回空响应,返回路径也没有执行结果,因此该项只能确认文件上传和公开托管,不能认定为代码执行。
3.白名单请求体拆分绕过
漏洞情况
认证拦截器依据URL中的action判断是否放行,而业务控制器优先解析请求体中的action。两者取值不一致时,匿名请求会以白名单动作通过检查,再执行请求体指定的真实操作。
请求进入系统时会同时携带查询参数和表单参数,不同组件对action的取值顺序并不一致。测试把白名单动作saveFiles放在URL中,把真实业务动作放进请求体,从而先通过认证检查,再被控制器分发到目标查询。该问题并不依赖特定业务接口,任何复用同一分发链路的动作都应纳入排查。
危害
匿名用户可以触达本应登录的部门、在线客户端和其他后台查询接口,读取组织架构及终端信息。
测试过程
1.先请求一个不在白名单中的后台查询动作,响应为登录跳转页,确认该动作确实经过认证拦截。观察前端请求后发现URL和请求体都可能携带action,于是把白名单动作saveFiles放在URL中,把真实业务动作放进请求体,检查两个组件是否读取同一个值。
POST /systemController.do?saveFiles HTTP/1.1
Host:1XX.X.X.X05:9090
Content-Type:application/x-www-form-urlencoded
datagridDepart=1&page=1&rows=1&field=id,departname,orgCode,orgType,description
2.拆分后的请求返回HTTP200和total=188的部门数据,原来的登录跳转没有出现。为了确认这不是部门接口单独缺少权限,保持URL不变,只把请求体换成在线客户端查询字段。
3.响应返回total=1458及客户端记录,两个不同业务动作都通过同一白名单入口到达。结果确认拦截器按URL放行,而控制器按请求体分发,认证判断和实际执行对象并不一致。
4.匿名新增和删除字典
漏洞情况
同一请求体拆分方式可以调用字典分组和字典项的新增、查询、删除动作,服务端没有继续校验用户角色。
认证绕过建立后,字典控制器没有再次确认调用者身份。测试先读取分组和总数,再创建带随机标记的字典项,随后通过同一入口删除并复核数量。由于字典会影响下拉框、设备分类和业务校验,匿名写入可能造成配置错误,删除动作还可能破坏依赖该字典的业务页面。
危害
攻击者可增删业务字典,造成安防设备分类、部门字段或业务选项缺失和错误,影响后台展示与业务处理。
测试过程
1.先通过已经验证的请求体拆分通道读取字典分组,记录当前总数为94,同时确认调用过程没有会话信息。
POST /systemController.do?saveFiles HTTP/1.1
Host:1XX.X.X.X05:9090
Content-Type:application/x-www-form-urlencoded
typeGroupGrid=1&page=1&rows=1&field=id,typegroupname,typegroupcode
2.分组数据可以匿名返回后,提交一个带随机标记的字典分组,检查写操作是否还会执行角色校验。请求中保留白名单URL,只改变请求体中的业务动作和字段。
POST /systemController.do?saveFiles HTTP/1.1
Host:1XX.X.X.X05:9090
Content-Type:application/x-www-form-urlencoded
typegrid=1&typegroupcode=zzpt_retest&typegroupname=zzpt_retest
3.写入请求返回成功,重新读取字典树后出现zzpt_retest,分组总数从94增加到95。继续使用返回的记录标识调用删除动作,再读取同一列表,总数回到94,确认匿名用户不仅可以写,还可以删除字典项。
1XX.X.X.X8:8082 FRQ综合治税系统
资产概况
系统承载综合治税和业务流程数据,对外提供树查询、数据源配置和业务表单接口。数据库为Oracle,应用入口位于/FRQ/。
1.未授权时间盲注
漏洞情况
queryTreeByArrJson把arrJson中的fjhbh直接拼接到Oracle查询。匿名请求可注入DBMS_PIPE.RECEIVE_MESSAGE,并通过指定等待时间控制响应延迟。
接口主要用于加载树形业务数据,arrJson由前端提交并在后端解析后拼入SQL。单引号能够跳出原字符串,Oracle的DBMS_PIPE.RECEIVE_MESSAGE又允许用指定秒数产生可观察延迟。多次发送正常值、三秒载荷和八秒载荷后,响应时间与设定值对应,说明延迟来自数据库执行而不是网络波动。
危害
攻击者可以在未登录状态下推断数据库结构、表名和业务数据,严重时可读取完整业务库。多种等待秒数产生对应延迟,已排除普通网络抖动。
测试过程
1.先向树查询接口提交正常的fjhbh值,记录返回时间和响应正文,作为网络延迟的基线。
POST /FRQ/queryTreeByArrJson HTTP/1.1
Host:1XX.X.X.X8:8082
Content-Type:application/x-www-form-urlencoded
arrJson=[{\"fjhbh\":\"1\"}]
2.正常请求用时约0.4至1.5秒并返回空数组。空数组无法判断查询是否真正进入数据库,因此把输入改为闭合原字符串后调用DBMS_PIPE.RECEIVE_MESSAGE,并让载荷保持原查询结构,观察响应是否随指定秒数延迟。
[{\"fjhbh\":\"1') AND 1=DBMS_PIPE.RECEIVE_MESSAGE('d',8) AND ('1'='1\"}]
3.先发送8秒载荷,再分别用3秒和正常值重复请求。三次请求的HTTP状态均为200,正文仍为[],但3秒和8秒载荷产生对应延迟,正常值恢复原来的响应时间。
4.相同接口、相同参数结构和稳定可重复的延迟差异排除了偶发网络抖动,确认延迟由数据库函数执行,queryTreeByArrJson存在未授权时间盲注。
2.数据源配置泄露
漏洞情况
getDataCenters直接返回内部数据源配置,其中包含Oracle地址、端口、库名、账号和明文口令。
该接口原本用于前端或管理端读取数据源信息,返回结构没有区分运行配置和敏感凭据。匿名访问即可取得完整的连接参数,配合已经确认的SQL注入入口,会显著缩短攻击者定位数据库和尝试连接的过程。测试只记录配置泄露,没有使用账号口令创建新的数据库会话。
危害
拿到配置的攻击者可直接尝试连接数据库,并进一步读取或修改业务数据。测试没有使用泄露凭据连接数据库。
测试过程
1.先匿名请求数据源接口,检查它返回的是页面配置还是完整的运行参数。
GET /FRQ/getDataCenters HTTP/1.1
Host:1XX.X.X.X8:8082
2.响应返回结构化数据,其中包含内部Oracle地址、端口、库名、账号和明文口令,没有出现登录提示。为了确认这不是历史缓存或固定演示数据,后续再次检查配置状态,返回内容仍然有效。
3.配置未轮换说明泄露仍具备现实影响,但测试没有使用账号口令创建数据库会话,也没有读取更多业务数据。当前结论限于匿名读取真实连接配置,不把可能的数据库接管写成已经完成的结果。
2XX.X.X.XX2:8888 财政评审业务共享平台
资产概况
平台入口位于/yXXt,包含项目大屏、系统配置和账号相关接口。项目数据涉及建设单位、联系人、联系方式和审批状态。
1.大屏项目联系人泄露
漏洞情况
大屏项目查询和搜索接口没有校验登录态。匿名请求可一次性返回41条项目记录,每条包含156个字段,联系人和手机号字段均为非空。
大屏数据接口主要用于项目展示,为了适配前端一次性加载,返回字段远多于可视化页面需要。当前请求不需要令牌即可取得项目清单,搜索接口也会返回同一批记录。除联系人和手机号外,接口还包含项目单位、金额、状态和流程字段,暴露面大于单一联系方式。
危害
项目负责人和联系人信息可被批量获取,可用于后续社工、电话骚扰或结合其他系统扩大攻击面。
测试过程
1.大屏展示页可能对项目概况开放,因此先不携带认证信息请求项目接口,检查返回字段是否与页面展示范围一致。
GET /yXXt/workflow/project/getBigScreenProjectInfo HTTP/1.1
Host:2XX.X.X.XX2:8888
2.响应返回41条项目记录,每条156个字段,内容包含项目单位、金额、状态、联系人和手机号。字段明显超过大屏页面需要,为了确认不是全站认证失效,在同一会话中请求已知受保护的用户列表接口。
3.用户列表接口返回令牌不能为空和code=401,说明目标并非整体匿名开放。接着用POST搜索接口提交空搜索词,检查是否还能取得同一批项目数据。
POST /yXXt/workflow/project/searchBigScreenProject HTTP/1.1
Host:2XX.X.X.XX2:8888
Content-Type:application/json
{\"searchValue\":\"\"}
4.搜索接口同样返回41条记录,联系人和手机号字段均为41条非空。401对照与项目接口的成功响应形成明确差异,确认问题集中在项目大屏相关接口,影响是批量项目联系人泄露。
2.通用配置读取
漏洞情况
config/getPhoneConfig接受任意配置键并返回对应值。直接请求sys.user.initPassword时,响应同时暴露初始口令配置。
配置接口把键名放在URL末段,没有限制可读取的配置范围和调用者身份。sys.user.initPassword属于账号初始化参数,返回结果可用于判断系统是否仍使用统一口令。测试没有尝试使用该值登录真实账号,因此当前确认的是敏感配置读取,账号接管仍需结合实际口令状态判断。
危害
如果目标账号仍使用统一初始口令,攻击者可能直接登录。实际测试没有使用该口令登录任何账号,当前确认的是配置读取能力。
测试过程
1.先从账号初始化页面观察到配置键sys.user.initPassword会随请求发送。为了判断配置值是否对匿名用户可见,直接请求该键。
GET /yXXt/config/getPhoneConfig/sys.user.initPassword HTTP/1.1
Host:2XX.X.X.XX2:8888
2.响应中的msg和data均为初始口令值,没有要求登录。为了判断接口是否只能读取这一项,把最后一段换成普通系统配置键sysName,观察是否返回对应配置。
3.sysName也返回了实际配置值,确认接口按路径中的键名读取通用配置。测试没有使用初始口令尝试登录任何账号,因此能够确认的是敏感配置读取,账号是否仍使用统一口令需要另行核实。
3.账号相关接口匿名可达
漏洞情况
短信、注册和手机验证码登录接口可以被匿名请求进入业务处理逻辑,没有统一网关或登录前置校验。
这些接口分别承担短信下发、账号注册和手机验证码登录,正常流程应限制来源、频率和会话状态。测试只使用不存在的手机号和空JSON观察错误处理,接口返回账号存在性判断或业务参数异常,说明请求已经进入控制器。没有发送真实短信,也没有创建账号,影响集中在接口暴露和可被自动化调用的条件。
危害
当前已确认账号存在性判断和业务报错回显。若接口缺少频率控制,还可能被用于短信消耗或账号枚举,但测试没有发送真实短信或创建账号。
测试过程
1.先使用一个不存在的手机号请求短信接口,检查请求是否在进入业务逻辑前被登录或网关拦截。
GET /yXXt/extMessageTask/sendTextMessage?userName=00000000000 HTTP/1.1
Host:2XX.X.X.XX2:8888
2.响应返回账号不存在和code=500,说明请求已经到达账号查询逻辑。为了确认注册和验证码登录接口也处于同样的匿名可达状态,继续向两个接口发送空JSON。
POST /yXXt/auth/register HTTP/1.1
Host:2XX.X.X.XX2:8888
Content-Type:application/json
{}
3.注册接口返回用户或密码必须填写,手机验证码登录接口返回后台异常,两者都没有跳转到登录页。接口已经进入参数处理和账号流程,但测试没有创建账号,也没有发送真实短信,因此只确认账号存在性判断和匿名调用条件。
1XX.X.X.X6:58443 大华ICC智能物联平台
资产概况
平台为大华ICC-B8900-PRO,涉及账号、密码策略、密保问题、登录认证和内部组件。物联平台通常与视频、门禁和设备管理网络相连。
1.匿名账号与版本信息
漏洞情况
账号存在性、版本、站点、密保问题和密码策略接口均未要求认证。匿名请求可以确认admin账号存在,并取得精确产品版本和22个内部组件。
这些接口属于登录和账号管理模块,通常在进入验证码或认证流程之前调用。当前实现把它们直接暴露给匿名用户,产品版本、组件和密码策略可以帮助攻击者匹配已知漏洞并估算口令规则。账号存在性响应还会区分有效用户和无效用户,为后续口令尝试减少枚举成本。
危害
攻击者可以先确认高权限账号,再依据精确版本和组件查找公开漏洞,降低后续攻击的不确定性。
测试过程
1.先从登录页面抓取登录前的初始化请求,确认账号存在性接口会在验证码之前调用。为了检查它是否允许匿名访问,不携带Cookie和Token提交admin用户名。
POST /evo-apigw/evo-brm/1.0.0/user/is-exist HTTP/1.1
Host:1XX.X.X.X6:58443
Content-Type:application/json
{\"username\":\"admin\"}
2.响应返回账号存在及用户ID,没有出现认证失败。为了判断系统信息和密码策略是否同样暴露,继续请求产品版本接口。
GET /evo-apigw/evo-brm/1.0.0/config/get-version HTTP/1.1
Host:1XX.X.X.X6:58443
3.版本接口返回精确产品版本和22个内部组件,继续请求站点、密保问题和密码策略时也能取得对应内容。多个登录前接口共用同一匿名访问状态,确认账号枚举和组件信息收集不需要有效账号。
2.密保锁定按出口IP隔离
漏洞情况
密保失败次数绑定出口IP,而不是主要绑定目标账号。同一出口连续失败会锁定,但更换出口后,同一账号立即恢复新的尝试次数。
锁定策略在单一出口内有效,但没有把失败计数与账号、设备或全局风险状态关联。测试同一账号在一个出口触发锁定后,从另一个出口重新提交错误答案,服务端立即接受新的尝试。上述结果确认了限制可被绕开,实际重置仍需要正确密保答案,测试没有完成账号接管。
危害
攻击者可通过轮换出口继续尝试密保答案。实际测试没有提交正确密保答案,也没有调用重置接口,未确认可完成账号接管。
测试过程
1.先固定一个出口地址,对同一账号连续提交错误密保答案,观察失败计数和锁定提示何时出现。
2.连续三次错误后,接口返回5分钟锁定,说明该出口下的失败次数确实生效。为了判断锁定计数是否绑定目标账号,换到出口B后继续使用同一账号提交错误答案。
3.出口B没有继承出口A的锁定状态,立即返回新的业务校验结果,并允许继续尝试三次。结果确认失败次数主要按出口地址累计,没有与账号形成全局约束。
4.测试没有提交正确密保答案,也没有调用密码重置接口。当前能够确认的是同一账号可以通过更换出口重新获得尝试次数,尚未完成账号接管。
3.OAuth登录验证码与锁定
漏洞情况
登录接口是否要求验证码由客户端verifyCodeFlag控制。把该值改为0后,空验证码请求会直接进入用户名和口令校验,失败锁定同样按出口IP隔离。
服务端根据请求体中的开关决定是否校验验证码,客户端因此可以自行关闭这项安全步骤。关闭后,空验证码不会在进入口令校验前被拒绝,错误次数仍只按出口地址计数。目标端口在后续复测时已经不可达,当前结论来自当时的请求和响应,没有取得有效口令或完成登录。
危害
验证码保护可被请求方关闭,账号口令校验更容易被自动化尝试。测试没有获得有效口令,且目标后续端口不可达,未完成完整登录验证。
测试过程
1.先保持服务端默认参数verifyCodeFlag=1,向登录接口提交空验证码,观察验证码校验是否在口令校验前执行。
POST /evo-apigw/evo-oauth/oauth/token HTTP/1.1
Host:1XX.X.X.X6:58443
Content-Type:application/x-www-form-urlencoded
username=<RSA值>&password=<RSA值>&code=&grant_type=password&client_id=web_client&client_secret=<client_secret>&public_key=<公钥>&rememberFlag=false&verifyCodeFlag=1
2.响应提示验证码不能为空,说明请求没有进入用户名和口令校验。由于开关就在请求体中,只把verifyCodeFlag改为0,其他参数和空验证码保持不变,检查服务端是否直接信任客户端传入的开关。
3.修改后的请求不再提示验证码错误,而是直接进入用户名和口令校验。为了判断失败锁定是否也存在按出口隔离的问题,在同一用户名连续失败后切换出口IP。
4.切换出口后失败计数重新开始,与密保接口的行为一致。测试没有取得有效口令,后续复测时目标端口已经不可达,因此以上结论来自当时的实际请求和响应,没有完成登录。
五、修复建议
1XX.X.X.XX6
所有上传接口统一增加身份和业务权限校验,上传目录移出Web根目录,禁止JSP执行。为工单和文件记录增加服务端归属检查,不信任客户端openid。关闭公网Druid,精确限制Swagger访问,并对字典写接口增加角色校验和审计。
2XX.X.X.18:8088
将模型、定义、导入、导出和部署接口统一纳入管理员权限,禁止匿名用户访问流程引擎管理功能。生产环境关闭不必要的ScriptTask,限制脚本类和外部调用。流程模型key先做白名单和规范化处理,导出文件不得落入可公开访问的目录。
1XX.X.X.X16:30180
撤销所有前端硬编码凭据并轮换已暴露密钥,公共客户端改用授权码加PKCE,客户端凭据只允许受限服务间调用。用户、组织和案件接口必须同时校验角色与数据范围。filesApi要求登录和归属校验,SVG、HTML等主动内容应独立域名托管或强制下载。
1XX.X.X.X05:9090
统一网关、过滤器和SpringMVC对路径、查询参数与请求体的解析顺序,白名单精确到端点和方法。queryData、上传和字典写接口全部增加身份和角色校验,限制分页、导出与文件类型,清理历史测试文件和无用白名单条目。
1XX.X.X.X8:8082
所有数据库查询改为参数化,禁止把业务参数直接拼入SQL。立即轮换数据库账号和口令,改用最小权限账号,关闭不必要的数据源配置返回。无法确认网络可达性时,也要按凭据已经泄露处理。
2XX.X.X.XX2:8888
取消统一初始口令,首次登录强制改密。大屏、配置、短信、注册和手机验证码登录接口全部增加认证、频率限制和业务校验,联系人手机号按最小必要原则返回。配置接口只返回当前页面需要的键,不能通过空参数读取全量配置。
1XX.X.X.X6:58443
登录验证码开关必须在服务端控制,失败次数按账号、设备和其他因素共同限制,不能仅按出口IP计数。密保找回流程应增加二次验证和风险评分。版本、内部组件、密码策略等接口只向已认证用户返回必要内容。
六、结语
这组IP资产的复现过程说明,很多风险并不需要复杂的前置条件。一个公开接口、一个格式变形的路径或者一个客户端可控参数,就可能让匿名请求进入真实业务。
修复时不能只拦截已经出现的字符串。认证、路由、参数解析、文件处理和流程引擎需要统一使用同一套判断,才能避免同一入口在更换payload或路径后继续绕过。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论