
搞过应用安全的朋友大概率都踩过这样一个痛点:面对分布式微服务架构,传统SAST工具早已经显得力不从心。一个用户请求从前端发起,经中间层路由至后端服务集群,需要穿透多个微服务节点;而污点数据会通过REST API、gRPC 调用、Kafka消息队列等多类通道跨服务流转。此时,传统SAST聚焦单服务内部的漏洞检测逻辑,已经无法适配这种跨服务、多链路的复杂数据流场景 ,这类跨服务调用链中的漏洞很难被精准识别。
今年Black Hat 2025 USA大会上Fengyu Liu团队发布的MScan工具,用 “LLM入口识别+插件化跨服务追踪+距离引导污点分析”的三层架构,直接在25个开源项目(1K+ GitHub Star)和5个金融级工业应用中检出59个0-day漏洞,召回率100%、准确率71.95%,全面超越CodeQL。本文将基于 Fengyu Liu 团队在大会上公开的演讲 PPT,简要分析MScan的技术架构、给大家提供一些方向参考。
微服务的去中心化、通信多样化特性,让污点漏洞(SQL注入、命令执行、任意文件写入等)的检测难度增加,传统工具的SAST、DAST短板变得尤其明显。
微服务的访问入口由网关路由规则统一管控,但非结构化的网关配置易形成检测盲区,导致那些间接可达的漏洞接口被传统 SAST 工具遗漏。这类隐藏入口点的核心风险在于:网关虽拦截了目标服务的直接访问路径,但是无法阻断其他服务通过内部调用转发请求,进而让被 “屏蔽” 的漏洞路径成为间接攻击通道 。典型场景如下:
/user/**路径返回 403 拒绝访问,看似阻断了对 User Service 的直接调用,但 Portal Service 作为可正常访问的中间服务,能接收用户输入并通过内部接口转发至 User Service;/portal/query接口直接接收用户可控的 id参数,该参数未经任何过滤处理,便通过 ScriptEngineManager.eval方法执行动态脚本,最终形成高危的服务内代码注入漏洞。代码实现如下:java// Portal Service (可访问) @Path(value = "/portal/query")publicUserquery(Stringid){Stringquery=(newScriptEngineManager()).eval(id);// 污点数据直接执行,无净化returnselect(query);}/user/**排除(漏报跨服务漏洞),要么将所有接口识别为漏洞(误报)。微服务架构中,服务间通信同时存在REST、gRPC等同步调用方式,以及Kafka、RabbitMQ等异步消息队列机制,这种混合通信模式使得污点数据的跨服务传递路径在代码层面表现为断裂的状态。传统SAST工具只能分析单个服务内的代码逻辑,无法跨服务串联污点数据的完整流转链路,最终形成跨服务数据流的检测盲区,让这类跨服务传导的漏洞成为潜在的漏网之鱼。
id参数未经净化直接写入 Kafka 消息队列,User Service 从队列中消费该消息后,直接提取 id参数传入 eval方法执行动态脚本,最终形成跨服务的代码注入漏洞。完整的跨服务漏洞代码实现如下:// 1. Portal Service (可访问) @Path(value = "/portal/query") publicUser query(String id){String op ="query";KafkaProducer kafkaProducer =newKafkaProducer();kafkaProducer.send(id);// 将用户输入id异步发送至Kafka}// 2. User Service (不可直接访问) @KafkaListener(topics="user/query") publicUser queryTask(){String id = kafkaConsumer.poll();// 从Kafka接收id(污点数据)String query =(newScriptEngineManager()).eval(id);// 直接执行,无净化return select(query);}传统工具只能分析单服务代码,无法识别 KafkaProducer.send与 KafkaConsumer.poll的通信关联,这类场景会导致跨服务传导。
在电商或金融等这类中大型复杂业务场景的微服务架构中,调用链深度甚至达到10层以上,传统SAST工具在对这类长调用链做上下文分析时,会面临性能与精度不可兼得的困境,如果采用 “全上下文敏感分析”,会因上下文对象数量呈指数级膨胀引发内存溢出(OOM),导致工具直接崩溃;如果为了规避性能问题改用固定的深度分析(例如2层调用链),又会因调用链分析被强行截断,牺牲漏洞检测的精度,最终造成漏洞漏报。
以一个典型的电商场景为例:
MScan基于Tai-e静态分析引擎构建,仅通过7K行Java代码便实现了 8 类典型微服务漏洞的检测能力,核心通过 “LLM 辅助入口识别 → 跨服务依赖图 → 污点分析” 三步递进的技术路径解决微服务安全检测中隐藏入口遗漏、跨服务数据流盲区、长调用链性能失衡三大核心痛点。
针对网关路由规则非结构化导致的隐藏入口遗漏问题,MScan 引入大语言模型(LLM)解析网关配置文件识别用户实际可达的接口代码路径 ,从源头上剔除无效分析链路,大幅降低后续污点追踪的计算开销。
输入路由规则:portal-route: path:/portal/**; util-route: path:/util/**; filter: denyLLM 输出结果:["/portal/**"](自动过滤被 deny规则拦截的/util/**路径)代码层面价值 :仅将 /portal/query等网关允许访问的接口代码纳入分析范围,直接排除 /user/**等被屏蔽的不可达接口,从根源上减少无意义的污点数据追踪与分析,提升检测效率。Fengyu Liu团队通过对照组实验验证了这个思路的有效性,如果关闭入口过滤功能(MScan-NoEntry)后,检测结果的误报数量从 23 骤增至 89,整体检测准确率从 71.95% 大幅降至 39.86%。从对照组数据结果看,LLM 辅助的入口识别环节能有效削减代码层面的误报源,这里面得益于大模型强大的上下文分析能力。笔者之前所在团队在自研DAST中使用了LLM来识别接口上下文,特别是在未授权类访问类漏洞识别准确率上收益极为明显,准确率可达90%以上,另外在接口识别中可以有效的排除增删改类接口,能够极大降低脏数据对业务的影响。
MScan为每类通信框架开发专属插件,识别跨服务通信API,在代码层面构建 “communication edge”,串联不同服务的控制流。
| 框架 | 类型 | 关键 API |
|---|---|---|
| OpenFeign | 同步 | @FeignClient注解、 @Target接口 |
| RestTemplate | 同步 | RestTemplate.exchange/ get/ post |
| Kafka | 异步 | KafkaProducer.send/ KafkaConsumer.poll |
| gRPC | 同步 | *BlockingStub.*/ *ImplBase.* |
在代码层面构建依赖图:
以Kafka通信为例,插件识别 KafkaProducer.send(id)(Portal Service)与 KafkaConsumer.poll()(User Service)的关联,在SDG中添加Portal到User 的communication edge,使污点数据 id的流转路径变得可追踪 。
实验验证:
关闭跨服务communication edge(MScan-NoSDG)后,仅能检出27个服务内漏洞,32个跨服务漏洞被漏报,召回率降到了45.76%。
MScan以污点传播距离为核心调度机制,针对代码调用链中的关键节点实施差异化分析,对近距核心节点进行深度上下文敏感分析,对远距非关键节点采用轻量化处理方案,从根源上规避 OOM 风险,同时最大化分析效率。
典型调用链示例:/portal/query接口(污点源,距离0)→PortalService的KafkaProducer.send(直接调用,距离1,上下文敏感分析)→Kafka队列(中转节点,距离2,轻量化简化处理)→UserService的KafkaConsumer.poll(间接调用,距离3,上下文敏感分析)→eval(id)(漏洞高风险点,距离4,上下文敏感分析);这里仅对距离≤4的节点做上下文分析,既保证 eval(id)的漏洞点精准识别,又避免长调用链的性能损耗,在检测精度与性能之间做了平衡取舍。
| 方案 | 召回率 | 准确率 | 超时率 |
|---|---|---|---|
| 全上下文分析 | 49.15% | 72.50% | 30% |
| 双层调用策略 | 100% | 19.03% | 0% |
| 距离引导机制 | 100% | 71.95% | 0% |
MScan的有效性在三类典型场景中得到验证,以下根据PPT中的代码片段推导的检测逻辑。
漏洞背景:Stream Service接收用户上传参数,漏洞根因是Stream Service 通过 RestTemplate 传递用户可控的文件参数,Package Service 未校验路径可以达成任意文件写入。
核心代码片段:
// 1. Stream Service入口:/streams/deployments @RequestMapping("/streams/deployments")publicResponse deploy(Map<String,String> properties){this.deployStream.upload(properties);// 接收用户输入(污点源)}// 2. RestTemplate跨服务调用 String url =String.format("%s/%s", baseUrl,"upload");Object response = restTemplate.exchange(url, entity);// 调用Package Service// 3. Package Service写入文件(污点sink)@RequestMapping("/api/package/upload")publicMetadata uploadFile(UploadRequest req){Path file =Paths.get(uploadDir + req.getName());// 未校验路径Files.write(req.getFileAsBytes(), file);// 直接写入,触发任意文件写入returnMetadata;}MScan检测逻辑:
1、RestTemplate插件识别exchange调用,构建跨服务依赖;2、污点分析追踪 properties→req.getFileAsBytes()的流转路径;3、发现Files.write(sink)无路径净化,命中告警。漏洞背景:
Device Rest接口接收 alternateId,通过gRPC传给Event Service,直接拼接SQL导致SQL注入漏洞;
核心代码片段:
// 1. Device Rest入口:/alternate/{alternateId} @Path("/alternate/{alternateId}")publicEvent getDeviceEventById(Request request){return getEvent(request.getAltId());// 接收alternateId(污点源)}// 2. gRPC跨服务调用 publicEvent getEventByAltId(String alternateId){EventGrpc.EventStub stub =EventGrpc.newStub();return stub.getDeviceEventById(alternateId);// 调用Event Service}// 3. Event Service SQL拼接(污点sink)publicstaticIDeviceEvent getEvent(String altId){String query ="select * from events where altid="+ altId +";";// 直接拼接return getInflux().query(query);// 执行SQL,触发注入}MScan检测逻辑:
1、gRPC插件识别EventGrpc.newStub()调用,串联跨服务数据流;2、污点分析发现 altId直接进入SQL拼接(无预编译/过滤)判定为SQL注入漏洞。漏洞背景:
Web Service接收用户URL,通过OpenFeign传给Picture Service,可以直接构造URL对象;
核心代码片段:
// 1. Web Service入口:/wechatCheck @PostMapping("/wechatCheck")publicString index(HttpServletRequest request){FileVO fileVO =newFileVO();fileVO.setUrl(request.getParameter("url"));// 接收用户URL(污点源)return pictureClient.uploadPicsByUrl(fileVO);}// 2. OpenFeign跨服务调用 @FeignClient("mogu-picture")publicinterfacePictureFeignClient{@Target(value ="/uploadPicsByUrl")String uploadPicsByUrl(FileVO fileVO);// 调用Picture Service}// 3. Picture Service构造URL(污点sink)publicString uploadPictureByUrl(FileVO fileVO){URL url =new URL(fileVO.getUrl());// 直接用用户URL构造对象,无校验// 后续请求逻辑,触发SSRF}MScan检测逻辑:
1、OpenFeign插件识别@FeignClient注解,构建Web到Picture的 communication edge(这个不晓得咋翻译合适);2、污点分析发现 fileVO.getUrl()直接进入 URL,判定为SSRF漏洞。Fengyu Liu团队在MScan项目中的技术创新,给甲方应用安全团队落地微服务漏洞的代码级检测提供了可直接参考的实践路径,这是LLM在SAST落地的一个优秀的细分的落地案例,比较平衡的解决了跨服务漏洞识别的难题。一方面解决在没有IAST的情况下,以及在一切皆可code的DevSecOps场景下实现最大化的ROI,另外这个思路还可以延伸到与DAST的联动,实现静态扫描 + 动态验证。
微服务跨服务污点传递的核心载体是各类通信框架的API,实战中需将这类API的代码路径作为检测重点:
send/ poll方法、gRPC的 Stub类调用、OpenFeign的 @FeignClient注解等,这些是跨服务漏洞的核心触发节点;网关路由规则的非结构化特性,加上数量变大的话导致人工解析效率低、不仅成本高也容易遗漏,利用LLM实现网关配置的自动化预处理,充分发挥LLM优势:
application.yml等网关配置文件,利用LLM批量解析并提取用户可达的接口列表,仅对这些接口对应的代码开展检测,大幅减少无效分析工作量;微服务长调用链下,全上下文敏感分析容易引发性能瓶颈,可以根据代码调用深度动态调整分析策略,平衡检测精度与效率:
MScan的创新在于将原本只能由IAST完成的跨服务污点追踪能力,左移到了SAST阶段,初步实现代码级别的串联检测,为微服务架构的漏洞检测提供了创新思路。在这里给项目团队点个赞,同时也期待甲方同学点企业级落地实践案例。
附:
项目开源地址:https://github.com/LFYSec/MScan
PPT截图:









































