php实现Linux服务器木马排查及加固功能


Posted in PHP onDecember 29, 2014

网站频繁被挂马?做一些改进,基本上能把这个问题解决,因为discuz x等程序存在漏洞,被上传了websehll,每次被删除过段时间又出来了,最终查到所有的木马。

从以下几个方面查找并加强(如果能不开启会员功能,不给任何上传入口,保护好后台密码,加固好PHP,一般就没什么问题了)。

1.根据特征码查找:

php木马一般含有

<?php eval($_POST[cmd]);?>

或者
<?php assert($_POST[cmd]);?>
find /wwwroot/* -type f -name "*.php" |xargs grep "eval(" > /wwwroot/scan.txt

结果就查出很多明显的webshell,并且发现都藏在attachment等目录下

2.利用网上的一个php代码,搜索最近被修改的文件

scandir.php
内容如下:

<?php 

set_time_limit(0);//防止超时 

/** 

* 

* php目录扫描监控增强版 

* 

* @author lssbing (lssbing#gmail.com) 

* @date 2010-1-18 

* @license BSD 

* @version 1.0 

* 

下面几个变量使用前需要手动设置 

* 

**/ 

/*===================== 程序配置 =====================*/ 

$pass="12345";//设置密码 

$jkdir="."; //设置监控扫描的目录,当前目录为'.',上一级目录为'..',也可以设置绝对路径,后面不要加斜杠,默认为当前目录 

$logfilename="./m.log";//设置存储log的路径,可以放置在任意位置 

$exclude=array('data','images');//排除目录 

$danger='eval|cmd|passthru|gzuncompress';//设置要查找的危险的函数 以确定是否木马文件 

$suffix='php|inc';//设置要扫描文件的后缀 

/*===================== 配置结束 =====================*/ 

 

$filename=$_GET['filename']; 

$check=$_GET['check']; 

$jumpoff=false; 

$url = $_SERVER['PHP_SELF']; 

$thisfile = end(explode('/',$url)); 

$jump="{$thisfile}|".implode('|',$exclude); 

$jkdir_num=$file_num=$danger_num=0; 

define('M_PATH',$jkdir); 

define('M_LOG',$logfilename); 

if ($check=='check') 

{ 

$safearr = explode("|",$jump); 

$start_time=microtime(true); 

safe_check($jkdir); 

$end_time=microtime(true); 

$total=$end_time-$start_time; 

$file_num=$file_num-$jkdir_num; 

$message= " 文件数:".$file_num; 

$message.= " 文件夹数:".$jkdir_num; 

$message.= " 可疑文件数:".$danger_num; 

$message.= " 执行时间:".$total; 

echo $message; 

}else{ 

if ($_GET['m']=="del") Delete();//处理文件删除 

//读取文件内容 

if(isset($_GET['readfile'])){ 

//输出查看密码,密码校验正确以后输出文件内容 

if(emptyempty($_POST['passchack'])){ 

   echo"<form id=\"form1\" name=\"form1\" method=\"post\">" 

    . " <label>pass" 

    . " <input type=\"text\" name=\"passchack\" />" 

    . " </label>" 

    . " <input type=\"submit\" name=\"Submit\" value=\"提交\" />" 

    . "</form>" 

   .""; 

   exit; 

}elseif(isset($_POST['passchack'])&&$_POST['passchack']==$pass){ 

   $code=file_get_contents($_GET['readfile']); 

   echo"<textarea name=\"code\" cols=\"150\" rows=\"30\" id=\"code\" style='width:100%;height:450px;background:#cccccc;'>{$code}</textarea>"; 

   exit; 

}else{ 

   exit; 

} 

 

}else{ 

record_md5(M_PATH); 

if(file_exists(M_LOG)){ 

        $log = unserialize(file_get_contents(M_LOG)); 

}else{ 

        $log = array(); 

} 

 

if($_GET['savethis']==1){ 

//保存当前文件md5到日志文件 

@unlink(M_LOG); 

file_put_contents(M_LOG,serialize($file_list)); 

echo "<a href='scandir.php'>保存成功!点击返回</a>"; 

exit; 

} 

if(emptyempty($log)){ 

echo "当前还没有创建日志文件!点击[保存当前]创建日志文件!"; 

}else{ 

if($file_list==$log){ 

   echo "本文件夹没有做过任何改动!"; 

}else{ 

   if(count($file_list) > 0 ){ 

    foreach($file_list as $file => $md5){ 

    if(!isset($log[$file])){ 

     echo "新增文件:<a href={$file} target='_blank'>".$file."</a>"." 创建时间:".date("Y-m-d H:i:s",filectime($file))." 修改时间:".date("Y-m-d H:i:s",filemtime($file))." <a href=?readfile={$file} target='_blank'>源码</a><a href='?m=del&filename={$file}' target='_blank'>删除</u></a><br />"; 

    }else{ 

     if($log[$file] != $md5){ 

     echo "修改文件:<a href={$file} target='_blank'>".$file."</a>"." 创建时间:".date("Y-m-d H:i:s",filectime($file))." 修改时间:".date("Y-m-d H:i:s",filemtime($file))." <a href=?readfile={$file} target='_blank'>源码</a><br />"; 

 

     unset($log[$file]); 

     }else{ 

     unset($log[$file]); 

     } 

    } 

    } 

   } 

   if(count($log)>0){ 

    foreach($log as $file => $md5){ 

    echo "删除文件:<a href={$file} target='_blank'>".$file."</a><br />"; 

    } 

   } 

    } 

} 

} 

} 

 

