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 相关文章推荐
用函数读出数据表内容放入二维数组
Oct 09 PHP
php实现简单洗牌算法
Jun 18 PHP
PHP 读取和编写 XML
Nov 19 PHP
jQuery Mobile + PHP实现文件上传
Dec 12 PHP
php绘制一条弧线的方法
Jan 24 PHP
php include类文件超时问题处理
Feb 06 PHP
WordPress导航菜单的滚动和淡入淡出效果的实现要点
Dec 14 PHP
PHP简单判断字符串是否包含另一个字符串的方法
Mar 25 PHP
php实现的mysqldb读写分离操作类示例
Feb 07 PHP
针对thinkPHP5框架存储过程bug重写的存储过程扩展类完整实例
Jun 16 PHP
Yii框架布局文件的动态切换操作示例
Nov 11 PHP
laravel与thinkphp之间的区别与优缺点
Mar 02 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
php文件怎么打开 如何执行php文件
2011/12/21 PHP
php自定义session示例分享
2014/04/22 PHP
PHP中的print_r 与 var_dump 输出数组
2016/06/13 PHP
THinkPHP获取客户端IP与IP地址查询的方法
2016/11/14 PHP
CodeIgniter框架实现的整合Smarty引擎DEMO示例
2019/03/28 PHP
php web环境和命令行环境下查找php.ini的位置
2019/07/17 PHP
通过event对象的fromElement属性解决热区设置主实体的一个bug
2008/12/22 Javascript
JavaScript弹簧振子超简洁版 完全符合能量守恒,胡克定理
2009/10/25 Javascript
跟我学习javascript的prototype,getPrototypeOf和__proto__
2015/11/17 Javascript
如何判断Javascript对象是否存在的简单实例
2016/05/18 Javascript
jQuery插件easyUI实现通过JS显示Dialog的方法
2016/09/16 Javascript
JS控制HTML元素的显示和隐藏的两种方法
2016/09/27 Javascript
vue2.0 中#$emit,$on的使用详解
2017/06/07 Javascript
AngularJS  ng-repeat遍历输出的用法
2017/06/19 Javascript
理解 javascript 中的函数表达式与函数声明
2017/07/07 Javascript
详解使用PM2管理nodejs进程
2017/10/24 NodeJs
vue-scroller记录滚动位置的示例代码
2018/01/17 Javascript
详解关于vue-area-linkage走过的坑
2018/06/27 Javascript
Vue 路由 过渡动效 数据获取方法
2018/07/31 Javascript
原生JS实现获取及修改CSS样式的方法
2018/09/04 Javascript
python使用7z解压软件备份文件脚本分享
2014/02/21 Python
python常规方法实现数组的全排列
2015/03/17 Python
Python基于pygame实现的弹力球效果(附源码)
2015/11/11 Python
离线安装Pyecharts的步骤以及依赖包流程
2020/04/23 Python
获取python的list中含有重复值的index方法
2018/06/27 Python
python调用c++传递数组的实例
2019/02/13 Python
Django 中自定义 Admin 样式与功能的实现方法
2019/07/04 Python
Python上下文管理器全实例详解
2019/11/12 Python
基于torch.where和布尔索引的速度比较
2020/01/02 Python
美国的Eastbay旗下的运动款子品牌:Final-Score
2018/01/01 全球购物
网络通讯中,端口有什么含义,端口的取值范围
2012/11/23 面试题
大专会计自我鉴定
2014/02/06 职场文书
预备党员期盼十八届四中全会召开思想汇报
2014/10/17 职场文书
不同意离婚上诉状
2015/05/23 职场文书
2016班级元旦联欢会开幕词
2016/03/04 职场文书
使用golang编写一个并发工作队列
2021/05/08 Golang