webshell检测总结与实例分析

背景

很久之前做过webshell检测方案调研,webshell可以在流量安全产品(比如waf、nids)和主机安全产品(hids)检测。

在流量安全产品常见的检测场景包括:

  • 文件上传接口,比如检查上传的文件名、文件内容
  • webshell访问,比如检查常见的webshell管理工具

在主机安全产品常见的检测场景包括:

  • 文本内容,比如检查所有php文件是否webshell
  • 内存马

根据网络上公开资料总结,”文本内容”检测手段包括:
| webshell检测技术 | 举例
| - | - |
| 动态分析-沙箱 | 百度webdir |
| 静态分析-正则 |
| 静态分析-统计学角度 |
| 静态分析-AST |
| 机器学习/深度学习 |
| RASP | 百度OpenRASP |

长亭开源的cloudwalker检测方式较全,个人觉得值得学习。

本文简要分析cloudwalker的检测手段,应该适合正在调研webshell检测方案的读者阅读。

PS: p牛说他们目前的方案已经和开源版本有非常大的不同,目前方案的线上demo:https://forum.xray.cool/webshell

分析

模糊哈希

  • 是什么?

    ssdeep命令来实践,看一下生成的模糊哈希。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@vm10-50-0-18 ssdeep_test]# ssdeep /usr/bin/sleep /usr/bin/sleep1 -s
    ssdeep,1.1--blocksize:hash:hash,filename
    768:VQ1Q5jc5QNAVo5FWQkckarfJ8JV3XAiqbolRX7:O35Q2Vo5FWkfJ8nXX7,"/usr/bin/sleep"
    768:VQ1Q5jc5QNAVo5FWQkckarfJ8JV3XAiqbolRX7:O35Q2Vo5FWkfJ8nXX7,"/usr/bin/sleep1"
    [root@vm10-50-0-18 ssdeep_test]# echo 11 >> /usr/bin/sleep1
    [root@vm10-50-0-18 ssdeep_test]# ssdeep /usr/bin/sleep /usr/bin/sleep1 -s
    ssdeep,1.1--blocksize:hash:hash,filename
    768:VQ1Q5jc5QNAVo5FWQkckarfJ8JV3XAiqbolRX7:O35Q2Vo5FWkfJ8nXX7,"/usr/bin/sleep"
    768:VQ1Q5jc5QNAVo5FWQkckarfJ8JV3XAiqbolRX7B:O35Q2Vo5FWkfJ8nXX7B,"/usr/bin/sleep1"

    可以看出来,/usr/bin/sleep1 在添加了两个字节的数据后,算出来的模糊哈希虽然和原来的不同,但是很相似。

    所以可以得出结论:如果文件的”模糊哈希”相似,就很可能文件内容非常相似。

  • cloudwalker怎么用”模糊哈希”检测webshell?

    在 tool/webshell-detector/bin/static/model-latest/SampleHash.txt 文件有计算好的”webshell模糊哈希列表”

    在检测文件时,先计算出”检测对象”的模糊哈希,然后和”webshell模糊哈希列表”做相似度比较

    输入图片说明

代码风格

  • 是什么?

    从代码字符串中统计出的如下信息:

    1
    2
    3
    4
    5
    * WM:代码中的单词总数
    * LM:代码行数
    * SPL:代码中的分号数量/总行数
    * SR:符号比例 = 符号长度/总长度
    * ...

    这一部分业务逻辑在 Stat.go

  • cloudwalker怎么用”代码风格”检测webshell?

    statState.json 中允许用户配置”代码风格合理范围”。cloudWalker计算出”检测对象”的”代码风格”后,会检查是否在此范围内。

    另外,”代码风格”信息会作为机器学习模型中的特征。

机器学习

  • cloudwalker怎么用”机器学习”检测webshell?

    使用了两层的机器学习。

    第一层模型使用svm算法,特征包括三类:

    1
    2
    3
    * 前面说的"代码风格"
    * "操作序列模型"的预测结果
    * "操作名称模型"的预测结果

    输入图片说明

  • “操作序列模型”是什么?

    训练好的模型在 tool/webshell-detector/bin/static/model-latest/OpSerial.model

    它使用svm算法,特征是”操作序列”处理后的数据。

    “操作序列”包含了php代码中的”操作特征”。

  • 怎么生成”操作序列”?

    由代码获取到抽象语法树后,再由抽象语法树生成”操作序列”。

    举个例子:

    假设待检测的php代码如下

    1
    <?php eval($_POST[0]);?>

    代码生成的抽象语法树(ast)

    1
    {"status":"successed","ast":{"kind":132,"flags":0,"lineno":1,"children":[{"kind":269,"flags":1,"lineno":1,"children":{"expr":{"kind":512,"flags":0,"lineno":1,"children":{"expr":{"kind":256,"flags":0,"lineno":1,"children":{"name":"_POST"}},"dim":0}}}}]}}

    输入图片说明

    对应的”操作序列”如下:

    输入图片说明

    可以看出来,”操作序列”包含了”抽象语法树”两层之间的联系。

抽象语法树

  • 怎么生成”抽象语法树”?

    代码在 tool/webshell-detector/php 目录。

    流程如下:

    1
    2
    * 在cloudwalker启动时,[php.c](https://github.com/leveryd/cloudwalker-source-read/blob/master/tool/webshell-detector/php/php.c)新建子线程,并等待输入。
    * 子线程接收php代码后,解析生成"抽象语法树",将结果返回给主线程。子线程通过管道与主线程通信。

    解析能力基于php-ast项目,业务逻辑可以见index.php

    可以运行index.php做一点简单的测试:输入包括”字符串长度”和”代码”,输出ast字符串

    1
    2
    3
    4
    5
    ➜  php git:(master) ✗ ./bin/php payload/index.php
    26
    <?php eval('$_POST[0]');?>
    142
    {"status":"successed","ast":{"kind":132,"flags":0,"lineno":1,"children":[{"kind":269,"flags":1,"lineno":1,"children":{"expr":"$_POST[0]"}}]}}

总结

仓库中放了我阅读代码时的注释,方便有需要的读者。

从测试效果来看,开源版本和目前线上版本有很大差异:开源版本cloudwalker比较容易绕过,线上则难度大很多。

输入图片说明