前言
技多不压身,多掌握几种不同的编程语言,不但有助于开拓我们的视野,还可以让我们在工作时,自己写一些小程序来帮我们减少工作量。前段时间给一个客户维护服务器,服务器总是被挂马,装了个某狗,然后并没有解决问题,到不是说安全狗不行,是现在很多防护软件并不贴心啊。
下面,我举个栗子
目前WAF用户体验性差
某狗、某网站防护、某主机卫士,只针对文件上传进行拦截和防护,先不说特征库全不全的问题,但是,如果攻击者利用远程下载的方式,直接下载到服务器,或者通过命令执行写进去,亦或者通过其他方式进行创建写入的,这些防护软件就没有办法管了。而杀软对webshell后门貌似也不是很敏感,所以,这就尴尬了。。摆在管理员面前的,只有手工查杀或者工具主动扫描两条路了。但是,你真的确定你天天会上去点查杀么?
好吧,我也遇到了这样的问题。一天登录服务器千百遍啊,就是为了点下查杀按钮。
前段时间给一个客户维护服务器,服务器总是被挂马,装了个某狗,然后并没有解决问题,到不是说安全狗不行,是现在很多防护软件并不贴心啊。。
解决思路
起初为了解决这个问题,用C#写了个命令行程序,对网站目录进行循环检测
但是240G的源代码,跑完一次需要1个多小时,也就是说,在这个时间范围内,网马可以存活一定时间,对于一个黑客来说,一个多小时,能做很多事情,所以,这不是我想要的。
之前一直在琢磨,有没有一个好的方式,能够代替人工去监控网站目录文件,一旦出现webshell,就自动进行隔离呢。
之前写了个小工具,但是界面有点小气。。
从乌云群里要了个shack2写的,一个“超级文件监控”工具,貌似是前两年的,我就顺手改了改,实现了下这个功能,下面详细说下正题。
要想实现这个功能,首先得解决两个问题。
1、针对文件的创建、更改、重命名进行监控;
2、对触发创建、更改、重命名的文件内容进行判断;
先说说第一个
我是用C#来写的
程序开始,肯定得先指定文件监控路径
private void btn_selectDir_Click(object sender, EventArgs e)
{
FolderBrowserDialog dialog = new FolderBrowserDialog();
dialog.Description = "请选择监控文件路径";
if (dialog.ShowDialog() == DialogResult.OK)
{
String foldPath = dialog.SelectedPath;
this.txt_dir.Text = foldPath;
}
C#对文件进行监控,得用到FileSystemWatcher类
FileSystemWatcher类提供了Created, Deleted,Rename等事件的监控
例如shack2写的文件监控源码,我以创建文件为例:
private void fileCreate_EventHandle(Object sender, FileSystemEventArgs e) //文件增删改时被调用的处理方法 {
add++;
this.lvw_log.Invoke(new updateResult(addNode), new Object[] { e, "创建" })
}
当触发了创建文件操作时,将内容输出。
当然了,除了创建以外,还可以用WatcherChangeTypes来注册其他事件。
因为shack2已经共享了源码,这里就不再累述。
文件监控这里,百度有很多现成的方法,这个完全可以复制粘贴的,重点是第二个问题,如何对触发行为的内容进行处理。
大致处理思路是:
触发文件状态(如:创建)---->对触发该状态的文件进行检查------->确定文件内容是否存在可疑------->不处理or隔离
知道了思路,写起来就相对简单些了。
先创建个ScanHelper类
这个类,主要是写扫描方法和所关联的特征码,也就是表达式。以及文件的处理措施。
这里的表达式,可以根据需求来自己设定,也可以将特定脚本类型的特征码进行归类。
c
onst string sPattern = "webshell特征表达式";
const string sString = "HTML、JS代码特征表达式2";
const string sjm = "加密一句话或加密webshell特征表达式3";
static Regex RegPattern = new Regex(sPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
static Regex RegString = new Regex(sString, RegexOptions.Compiled | RegexOptions.IgnoreCase);
static Regex Regsjm = new Regex(sjm, RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>
/// 日志文件路径
/// </summary>
public static string LogPath { get; set; }
/// <summary>
/// 临时文件目录
/// </summary>
public static string TempPath { get; set; }
/// <summary>
/// 扫描文件
/// </summary>
/// <param name="filePath"></param>
表达式写清楚了,然后就是写文件打开的方法和文件内容的判断
这里使用 FileInfo NextFile = new FileInfo(filePath);
判断文件是否存在 if (NextFile.Exists)
string FileText = File.ReadAllText(Path.GetFullPath(filePath));//读取文件内容
if (RegString.IsMatch(FileText) || RegPattern.IsMatch(FileText) || Regsjm.IsMatch(FileText)) //如果存在危险字符
如果存在设定好的字符,则处理文件
这里呢,当然不能直接删除,通过moveTo的方式移动到别的地方来处理
NextFile.MoveTo(Path.Combine(TempPath, NextFile.Name));
只是判断文件还不行,如果文件出现重复,依然会出现问题,这里,需要对文件进行一个处理
比如说,当发现1.asp文件存在问题,我们处理以后,下次再出现1.asp文件时,则会报错。。。
这里,我们需要用到下面的方法来处理下文件重复的问题。
//如果自身文件在运行,不能直接覆盖,需要重命名之后再移动
if (File.Exists(Path.Combine(TempPath, NextFile.Name)))
{
if (File.Exists(Path.Combine(TempPath, NextFile.Name + ".bak")))
{
File.Delete(Path.Combine(TempPath, NextFile.Name + ".bak"));
}
File.Move(Path.Combine(TempPath, NextFile.Name), Path.Combine(TempPath, NextFile.Name + ".bak"));
}
NextFile.MoveTo(Path.Combine(TempPath, NextFile.Name));
上面代码的意思是,当发现文件重复了,在新处理的文件名加上.bak来做区分,当再次发现.bak也重复的时候,直接进行删除操作。
在处理完这些问题后,有一个核心的问题,线程占用的情况。。
也就是说,在windows文件系统中,你创建一个文件时,会触发created和changed两种操作,你修改文件内容时,也同样会触发这两个操作,这样就会冲突了。这不是关键,关键问题时,在执行监控时,你还要对文件内容进行判断和处理,这样就很容易发生错误。
我问过好多C#大牛,都说不好解决,最好的办法,是用C++来写,通过底层的方式来处理,但是坑的是,我还没学C++,C#也是才学了2个月吧,如果这样就放弃了,那整个程序就白写了。。
后来琢磨了好几天,想到了一个不是解决办法的解决办法。
用try catch和Thread.Sleep来解决这个问题。
示例代码:
private void fileCreate_EventHandle(Object sender, FileSystemEventArgs e) //文件增删改时被调用的处理方法
{
add++;
this.lvw_log.Invoke(new updateResult(addNode), new Object[] { e, "创建" });
Thread.Sleep(20000);
try
{
if (File.Exists(e.FullPath)) //是文件
{
string type = e.ChangeType == WatcherChangeTypes.Created ? "重命名" : "改名";
lock (this)
{
ScanHelper.ScanFile(e.FullPath);
}
}
}
catch
{
Thread.Sleep(20000);
if (File.Exists(e.FullPath)) //是文件
{
//string type = e.ChangeType == WatcherChangeTypes.Created ? "重命名" : "改名";
lock (this)
{
ScanHelper.ScanFile(e.FullPath);
}
}
}
}
try执行,当文件触发了创建操作,就执行文件内容判断和处理的方法
如果线程出错,则通过catch的方式来重复执行,但是catch不再判断文件状态,只是判断是文件,然后对内容进行检查,发现问题,则进行下一步处理操作。
这里用到了 Thread.Sleep(20000);睡眠时间,是为了让程序在判断的时候,有足够的时间释放线程,免得出现冲突,而导致程序崩溃。
当然了,界面我没改动,还是shack2得界面,我只是在界面上加入了一个隔离区操作。
我把软件贴出来,大家可以玩玩。
使用方法:监控目录输入你要监控的网站目录,点击“开始监控”。
隔离区默认设置在C:TEMP目录下,凡是被隔离的文件,均在该目录下。
当创建文件、修改文件或者重命名文件时,内容中如果含有webshell的关键词或函数,则会进行处理。
补充说明:
监控后缀和跳过后缀完全可以忽略,因为这个监控,是针对所有文件内容的,所以无所谓监控哪个或不监控哪个,管它是畸形文件名还是war,都会去进行检测。
第一次执行时,执行可能会有些缓慢,当执行完一次后,会建立索引,后面速度则会有提升。。
软件中已写好了近百种特征,共170个webshell样本,虽然不一定全,但是至少还是有些查杀能力的。
一般同文件名,首次上传到被处理,存活周期在10-20秒之间。
当文件监控到“修改”操作时,其实就已经执行了处理操作,只是我把显示的时间延迟了20秒。
不管什么软件,误杀的情况是不可避免的,假如在使用该软件的时候,软件匹配到特征,就会将文件隔离到c:temp目录下,并不会直接删除
当你发现文件是误删除的,可以点击“停止监控”,将文件根据软件下方显示的位置,还原到原来的目录,再点击监控就可以了,这样,这个文件就不会查杀了,除非这个文件的名字、内容有了变动,则会继续触发规则。
因为这段时间要做移动APP安全审计的工作,C#暂时先放放,准备开始学移动APP这块,功能暂时不做改动了。
后面找时间修改,计划是把功能修改的更为简洁,把监控的记录完善下,增加白名单区域等小功能。
有什么问题,欢迎邮件或站内信反馈。
欢迎测试。
链接失效了
2016-11-04 下午4:32