测试那些没人愿意测试的接口,总能发现点什么

admin 2026-09-11 04:56:56 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文通过调试Cookie政策页面发现XSS漏洞的实战案例,强调测试被忽视端点的重要性。作者追踪URL中language参数未经校验即拼接进URL,最终通过innerHTML注入DOM形成XSS。文章指出自定义实现安全路径的潜在风险,建议安全测试人员关注非核心页面,逐行追踪数据流以发现类似漏洞。 综合评分: 88 文章分类: 漏洞分析,WEB安全,实战经验


测试那些没人愿意测试的接口,总能发现点什么

Adhamkhairy Adhamkhairy

漏洞集萃

2026年9月10日 15:35 山东

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

本公众号所发布的文章内容仅供学习与交流使用,禁止用于任何非法用途;如有侵权烦请告知,我们会立即删除并致歉,谢谢

在测试一个私有漏洞赏金计划时,我遇到了一个

作者: Adhamkhairy
原文链接: https://0xsponge.medium.com/debugging-endpoints-nobody-bothers-to-test-leads-to-some-crits-579eb9fbceb7

如何通过在调试器中阅读两行代码,将一个 Cookie 政策页面变成了一个关键漏洞。

该网址是这样一个无聊的链接:

https://app.example.com/cookie-policy/es/es

一个 Cookie 政策页面。路径中包含语言代码。仅此而已。

没人会测试这个。你看 /cookie-policy/通过测试工具查看时,你的视线会直接略过它,径直跳转到登录流程、文件上传、支付接口……任何真正能触发操作的地方。一个纯粹用于展示 Cookie 相关法律文本的页面,在任何测试目标中都是最无趣的东西。

我还是在上面打开了调试器,主要是出于固执。

Press enter or click to view image in full size

调试器告诉我这不是一个静态页面

我打开了该页面,启动了开发者工具,然后开始逐步调试。

没有理论,也没有预设的预期结果。只是在组件的早期阶段设置了一个断点,然后一行一行地向前执行,观察代码是如何自行运行的。

结果才看了几帧,我一开始的设想就彻底破产了。

我一直在阅读 /cookie-policy/es/es像处理任何本地化 URL 那样——将其视为静态路由。 en英语。有一个英语页面。它返回该英语页面。太无聊了,搞定,继续下一条。URL 看起来就是这个意思。

不过调试器显示 en根本没有选择任何页面。它只是作为值从路由中提取出来的:

const { language } = this.route.snapshot.params;

那不是路由。那是读取我的输入。我在地址栏中输入的字符串现在已成为应用程序内部的一个变量,而在输入过程中,没有任何机制检查它是否是一个真实的区域设置。

这重新定义了整个页面的攻击面。静态的区域设置路由没有攻击面。将路径片段提升为变量的页面,其攻击面大小完全取决于该变量后续被如何使用。

于是,我继续一步步地走下去。慢慢地。并不是在寻找有效载荷——只是沿着代码中属于我自己的那条线索,一行一行地追踪,直到看清它最终落在了哪里。

两帧之后:

Press enter or click to view image in full size

const link = AppConfig.cookieConsentFrameUrl + language;
trustArcWindow.html = trustArcWindow.html.replace("{path}", link);

于是,我就不读下去了。

这些话的实际含义是什么

重新向上: language直接取自 URL。既没有验证,也没有白名单,更没有检查它是否为真实的区域设置。

然后它会被拼接到一个配置 URL 上。不是 encodeURIComponent。不是 URL 对象。而是字符串拼接。

然后,将结果填入 HTML 模板中,通过替换一个 {path}占位符。

它被放置的模板是一个 iframe:

<iframe&nbsp;width='100%'&nbsp;height='800'&nbsp;src='{path}'></iframe>

因此,我的输入会直接进入一个 HTML 属性中,该属性位于即将被渲染的 HTML 字符串内。我又追踪了一个帧,想弄清楚它是如何被渲染的,结果就看到了:

addHtml(u){&nbsp;this.htmlContainer.nativeElement.innerHTML&nbsp;= u }

原始 innerHTML,直接写入 DOM 节点。

这是 Angular。Angular 提供了一个数据净化器。Angular 希望为你对数据进行净化——这正是 [innerHTML]绑定。有人绕过了它,直接向 nativeElement,这会关闭框架的内置保护机制。

源头与汇口,相距四行,其间空无一物。

Press enter or click to view image in full size

有效载荷会自动写入

一旦你能看到“sink”,那么这个创意就不再是富有创意的作品了。你只不过是在关闭已经打开的东西罢了。

我的数值位于 src='...'。因此:

  • '关闭该属性

  • >

    关闭 iframe 的开始标签

  • </iframe>

    — 这一点很重要。Iframe 的子元素会被解析为原始文本,因此你注入该元素内的任何内容都处于非活动状态。你必须先将其关闭,才能恢复为可解析的 HTML。

  • 那么,作为兄弟元素,你可以放任何内容

大致是这样的:

'></iframe><svg&nbsp;onload=...>

将其加载到一个新的标签页中,脚本便会在应用程序自身的源上执行。

正因如此,Cookie 政策页面便不再仅仅是一个 Cookie 政策页面。同源原则意味着注入的脚本位于应用程序的安全边界之内——它可以读取应用程序自身的端点,干预已登录用户正在进行的任何操作,并冒充该用户与后端进行交互。就这个特定目标而言,这意味着一个处理用户个人提交信息和文档上传的工作流。

这篇文章很无聊,但刊登它的平台却并非如此。

Press enter or click to view image in full size

Press enter or click to view image in full size

XSS 成功了!!!!!!

真正的教训

这就是我希望你们从中总结出的规律,因为这是可以反复运用的部分。

本地化内容的渲染是一个已解决的问题。每个框架都有相应的实现方法。最基础的实现方式如下:

@app.get("/{lang}") &nbsp;→ &nbsp;return&nbsp;templates[lang]

查询区域设置。返回模板。完成。输出中不包含任何用户输入。

当你发现有人用一种独特的方式在处理同一个已解决的问题时——比如通过 +,用 .replace(),或者将数据写入 innerHTML——而框架明明提供了经过安全处理的绑定接口——这每次都是一个危险信号。

并不是因为自定义代码不好。而是因为自定义代码意味着有人认为安全路径不适合他们的场景,于是偏离了这条路径。框架的默认设置在设计上就是安全的。任何围绕这些默认设置手动编写的代码,都是由开发者为了让功能正常运行而编写的,而非考虑当遇到恶意字符串时会发生什么。

已解决问题的自定义实现中往往存在错误。

而你只有通过设置断点,一行一行地阅读代码,才能看到它们,直到查明你的输入最终流向了哪里。这个过程既慢又乏味,这也正是我为何在其他人早已滑过的页面上,依然能发现那个线索的原因。

觉得本文内容对您有启发或帮助? 点个关注➕,获取更多深度分析与前沿资讯!

👉 往期精选

逻辑漏洞:邮箱注册 tips #11

非常用403绕过 Tips

Android IPC 漏洞利用系列

新技术绕过文件上传


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:漏洞集萃 Adhamkhairy Adhamkhairy《测试那些没人愿意测试的接口,总能发现点什么》

评论:0   参与:  0