//计算md5 

function record_md5($jkdir){ 

        global $file_list,$exclude; 

        if(is_dir($jkdir)){ 

                $file=scandir($jkdir); 

                foreach($file as $f){ 

                        if($f!='.' && $f!='..' && !in_array($f, $exclude)){ 

                                $path = $jkdir.'/'.$f; 

                                if(is_dir($path)){ 

                                        record_md5($path); 

                                }else{ 

                                        $file_list[$path]=md5_file($path); 

                                } 

                        } 

                } 

        } 

} 

 

function Safe_Check($jkdir)//遍历文件 

{ 

global $danger ,$suffix ,$jkdir_num ,$file_num ,$danger_num; 

 

$hand=@dir($jkdir) or die('文件夹不存在') ; 

while ($file=$hand->read()) 

{ 

    $filename=$jkdir.'/'.$file; 

    if (!$jumpoff) { 

   if(Jump($filename))continue; 

    } 

    if(@is_dir($filename) && $file != '.' && $file!= '..'&& $file!='./..') 

    {   $jkdir_num++; 

    Safe_Check($filename); 

    } 

    if (preg_match_all ("/\.($suffix)/i",$filename,$out)) 

    { 

 

   $str=''; 

   $fp = @fopen($filename,'r')or die('没有权限'); 

   while(!feof($fp)) 

   { 

   $str .= fgets($fp,1024); 

   } 

   fclose($fp); 

   if( preg_match_all ("/($danger)[ \r\n\t]{0,}([\[\(])/i",$str,$out)) 

   { 

   echo "<font color='green' style='font-size:14px'>可疑文件:{$filename}</font>"." 创建时间:".date("Y-m-d H:i:s",filectime($filename))." 修改时间:".date("Y-m-d H:i:s",filemtime($filename))." <a href='?readfile={$filename}' target='_blank'><u>查看代码</u></a> <a href='?m=del&filename=$filename' target='_blank'>删除</u></a><br>"; 

   $danger_num++; 

   } 

    } 

    $file_num++; 

} 

} 

function Edit()//查看可疑文件 

{ 

global $filename; 

$filename = str_replace("..","",$filename); 

$file = $filename; 

$content = ""; 

if(is_file($file)) 

{ 

    $fp = fopen($file,"r")or die('没有权限'); 

    $content = fread($fp,filesize($file)); 

    fclose($fp); 

    $content = htmlspecialchars($content); 

 

} 

echo "<textarea name='str' style='width:100%;height:450px;background:#cccccc;'>$content</textarea>\r\n"; 

exit(); 

} 

function Delete()//删除文件 

