What RPO?

RPO (Relative Path Overwrite)相对路径覆盖,作为一种相对新型的攻击方式,利用的是nginx服务器、配置错误的Apache服务器和浏览器之间对URL解析出现的差异,并借助文件中包含的相对路径的css或者js造成跨目录读取css或者js,甚至可以将本身不是css或者js的页面当做css或者js解析,从而触发xss等进一步的攻击手段。

利用条件

  • Apache 配置错误导致AllowEncodedSlashes这个选项开启(默认关闭),或者nginx服务器。
  • 存在相对路径的js或者css的引用

服务器解析差异

apache和nginx服务器两者对于%2f解析是不一样的。

默认情况下,apache服务器并不会解析%2f,即AllowEncodedSlashes=off:

但是nginx服务器默认会解析%2f

5

浏览器解析差异

在nginx中,会对编码后的url正常识别,也就是在服务器中会对url解析后找到正确的路径

但是浏览器识别url不会解析,所以并不认识%2f,那么就造成客户端与服务端两者的解析产生了差异

我们服务器上有index.php style.css两个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//index.php
<html>

<head></head>

<body>
<link href="style.css" rel="stylesheet" />
</body>

</html>

<?php
echo "RPO Test!";
?>

正常情况下,我们是可以访问index.php,会加载同目录下的style.css文件的:

6

但是一旦我们使用%2f,解析差异就会导致相对路径的文件错误:

7

我们本应该加载/RPO/style.css的,但是因为差异导致加载/RPO/index.php/style.css

简单的利用

当前文件夹文件分布:

1
2
3
4
5
6
─RPO
1.js
│ index.php

└─js
1.js

文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>

<head></head>

<body>
<script src=1.js></script>
</body>

</html>

<?php
echo "RPO Attack!";
?>
<!-- 同目录下的1.js为空文件
js文件下的1.js:
alert("RPO Attack success!"); -->

正常访问index.php,会加载当前目录下的1.js

8

倘若我们用%2f,就会出现不一样的情况:

9

我们可以发现,我们本来应该访问的是/RPO/index.php,但是却加载了/RPO/js/1.js,而且如果我们直接访问这个文件是不会执行的,但是这里却当作js执行了,触发了xss.

实现过程:

  • 我们访问:http://192.168.43.14/hack_to_learn/RPO/js/..%2findex.php
  • nginx服务器解析:http://192.168.43.14/hack_to_learn/RPO/js/../index.php
  • 服务器返回http://192.168.43.14/hack_to_learn/RPO/index.php内容给浏览器
  • 浏览器根据url路径来处理我们引用的相对路径文件,因为把..%2findex.php当作一个文件,所以它会调用当前路径下的1.js,自然就加载了当前目录下的1.js,因为引用的js被<script>标签包裹,所以会被当作js执行,触发了xss

既然我们可以加载静态资源文件,那么是不是还可以加载服务器返回的内容,将他当作css/js来解析呢,那么先来了解一下什么是pathinfo

Pathinfo模式

我们一般情况下,访问的url类似这种http://127.0.0.1/index.php?id=1&user=admin模式,称为动态url, 但在很多使用了url_rewrite的php开发框架以及python web框架中,会采用伪静态url类似这种http://127.0.0.1/index.php/1/admin(可以是任何模式,自己写规则)

这里我配置好了apache的url_write规则,当前目录下的index.php为:

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>

<head></head>

<body>
<link href="style.css" rel="stylesheet" />
</body>

</html>

<?php
echo ($_SERVER['PHP_SELF']);
?>

同目录下的style.css

1
2
3
body{
color: blue;
}

我们访问index.php会正常加载当前目录下的样式:

10

倘若我们访问/RPO/index.php/xxxx/,来看看会发生什么:

11

可以看到,RPO/style.css文件的路径变成了/RPO/index.php/xxxx/style.css,并且内容变成了index.php的内容,也就是说浏览器将服务器返回的内容当作css解析了,这就是为什么样式失效的原因(js同理)

这里本来是想弄一个将服务器返回内容加载成js的,因为AllowEncodedSlashes这个一配置就导致php无法解析,所以没有弄成功,找了半天没搞得什么原因…