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 裁剪图片成固定大小代码方法
Sep 09 PHP
无法在发生错误时创建会话,请检查 PHP 或网站服务器日志,并正确配置 PHP 安装最快的解决办法
Aug 01 PHP
php笔记之:AOP的应用
Apr 24 PHP
php环境套包 dedeampz 伪静态设置示例
Mar 26 PHP
国产PHP开发框架myqee新手快速入门教程
Jul 14 PHP
PHP中new static() 和 new self() 的区别介绍
Jan 09 PHP
PHP中使用file_get_contents post数据代码例子
Feb 13 PHP
php获取字符串中各个字符出现次数的方法
Feb 23 PHP
判断、添加和删除WordPress置顶文章的相关PHP函数小结
Dec 10 PHP
PHP的mysqli_sqlstate()函数讲解
Jan 23 PHP
Yii框架自定义数据库操作组件示例
Nov 11 PHP
PHP实现微信提现功能(微信商城)
Nov 21 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变量
2006/10/09 PHP
php 连接mssql数据库 初学php笔记
2010/03/01 PHP
PHP针对中英文混合字符串长度判断及截取方法示例
2017/03/31 PHP
PHP判断是否是微信打开还是浏览器打开的方法
2019/02/27 PHP
JS版网站风格切换实例代码
2008/10/06 Javascript
关于JS字符串函数String.replace()
2013/04/07 Javascript
js+div实现图片滚动效果代码
2014/02/10 Javascript
浅析node.js中close事件
2014/11/26 Javascript
JavaScript中遍历对象的property的3种方法介绍
2014/12/30 Javascript
Bootstrap每天必学之附加导航(Affix)插件
2016/04/25 Javascript
animate 实现滑动切换效果【实例代码】
2016/05/05 Javascript
vue+element加入签名效果(移动端可用)
2019/06/17 Javascript
Vue路由之JWT身份认证的实现方法
2019/08/26 Javascript
使用vuex存储用户信息到localStorage的实例
2019/11/11 Javascript
Python入门篇之字符串
2014/10/17 Python
Python批量修改文本文件内容的方法
2016/04/29 Python
Python只用40行代码编写的计算器实例
2017/05/10 Python
Python探索之实现一个简单的HTTP服务器
2017/10/28 Python
python使用正则表达式替换匹配成功的组并输出替换的次数
2017/11/22 Python
Python GUI Tkinter简单实现个性签名设计
2018/06/19 Python
Python控制Firefox方法总结
2019/06/03 Python
Selenium 滚动页面至元素可见的方法
2020/03/18 Python
CSS3混合模式mix-blend-mode/background-blend-mode简介
2018/03/15 HTML / CSS
Canvas与Image互相转换示例代码
2013/08/09 HTML / CSS
data:image data url 文件转为Blob上传后端的方法
2019/07/16 HTML / CSS
请解释接口的显式实现有什么意义
2012/05/26 面试题
大学生新学期计划书
2014/04/28 职场文书
5.12护士节演讲稿
2014/04/30 职场文书
文秘专业应届生求职信
2014/05/26 职场文书
材料化学专业求职信
2014/07/15 职场文书
建设工程授权委托书
2014/09/22 职场文书
乡镇三严三实学习心得体会
2014/10/13 职场文书
2015年财务科工作总结范文
2015/05/13 职场文书
实习报告范文
2019/07/30 职场文书
合同范本之电脑出租
2019/08/13 职场文书
如何获取numpy array前N个最大值
2021/05/14 Python