{ global $filename,$pass; 

if(emptyempty($_POST['passchack'])){ 

    echo"<form id=\"form1\" name=\"form1\" method=\"post\">" 

   . " <label>pass" 

   . " <input type=\"text\" name=\"passchack\" />" 

   . " </label>" 

   . " <input type=\"submit\" name=\"Submit\" value=\"提交\" />" 

   . "</form>" 

    .""; 

    exit; 

}elseif(isset($_POST['passchack'])&&$_POST['passchack']==$pass){ 

   (is_file($filename))?($mes=unlink($filename)?'删除成功':'删除失败 查看权限'):''; 

   echo $mes; 

   exit(); 

}else{ 

   echo '密码错误!'; 

   exit; 

} 

} 

function Jump($file)//跳过文件 

{ 

global $jump,$safearr; 

if($jump != '') 

{ 

    foreach($safearr as $v) 

    { 

   if($v=='') continue; 

   if( eregi($v,$file) ) return true ; 

    } 

} 

return false; 

} 

?> 

<a href="scandir.php">[查看文件改动]</a>|<a href="scandir.php?savethis=1">[保存当前文件指纹]</a>|<a href="scandir.php?check=check">[扫描可疑文件]</a>

执行后能看到最近被修改的文件,具有参加价值

3.修改php.ini,限制以下函数

disable_functions =  phpinfo,passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocke,popen,proc_close,curl_exec,curl_multi_exec,parse_ini_file,show_source,dl,escapeshellarg,escapeshellcmd

4.修改nginx.conf ,限制一些目录执行php文件

server 

