5.2 HackerOne非预期HTML包含漏洞

难度:

URL:https://hackerone.com/reports/<report_id>/

报告位置:https://hackerone.com/reports/110578/

报告日期:2016年1月13日

支付奖金:500美元

本例和下一节中的例子都需要理解Markdown、悬挂单引号、React和文档对象模型(DOM),因此,我将先介绍这些概念,然后再看它们是如何导致这两个漏洞的。

Markdown是一种使用特定语法生成HTML的标记语言。例如,Markdown会接受和解析以#为前导的纯文本并返回以标题标签格式化的HTML。标记# Some Content将会生成HTML标签<h1>Some Content</h1>。开发者在网站编辑器中使用Markdown,主要是因为它使用起来非常简单。另外,在允许用户提交输入的网站上,开发者不必担心HTML会发生格式错误,因为编辑器会自动处理并生成相应的HTML。

本节讨论的漏洞使用Markdown语法生成一个具有title属性的<a>锚标签。通常情况下,语法如下:

中括号中的文本就是要显示的文本,链接到该文本的URL包含在小括号中,并且具有一个title属性,该属性包含在一对双引号中。该语法产生如下的HTML:

2016年1月,漏洞挖掘者Inti De Ceukelaire发现HackerOne的Markdown编辑器存在配置错误,攻击者可以在使用Markdown编辑器的任何地方向Markdown语法注入一个悬挂单引号,并将在最终生成的HTML中呈现出来。漏洞奖励项目管理页面和相应的报告页面都存在这个漏洞风险。这一点非常重要:如果攻击者能够在管理页面上发现另一个漏洞并在<meta>标签页的开始处注入另一个悬挂单引号(注入整个<meta>标签,或者在<meta>标签中注入内容),就可以利用浏览器的HTML解析来提取网页内容。原因在于<meta>标签会告诉浏览器通过其content属性中定义的URL来刷新网页。当呈现该网页时,浏览器就会向指定的URL发起GET请求。页面内容就可能会被作为GET请求的参数发送出去,攻击者就可以基于这些内容来获取目标对象的数据。下面是一个具有注入单引号的恶意<meta>标签的例子:

0定义了浏览器在向URL发起HTTP请求时需要等待的时间。本例中,浏览器将立即向https://evil.com/log.php?text=发起HTTP请求。HTTP请求将包含content属性开始处的单引号与攻击者使用Markdown解析器注入网页上的第二个单引号之间的所有内容。示例如下:

从content属性在❶处的第一个单引号开始到❷处攻击者注入的单引号为止的网页内容,都将作为URL text参数的一部分发送给攻击者。当然也包含隐藏在input域中的敏感跨站请求伪造(CSRF)令牌。

通常,这种HTML注入风险对于HackerOne来说并不是问题,因为它使用了React JavaScript框架来呈现HTML。React是Facebook开发的用于自动更新网页内容而不必重新加载整个网页的框架库。React的另一个优点是除非使用JavaScript函数dangerouslySetInnerHTML来直接更新DOM或者呈现HTML,否则它会转义所有HTML(DOM是HTML和XML文档的API,允许开发者通过JavaScript修改网页的结构、风格和内容)。事实证明,HackerOne使用了dangerouslySetInnerHTML,因为它相信从服务器接收到的HTML,因此,它就在DOM中被直接注入了HTML而没有进行转义。

尽管Ceukelaire不能利用该漏洞,但他确实标识出了在HackerOne加载CSRF令牌后他能注入单引号的网页。因此从概念上来说,如果HackerOne将来做了代码修改并且允许攻击者能够在同一个页面的<meta>标签中注入另一个单引号的话,攻击者就可以提取目标对象的CSRF令牌进而发起CSRF攻击。HackerOne认可了这个潜在的威胁,修复了报告中的漏洞,并支付了500美元奖金。

要点

深入理解浏览器如何呈现HTML和响应特定HTML标签的细微差别,将为我们打开一个很大的攻击面。尽管并不是所有的漏洞奖励项目都会接受关于潜在理论攻击的漏洞报告,但是这些知识的确有助于发现其他漏洞。FileDescriptor在https://blog.innerht.ml/csp-2015/#contentexfiltration中有很多关于<meta>刷新利用的解释说明,你可以去看看。