基于机器学习的jsp/jspx webshell检测

2019-08-16 约 122 字 预计阅读 1 分钟

声明:本文 【基于机器学习的jsp/jspx webshell检测】 由作者 ADog 于 2019-08-16 09:45:00 首发 先知社区 曾经 浏览数 37 次

感谢 ADog 的辛苦付出!

前言

在上文《基于AST的Webshell检测》中,笔者已经提出了基于抽象语法树是可以用来检测Webshell的,那么如何将这种思想应用在jsp/jspx的webshell检测便是本文讨论的重点。
简单回顾下抽象语法树的检测原来,由于webshell和正常文件在语法结构上会有比较明显的出入,比如说一句话木马普遍流程就是传参然后执行命令,转化为语法结构上其实是比较单一的,正常文件的语法结构会比这复杂的多得多,因此从语法结构上来分辨是否为webshell也是一种不错的选择。但是语法结构的缺点就是难以对具体参数进行分析,所以当出现“eval('1111');”和“eval(file_put_contents('shell.php','<?php phpinfo()'));”这种需要去区分具体数据的时候使用ast来做检测就会显得非常困难。
那么应用到java环境下,黑客的正常攻击流程就是通过web漏洞传入webshell,然后通过小马传大马的方式进行后渗透攻击,一般java环境下想要rce要么任意文件上传,要么反序列化执行命令(还有其他方法,这里只列举主流方法),所以通过任意文件上传就一定会留下文件痕迹,一般来说java的可执行文件为jsp或者jspx,一般情况下jspx是一种绕过jsp文件上传的方式,这里作一并处理。

回顾前面的检测原理,jsp文件的语法结构特征其实相较于php来说,是更为明显的。原因在于一般情况下jsp文件是作页面展示用的,而具有webshell特征的jsp文件是通过传参的方式来执行命令,在语法结构上其实是有本质的区别,所以这里起码检测原理是说的过去的,并且切实可行的。

数据处理

机器学习我们知道最重要的一步其实就是特征工程的构建上,那么这里jsp文件其实是没有专用的工具来解析其抽象语法树的,并且jsp文件跟php文件的最大区别就是php文件时可以直接执行的,而jsp文件其实是需要通过中间件进行编译后才能执行,那么这个问题其实就转化为了:在Tomcat等中间件服务器下,jsp文件经过了哪些处理流程?

这里jsp文件首先经过jsp parse会被编译为java文件,然后通过servlet分析器将java文件编译为class文件,最后将其转化为对应的Java字节码加载执行,这中间其实有一步比较关键,那就是编译为java文件这一步。

文件编译

那么作为检测程序来说,肯定不能说让tomcat调用这程序一遍,然后直接抓编译好的java文件,那么这里就必须要先运行tomcat服务器,使其自动加载WEB目录下的程序,这对于我们自动化检测来说肯定是不可取的,如果现在想要批量检测,就必须要有自己的编译工具,所幸这里找到了tomcat中编译jsp程序的类(org.apache.jasper.servlet.JspServlet),这里其实是一个比较大的坑,这里将编译命令直接放出来。

java -cp "apache-tomcat-8.5.35/lib/*:apache-tomcat-8.5.35/bin/*" org.apache.jasper.JspC -webapp  webroot -d webroot_java 
#直接运行可能会有点问题需要在lib目录下加入ant.jar包
#-webapp  指定文件目录
#-d : 指定编译后的文件目录

通过运行上述命令,我们其实就已经可以将某一个存放webshell文件的目录给转化为java文件,其中发现对于jspx文件的编译也是使用了同样的模块,所以这里也能够检测jspx的webshell。

抽象语法树的构建

针对jsp的抽象语法树构建笔者并没有找到相关工具,但是针对java的ast构建工具起码还有选择,这里使用的是javaparser这个工具来生成相应的抽象语法树

使用javaparser也比较简单,通过maven架构直接加载对应的pom信息即可

<dependencies>
    <dependency>
        <groupId>com.github.javaparser</groupId>
        <artifactId>javaparser-core</artifactId>
        <version>3.14.8</version>
    </dependency>
</dependencies>

这里在参照了网上的大部分教程后,决定使用文件流的方式来静态编译。

public static void main(String[] args) throws Exception {
    String filename = args[0];
    //File file = new File("src/classes/org/apache/jsp/s03_jsp.java");
    File file = new File(filename);
    FileInputStream in = new FileInputStream(file);

    CompilationUnit cu = StaticJavaParser.parse(in);
    cu.accept(new MethodVistor(),null);
}


这里的MethodVistor类其实就是语法结构类型的检测方法,比如说函数调用可能就叫MethodCall,如果是注释就叫Comment,所以说经过这个类我们就能够生成全局的语法结构节点序列。这中间并不是取了所有的语法结构特征,并且针对部分语法结构特征做了深一步处理,如函数调用可能需要进一步获取函数名等。

机器学习

得到这个序列后,需要使用相关模型来将其转化为矩阵,以便后面的训练和学习,针对这种序列流模型,我采用的是tfidf模型,主要思想就是如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。这个模型其实是由词频和逆向文件频率组成的,最后表示其实就是两个参数的乘积,这个不多说,,没什么意义。。

CV = CountVectorizer(ngram_range=(1,3), decode_error="ignore",max_features=max_features,
                                       token_pattern = r'\b\w+\b',min_df=0,max_df=0.9)
    x=CV.fit_transform(x_all).toarray()
    transformer = TfidfTransformer(smooth_idf=False)
    x_tfidf = transformer.fit_transform(x)
    x = x_tfidf.toarray()

那么通过这个模型,我们就能将每个文件的ast语法结构序列给转化为一个统一的矩阵,并分别给黑白样本打上标记,进行有监督式的训练。这里黑样本来源于github上的开源仓库,白样本的获取其实有点难度,这里也是搜寻了大量的开源cms,不过白样本依然很少,原因比较简单,一个cms的jsp文件毕竟有限,所以这里唯一比较遗憾的就是数据量的问题。其中黑样本数量为632,白样本数量为470。

最后选取算法,这里参照前文的检测经验,初步选定了xgboost、随机森林、mlp等三种算法,最后经过漫长的调参和比较后,裁定各个算法的最优参数。

实验结果

采用随机算法的检测结果

采用xgboost算发的检测结果

采用mlp算法的检测结果

后记

回头看来,觉得整个实现思路上还是比较简单的,就是可能有几个坑点的确比较烦一点,不过感觉本文只能作为检测jsp/jspx webshell的基本思路,复杂点的还是会被绕过,如果真的想要提高检测精度,自我感觉对参数语义的检测还是非常有必要的!
上述如有不当之处,敬请指出~

关键词:[‘安全技术’, ‘WEB安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now