{ 

    listen       80; 

    server_name  www.***.com; 

    index   index.htm index.html index.php; 

    root  /wwwroot/; 

     

 

       

    rewrite ^([^\.]*)/topic-(.+)\.html$ $1/portal.php?mod=topic&topic=$2 last; 

    rewrite ^([^\.]*)/article-([0-9]+)-([0-9]+)\.html$ $1/portal.php?mod=view&aid=$2&page=$3 last; 

    rewrite ^([^\.]*)/forum-(\w+)-([0-9]+)\.html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last; 

    rewrite ^([^\.]*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last; 

    rewrite ^([^\.]*)/group-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=group&fid=$2&page=$3 last; 

    rewrite ^([^\.]*)/space-(username|uid)-(.+)\.html$ $1/home.php?mod=space&$2=$3 last; 

    rewrite ^([^\.]*)/([a-z]+)-(.+)\.html$ $1/$2.php?rewrite=$3 last; 

    rewrite ^([^\.]*)/topic-(.+)\.html$ $1/portal.php?mod=topic&topic=$2 last; 

         

 

        location ~ ^/images/.*\.(php|php5)$ 

                { 

              deny all; 

                } 

 

        location ~ ^/static/.*\.(php|php5)$ 

                { 

               deny all; 

                } 

 

        location ~* ^/data/(attachment|avatar)/.*\.(php|php5)$ 

            { 

                deny all; 

            } 

 

    location ~ .*\.(php|php5)?$ 

    {       

      fastcgi_pass  127.0.0.1:9000; 

      fastcgi_index index.php; 

      include fcgi.conf; 

    } 

     

         

 

error_page  400 /404.html; 

error_page  403 /404.html; 

error_page  404 /404.html; 

error_page  405 /404.html; 

error_page  408 /404.html; 

error_page  410 /404.html; 

error_page  411 /404.html; 

error_page  412 /404.html; 

error_page  413 /404.html; 

error_page  414 /404.html; 

error_page  415 /404.html; 

error_page  500 /404.html; 

error_page  501 /404.html; 

error_page  502 /404.html; 

error_page  503 /404.html; 

error_page  506 /404.html; 

 

 

log_format  acclog    "$remote_addr $request_time $http_x_readtime [$time_local] \"$request_method http://$host$request_uri\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""; 

        access_log  /logs/access.log  acclog; 

}

此处需要注意的是

location ~ ^/images/.*\.(php|php5)$ 

{ 

  deny all; 

}

这些目录的限制必须写在

location ~ .*\.(php|php5)?$ 

{       

  fastcgi_pass  127.0.0.1:9000; 

  fastcgi_index index.php; 

  include fcgi.conf; 

}

的前面,否则限制不生效。

PHP 相关文章推荐
别人整理的服务器变量:$_SERVER
Oct 20 PHP
php MySQL与分页效率
Jun 04 PHP
PHP中strtotime函数使用方法详解
Nov 27 PHP
如何使用php输出时间格式
Aug 31 PHP
PHP读取大文件的类SplFileObject使用介绍
Apr 09 PHP
ThinkPHP 404页面的设置方法
Jan 14 PHP
PHP session文件独占锁引起阻塞问题解决方法
May 12 PHP
PHP安装threads多线程扩展基础教程
Nov 17 PHP
php将文件夹打包成zip文件的简单实现方法
Oct 04 PHP
PHP利用二叉堆实现TopK-算法的方法详解
Apr 24 PHP
PHP PDO操作MySQL基础教程
Jun 05 PHP
php+mysql开发的最简单在线题库(在线做题系统)完整案例
Mar 30 PHP
php连接oracle数据库及查询数据的方法
Dec 29 #PHP
php查询mssql出现乱码的解决方法
Dec 29 #PHP
php+mysql大量用户登录解决方案分析
Dec 29 #PHP
php从memcache读取数据再批量写入mysql的方法
Dec 29 #PHP
php操作mongoDB实例分析
Dec 29 #PHP
Yii实现多数据库主从读写分离的方法
Dec 29 #PHP
php调用mysql存储过程实例分析
Dec 29 #PHP
You might like
使用php4加速网络传输
2006/10/09 PHP
php中出现空白页的原因及解决方法汇总
2014/07/08 PHP
php支付宝手机网页支付类实例
2015/03/04 PHP
PHP7内核之Reference详解
2019/03/14 PHP
Thinkphp 框架基础之入口文件功能、定义与用法分析
2020/04/27 PHP
javascript最常用与实用的创建类的代码
2010/08/12 Javascript
Firefox中beforeunload事件的实现缺陷浅析
2012/05/03 Javascript
判断文件是否正在被使用的JS代码
2013/12/21 Javascript
SuperSlide2实现图片滚动特效
2014/06/20 Javascript
JS实现的数组全排列输出算法
2015/03/19 Javascript
js完美解决IE6不支持position:fixed的bug
2015/04/24 Javascript
基于JavaScript实现生成名片、链接等二维码
2015/09/20 Javascript
js随机生成26个大小写字母
2016/02/12 Javascript
JavaScript从数组的indexOf()深入之Object的Property机制
2016/05/11 Javascript
解析NodeJs的调试方法
2016/12/11 NodeJs
详解如何使用webpack打包Vue工程
2017/05/27 Javascript
JavaScript实现各种排序的代码详解
2017/08/28 Javascript
JavaScript设计模式之调停者模式实例详解
2018/02/03 Javascript
Vue.js实现表格渲染的方法
2018/09/07 Javascript
小程序点击图片实现自动播放视频
2020/05/29 Javascript
js调用网络摄像头的方法
2020/12/05 Javascript
python读写ini文件示例(python读写文件)
2014/03/25 Python
Python遍历文件夹 处理json文件的方法
2019/01/22 Python
kali中python版本的切换方法
2019/07/11 Python
基于SQLAlchemy实现操作MySQL并执行原生sql语句
2020/06/10 Python
最新pycharm安装教程
2020/11/18 Python
Pretty Little Thing美国:时尚女性服饰
2018/08/27 全球购物
英国最大的纸工艺品商店:CraftStash
2018/12/01 全球购物
区域销售经理岗位职责
2013/12/10 职场文书
银行职员思想汇报
2013/12/31 职场文书
带薪年假请假条
2014/02/04 职场文书
风险评估实施方案
2014/03/09 职场文书
经典毕业生求职信
2014/07/12 职场文书
县委常委班子专题民主生活会查摆问题及整改措施
2014/09/27 职场文书
教师节班会开场白
2015/06/01 职场文书
2019年公司卫生管理制度样本
2019/08/21 职场文书