利用Java实现WebShell特征码定位器
文/图 海啸天鸣(Ansty) [华南农业大学 李海鸣]
不知大家是否还记得我去年在黑防发表的一篇有关WebShell特征码定位方法的文章,在那篇文章里,WebShell的特征码我是采用手工定位的,手工定位不仅效率低下,而且消磨了我们的免杀积极性。因此,我们有必要利用工具来实现自动化操作。下面,我们就利用Java自己编写一个WebShell特征码定位器。如图1所示就是我们要实现的WebShell特征码定位器。
图1
因为WebShell一般都不会很大,所以我们可以一次删除WebShell一行代码并保存文件,这样,在抽取出了WebShell的每一行代码后,就会生成很多的WebShell文件,然后我们用杀软对生成的文件进行杀毒,剩下的文件就是我们抽取了WebShell特征码以后的WebShell了。最后统计一下杀毒剩下的文件,就可以得到特征码是存在哪一行或者哪些行代码里面了。
下面我们一起来看看程序的实现,至于GUI的设计,我就不介绍了,这个不是我们的重点。在正式开始之前,先来看看全局变量的声明。
private JButton jbSelect; //文件选择按钮
private JButton jbAna; //开始分析按钮
private JButton jbLocate; //定位按钮
private JTextArea jtaResult; //结果显示文本域
private JTextArea jtaHelp; //帮助文本域
private JTextField jtfFile; //文件路径框
private File shell; //webshell选择文件
private String path; //文件父目录
private String fileExt; //文件扩展名
private Vector<String> fileContent; //文件内容,向量
1) 得到用户选择的WebShell文件
private void chooseFile(){
int choice;
JFileChooser jfc = new JFileChooser();
//使用JDK提供的JFileChooser类获得一个文件选择对话框
jfc.setSize(400,400);
choice = jfc.showOpenDialog(this);
//JFileChooser这个类提供了“保存文件、打开文件”等模式,这里我们使用“打开文件”模式,showOpenDialog用于显示一个文件打开对话框
if(choice == JFileChooser.APPROVE_OPTION){
//选择确认(yes、ok)后返回该值。
shell = jfc.getSelectedFile();
//getSelectedFile这个方易做图返回一个File对象,也就是我们选择的文件了
jtfFile.setText(shell.getAbsolutePath());
//使用file对象的getAbsolutePath方法得到文件的路径
fileExt = shell.getName().substring(shell.getName().lastIndexOf("."));
//得到文件的扩展名,最后一个“.”号后面的就是文件的扩展名了。Substring这个方法的功能就是从指定位置开始截取字符串
jbAna.setEnabled(true);
}
}
2)读取WebShell文件内容(readFile())
选择好WebShell后,我们就要开始分析抽取了。为了提高读取效率,我们将WebShell全部读入到内存并保存到Vector<String>里面,方便进行查找。
BufferedReader br;
br = new BufferedReader(new InputStreamReader(new FileInputStream(shell)));
//使用带缓存的方法来读取文件
String temp; //存放每一行数据的临时变量
while ((temp = br.readLine()) != null) {
//当文件读到最后一行的时候返回的是null,以此来作为循环结束条件
fileContent.add(temp);
//按行将文件内容存入Vector<String> fileContent
}
在这里,如果程序正常执行完以后,WebShell的内容将会全部存到fileContent变量里。
3)批量保存抽取代码后的WebShell(writeFile())
在我们的writeFile()方法执行前,“path=shell.getParent()+"\"+"temp"+"\";”这句代码是要在WebShell的同一目录下新建一个temp文件夹来保存生成的临时文件。
PrintWriter pw; //使用printwriter输出到文件
try {
File dir = new File(this.path);
dir.mkdir(); //在WebShell目录下新建一个temp文件夹
for(int i=0;i<fileContent.size();i++){
//每个文件抽一行代码,循环整个文件
String path = this.path + (i+1) + fileExt;
//得到我们要保存的文件路径,每一个文件用所抽取代码的所在行数来命名,扩展名用原WebShell的扩展名
pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(path)),true);
//建立输出到文件的连接
for(int j=0;j<fileContent.size();j++){
if(j!=i) //因为当前文件是按行号来命名的,而文件名就恰好是我们要抽取的代码,当我们的行号等于当前文件号的时候,就跳过该行,不做输出,那么就实现抽取代码的功能了
pw.println(fileContent.get(j)); //按行输出到文件
}
pw.close(); //每个文件输出完成后一定要关闭文件输出流
}
4) 杀毒
这一步就没什么好说了,用杀毒软件将生成的文件进行杀毒,发现病毒就直接删除,剩下没被杀掉的就是已经抽取了特征码的WebShell了。这个时候的Webshell虽然是杀软抓不到了,但它不是完整的,因为我们已经将它的部分代码抽取掉了,而且我们也不知道那些代码的功能,所以还需要下面一步的定位。
5) 定位(locate())
定位的思路就是分析杀毒剩下的WebShell。刚才说过了,我们的文件命名是用抽取代码所在的行号实现的,那么剩下的那些文件的文件名,就是我们特征码的所在的行号了。
File result = new File(shell.getParent()+"\temp");
//得到temp的目录
boolean[] exist = new boolean[fileContent.size()];
//存储文件是否存在,boolean初始化的时候自动是false
String[] dirContent = result.list();
//得到当前目录下所有文件,list()方法返回String[]
int temp;
for(int i=0;i<dirContent.length;i++){
//循环检查目录下面的文件
temp = Integer.parseInt(dirContent[i].substring(0,dirContent[i].lastIndexOf(".")));
//dirContent[i].lastIndesOf(“.”)得到扩展名的在文件名中的位置;dirContent[i].substring()截取出文件名,抛弃文件扩展名。因为文件名使用行号来命名的,所以我们可以用Integer.parseInt()来强制将得到的文件名转换成int类型
exist[temp-1] = true;
//将的得到行号对应的boolean设为true,因为我们实际文件名和行号是相差1的,所以要用-1来得到实际行号
}
for(int i=0;i<exist.length;i++){
if(exist[i]){ //如果行号存在,就是我们刚才定位得到的行号
jtaResult.append(i+1+" "+fileContent.get(i)+"
");
//从fileContent变量里提取出对应行号的代码,显示在定位结果窗口
}
}
当然,也有可能杀软查杀不到的情况,此时我们只需判断生成的文件数是否与行数相同就行了,实现代码如下。
if(dirContent.length == fileContent.size()){
jtaResult.append("没有被杀软查杀记录,可能没有特征码!");
return;
}
OK,介绍到这里,我们的WebShell特征码定位器就新鲜出炉了,实际测试一下吧。
随便找一个WebShell——ServUsu.asp,这个东西大家很熟悉了,Serv-U的提权网马,现正在被广大杀软通缉。利用我们的工具拆分网马后,祭出卡巴来杀毒,如图2所示,杀毒完毕,我们来定位,如图3所示。
这样,我们就定位到了这个WebShell的特征码在第1、2两行代码里面了。至于特征码的免杀处理,就不在本文的介绍范围内了。大家如有什么疑问,欢迎到黑防官方论坛讨论,我的ID是:Ansty。
补充:软件开发 , Java ,