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
分析
cloudwalker是什么?
牧云(CloudWalker)开源手记 | Webshell 监控检测策略初探
牧云(CloudWalker)开源|如约而至: Webshell核心检测引擎
这两篇官方文章其实已经把检测策略介绍过了,总结起来包括四类:
- 基于模糊哈希
- 基于模糊正则
- 基于代码风格
- 基于机器学习:模型使用svm,特征包括了三个维度(代码风格、操作序列、操作名)
模糊哈希
是什么?
用
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比较容易绕过,线上则难度大很多。