来源
https://www.freebuf.com/articles/web/166731.html
http://blog.nsfocus.net/rpo-attack/
RPO(Relative Path Overwrite)相对路径覆盖,是一种新型攻击技术,主要是利用浏览器的一些特性和部分服务端的配置差异导致的漏洞,通过一些技巧,我们可以通过相对路径来引入其他的资源文件,以至于达成我们想要的目的
就目前来看此攻击方法依赖于浏览器和网络服务器的反应,基于服务器的Web缓存技术和配置差异,以及服务器和客户端浏览器的解析差异,利用前端代码中加载的css/js的相对路径来加载其他文件,最终浏览器将服务器返回的不是css/js的文件当做css/js来解析,从而导致XSS,信息泄露等漏洞产生。
看一下我们的目录结构
WWW\RPO
111\
1.php
222\
style.css
x.js
style.css
x.js
相应的代码
#RPO/1.php
<h1>We are now in RPO/111/1.PHP</h1>
<link rel="stylesheet" href="../style.css" style="css" />
<script src=../x.js></script>
#RPO/style.css
h1 {
font-size:80px;
color:blue;
}
#RPO/222/style.css
h1 {
font-size:80px;
color:red;
}
#RPO/x.js
alert('wo are in RPO/x.js')
#RPO/222/x.js
alert('we are in RPO/222/x.js')
在apache和nginx环境下访问
http://localhost/RPO/111/%2f1.php
在Nginx和apache中,编码后的url服务器可以正常识别,也就是说服务器在加载文件时会解码后找到具体文件返回返回客户端。(在绿盟的这篇文章中提到说Apache无法解析这种URL,会返回404。其实是默认配置的问题,可以来看这篇文章)
但是在客户端识别url时是不会解码的,正常情况下解码%2f解码后应该加载的是RPO/111/…/x.js,最后也就是RPO/x.js文件;而这里加载的是/x.js,所以浏览器是没有解码%2f的。
实际上通过测试,客户端浏览器在加载相对路径文件时是以最后一个/为相对目录加载具体资源文件的
访问http://localhost/RPO/111/1.php
一切正常
如果/RPO/222/x.js
文件中的内容是我们可控的,但是有过滤不能写入等标签内容,那么如何利用此跨站漏洞呢?
有没有办法使1.php
加载到其他目录的静态资源文件,比如这里让1.php加载到/RPO/222/x.js
文件,这样就可以直接执行js代码了。
如我们访问http://localhost/RPO/222/2.php%2f..%2f..%2f111/1.php
可见我们加载了1.php中的内容,但是加载了RPO/222/x.js
和RPO/222/style.css
原理解析
这里服务器端识别为:
/RPO/222/2.php/../../111/1.php
实际上也就是/RPO/111/1.php
客户端识别为:
/RPO/222/2.php%2f..%2f..%2f111/1.php
,把2.php%2f..%2f..%2f111
当成一个目录,然后在加载静态资源文件时,比如这里加载../x.js
时,就会跳转到上一级目录222
目录下,(还记得前面说过客户端浏览器在加载相对路径文件时是以最后一个/为相对目录加载具体资源文件的)最后加载的静态文件为/RPO/222/x.js
。
此时成功加载到了其他目录下的文件。
这里有Apache和Nginx设置伪静态(URL Rewrite)的方法
以下是我的nginx rewrite_url设置,具体的含义看上面的链接
当我们在浏览器地址栏访问http://localhost/RPO2/index/page/4455
时,服务端接受到此url后,实际的路由是http://localhost/RPO2/index.php?page=4455
现在的目录结构
WWW\RPO2
test\
123456.txt
index.php
index.php
<!DOCTYPE html>
<html>
<head>RPO attack test<br></head>
<body>
<script src="3.js"></script>
</body>
</html>
error_reporting(E_ALL^E_NOTICE^E_WARNING);
if($_GET['page'])
{
$a=$_GET['page'];
Header('Location:http://localhost/RPO2/test/'."$a".'txt');
}
?>
#123456.txt
alert(233)
可以看到我们在index.php里加载了3.js
这是一种相对路径加载,并且我们用Header
函数做了跳转,跳转到test
目录下的txt文件
假设我们可控的是test
目录下的文件内容,但是无法直接插入标签,而且开启了rewrite_url,所以这里我们采用RPO来加载我们的
js
代码
注:这里的
3.js
还有123456.txt
文件名是任意的,因为我的nginx的rewrite_url文件名只匹配数字,所以我在Location:http://localhost/RPO2/test/'."$a".'txt'
加了.txt
访问localhost/RPO2/index/page/123456
可以看到跳转到了123456.txt
,页面返回了alert(233)
的文本内容
当我们访问http://localhost/RPO2/index/page/123456.txt/..%2f..%2f..%2findex.php
可以看到123456.txt
里的内容被当做js
代码执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GVHJec35-1593606034380)(https://s2.ax1x.com/2019/04/27/EKe3cj.png)]
我们来看一下执行过程
1.我们向服务器请求URL:
http://localhost/RPO2/index/page/123456/..%2f..%2f..%2findex.php
2.服务器看到的是:
http://localhost/RPO2/index/page/123456/../../../index.php
3.服务器返回index.php页面给浏览器
http://localhost/RPO2/index.php
4.浏览器加载index.php文件,并加载同目录下的3.js,但是浏览器看到的URL是:
http://localhost/RPO2/index.php/page/123456/..%2f..%2f..%2findex.php
5.浏览器认为…%2f…%2f…%2findex.php是一个页面,自然而然加载的URL就是:
http://localhost/RPO2/index.php/page/123456/3.js
6.而此时我们index.php
中用Header
函数跳转到12356.txt
,所以123456.txt
中的内容会展示的页面中,并且由于我们的请求是由生成的,所以返回给我们的
alert(233)
内容会被浏览器当做是js解析。