0x01 代码执行
问题出在数据备份然后可以代码执行
抓包可以看到请求的php文件为/e/admin/ebak/phome.php,这里来看下代码
获取phome参数内容为DoEbak
跟踪过来
继续跟踪Ebak_DoEbak函数
function Ebak_DoEbak($add,$userid,$username){
global $empire,$public_r,$fun_r,$ecms_config;
//验证权限
CheckLevel($userid,$username,$classid,"dbdata");
$dbname=RepPostVar($add['mydbname']); //$dbname = empirecms
if(empty($dbname)){
printerror("NotChangeDbname","history.go(-1)");
}
$tablename=$add['tablename'];
$count=count($tablename);
if(empty($count)){
printerror("MustChangeOneTable","history.go(-1)");
}
$add['baktype']=(int)$add['baktype'];
$add['filesize']=(int)$add['filesize'];
$add['bakline']=(int)$add['bakline'];
$add['autoauf']=(int)$add['autoauf'];
if((!$add['filesize']&&!$add['baktype'])||(!$add['bakline']&&$add['baktype'])){
printerror("FileSizeEmpty","history.go(-1)");
}
//目录名
$add['mypath']=RepPostStr($add['mypath'],1);
$bakpath=$public_r['bakdbpath'];
if(empty($add['mypath'])){
$add['mypath']=$dbname."_".date("YmdHis");
}
DoMkdir($bakpath."/".$add['mypath']);
//生成说明文件
$readme=$add['readme'];
$rfile=$bakpath."/".$add['mypath']."/readme.txt";
$readme.="
Baktime: ".date("Y-m-d H:i:s");
WriteFiletext_n($rfile,$readme);
$b_table="";
$d_table="";
for($i=0;$i<$count;$i++){
$tablename[$i]=RepPostVar($tablename[$i]);
$b_table.=$tablename[$i].",";
$d_table.="$tb[".$tablename[$i]."]=0;
";
}
//去掉最后一个,
$b_table=substr($b_table,0,strlen($b_table)-1);
$bakstru=(int)$add['bakstru'];
$bakstrufour=(int)$add['bakstrufour'];
$beover=(int)$add['beover'];
$waitbaktime=(int)$add['waitbaktime'];
$bakdatatype=(int)$add['bakdatatype'];
if($add['insertf']=='insert'){
$insertf='insert';
}
else{
$insertf='replace';
}
if($ecms_config['db']['dbver']=='4.0'&&$add['dbchar']=='auto')
{
$add['dbchar']='';
}
$string="<?php
$b_table="".$b_table."";
".$d_table."
$b_baktype=".$add['baktype'].";
$b_filesize=".$add['filesize'].";
$b_bakline=".$add['bakline'].";
$b_autoauf=".$add['autoauf'].";
$b_dbname="".$dbname."";
$b_stru=".$bakstru.";
$b_strufour=".$bakstrufour.";
$b_dbchar="".addslashes($add['dbchar'])."";
$b_beover=".$beover.";
$b_insertf="".addslashes($insertf)."";
$b_autofield=",".addslashes($add['autofield']).",";
$b_bakdatatype=".$bakdatatype.";
?>";
$cfile=$bakpath."/".$add['mypath']."/config.php";
WriteFiletext_n($cfile,$string);
if($add['baktype']){
$phome='BakExeT';
}
else{
$phome='BakExe';
}
echo $fun_r['FirstBakSuccess']."<script>self.location.href='phome.php?phome=$phome&t=0&s=0&p=0&mypath=$add[mypath]&waitbaktime=$waitbaktime".hReturnEcmsHashStrHref(0)."';</script>";
exit();
}
我们一步步来看
&mydbname=empirecms
首先是获取post包里的mydbname赋值给$dbname,如果为空就返回失败,然后就是获取这个数量
然后就是获取名字,这个就是保存备份的文件夹名跟踪一下RepPostStr
可以看到做了过滤这里就没法利用继续看下去
跟一下WriteFiletext_n函数
可以看到写入内容给readme.txt文件这里就是生成了一个说明文件打开看一下
然后就是把数据包里的tablename全部赋值过来
然后就写入config.php里面
但是没有对其添加双引号,我们先看一下正常的文件
所以我们把tablename内容改为phpinfo()
先看下本地
然后把readme.txt改为config.php
0x02 上传+文件包含
先随便上传一个文件
请求了/e/admin/ecmsmod.php文件
先获取了enews值
跟踪一下LoadInMod函数
//导入系统模型
function LoadInMod($add,$file,$file_name,$file_type,$file_size,$userid,$username){
global $empire,$dbtbpre,$ecms_config;
//验证权限
CheckLevel($userid,$username,$classid,"table");
$tbname=RepPostVar(trim($add['tbname']));
if(!$file_name||!$file_size||!$tbname)
{
printerror("EmptyLoadInMod","");
}
//扩展名
$filetype=GetFiletype($file_name);
if($filetype!=".mod")
{
printerror("LoadInModMustmod","");
}
//表名是否已存在
$num=$empire->gettotal("select count(*) as total from {$dbtbpre}enewstable where tbname='$tbname' limit 1");
if($num)
{
printerror("HaveLoadInTb","");
}
//上传文件
$path=ECMS_PATH."e/data/tmp/mod/uploadm".time().make_password(10).".php";
$cp=@move_uploaded_file($file,$path);
if(!$cp)
{
printerror("EmptyLoadInMod","");
}
DoChmodFile($path);
@include($path);
UpdateTbDefMod($tid,$tbname,$mid);
//公共变量
TogSaveTxtF(1);
GetConfig(1);//更新缓存
//生成模型表单文件
$modr=$empire->fetch1("select mtemp,qmtemp,cj from {$dbtbpre}enewsmod where mid='$mid'");
ChangeMForm($mid,$tid,$modr[mtemp]);//更新表单
ChangeQmForm($mid,$tid,$modr[qmtemp]);//更新前台表单
ChangeMCj($mid,$tid,$modr[cj]);//采集表单
//删除文件
DelFiletext($path);
//操作日志
insert_dolog("tid=$tid&tb=$tbname<br>mid=$mid");
printerror("LoadInModSuccess","db/ListTable.php".hReturnEcmsHashStrHref2(1));
}
先获取tbname参数内容,就是我们输入的导入表名
然后判断是否为mod后缀
再判断是否存在
接下来就是处理上传文件
可以看到include包含了一次
然后就很简单了我们上传test.php.mod
file_put_contents("shell.php","<?php phpinfo(); ?>");