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 相关文章推荐
PHP 和 COM
Oct 09 PHP
php 接口类与抽象类的实际作用
Nov 26 PHP
php 多线程上下文中安全写文件实现代码
Dec 28 PHP
PHP之APC缓存详细介绍 apc模块安装
Jan 13 PHP
Zend Framework页面缓存实例
Jun 25 PHP
phpmyadmin出现Cannot start session without errors问题解决方法
Aug 14 PHP
php动态生成缩略图并输出显示的方法
Apr 20 PHP
laravel学习教程之存取器
Jul 30 PHP
php mysql PDO 查询操作的实例详解
Sep 23 PHP
PHP删除数组中指定下标的元素方法
Feb 03 PHP
PHP+Ajax实现上传文件进度条动态显示进度功能
Jun 04 PHP
laravel5.2表单验证,并显示错误信息的实例
Sep 29 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性能优化 产生高度优化代码
2011/07/22 PHP
php+ajax实现文章自动保存的方法
2014/12/30 PHP
CI框架封装的常用图像处理方法(缩略图,水印,旋转,上传等)
2016/11/22 PHP
php+Memcached实现简单留言板功能示例
2017/02/15 PHP
Laravel实现短信注册的示例代码
2018/05/29 PHP
围观tangram js库
2010/12/28 Javascript
jQuery之选项卡的简单实现
2014/02/28 Javascript
js操作IE浏览器弹出浏览文件夹可以返回目录路径
2014/07/14 Javascript
js实现编辑div节点名称的方法
2014/12/17 Javascript
js判断移动端是否安装某款app的多种方法
2015/12/18 Javascript
Javascript如何判断数据类型和数组类型
2016/06/22 Javascript
微信小程序 location API实例详解
2016/10/02 Javascript
jQuery下拉菜单的实现代码
2016/11/03 Javascript
基于JS实现网页中的选项卡(两种方法)
2017/06/16 Javascript
详解从0开始搭建微信小程序(前后端)的全过程
2019/04/15 Javascript
简单了解微信小程序的目录结构
2019/07/01 Javascript
微信小程序中target和currentTarget的区别小结
2020/11/06 Javascript
python更新列表的方法
2015/07/28 Python
利用Python实现图书超期提醒
2016/08/02 Python
python中闭包Closure函数作为返回值的方法示例
2017/12/17 Python
浅谈Python用QQ邮箱发送邮件时授权码的问题
2018/01/29 Python
Python 实现异步调用函数的示例讲解
2018/10/14 Python
对Xpath 获取子标签下所有文本的方法详解
2019/01/02 Python
python代理工具mitmproxy使用指南
2019/07/04 Python
Python3 列表,数组,矩阵的相互转换的方法示例
2019/08/05 Python
python标准库sys和OS的函数使用方法与实例详解
2020/02/12 Python
Python要如何实现列表排序的几种方法
2020/02/21 Python
基于pytorch中的Sequential用法说明
2020/06/24 Python
如何快速一次性卸载所有python包(第三方库)呢
2020/10/20 Python
html5唤起app的方法
2017/11/30 HTML / CSS
网络教育自我鉴定
2013/11/01 职场文书
会计职业生涯规划范文
2014/01/04 职场文书
乡镇纠风工作实施方案
2014/03/22 职场文书
学校交通安全责任书
2014/08/25 职场文书
个人合伙协议书范本
2014/10/14 职场文书
告别网页搜索!教你用python实现一款属于自己的翻译词典软件
2021/06/03 Python