webshell检测方法归纳

时间:2021-12-05 09:48:18

0x00 背景

webshell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称做为一种网页后门。黑客在入侵了一个网站后,通常会将asp或php后门文件与网站服务器WEB目录下正常的网页文件混在一起,然后就可以使用浏览器来访问asp或者php后门,得到一个命令执行环境,以达到控制网站服务器的目的。

 

0x01 webshell检测模型

Webshell的运行流程:hacker -> HTTP Protocol -> Web Server -> CGI。简单来看就是这样一个顺序:黑客通过浏览器以HTTP协议访问Web Server上的一个CGI文件。棘手的是,webshell就是一个合法的TCP连接,在TCP/IP的应用层之下没有任何特征(当然不是绝对的),只有在应用层进行检测。黑客入侵服务器,使用webshell,不管是传文件还是改文件,必然有一个文件会包含webshell代码,很容易想到从文件代码入手,这是静态特征检测;webshell运行后,B/S数据通过HTTP交互,HTTP请求/响应中可以找到蛛丝马迹,这是动态特征检测。

 

0x02 静态检测

静态检测通过匹配特征码,特征值,危险函数函数来查找webshell的方法,只能查找已知的webshell,并且误报率漏报率会比较高,但是如果规则完善,可以减低误报率,但是漏报率必定会有所提高。优点是快速方便,对已知的webshell查找准确率高,部署方便,一个脚本就能搞定。缺点漏报率、误报率高,无法查找0day型webshell,而且容易被绕过。对于单站点的网站,用静态检测还是有很大好处,配合人工,能快速定位webshell,但是如果是一个成千上万站点的大型企业呢,这个时候再人肉那工作量可就大了。所以用这样一种思路:强弱特征。即把特征码分为强弱两种特征,强特征命中则必是webshell;弱特征由人工去判断。加入一种强特征,即把流行webshell用到的特征作为强特征重点监控,一旦出现这样的特征即可确认为webshell立即进行响应。要解决误报和漏报,就不能拘泥于代码级别了。可以换个角度考虑问题:文件系统。我们可以结合文件的属性来判断,比如apache是noboy启动的,webshell的属主必然也是nobody,如果我的Web目录无缘无故多了个nobody属主的文件,这里就有问题了。最理想的办法是需要制度和流程来建设一个web目录唯一发布入口,控制住这个入口,非法进来的Web文件自然可以发现。

笔者基于静态检测的webshell工具 https://github.com/he1m4n6a/findWebshell

 

0x03 动态检测

webshell传到服务器了,黑客总要去执行它吧,webshell执行时刻表现出来的特征,我们称为动态特征。先前我们说到过webshell通信是HTTP协议。只要我们把webshell特有的HTTP请求/响应做成特征库,加到IDS里面去检测所有的HTTP请求就好了。webshell起来如果执行系统命令的话,会有进程。Linux下就是nobody用户起了bash,Win下就是IIS User启动cmd,这些都是动态特征。再者如果黑客反向连接的话,那很更容易检测了,Agent和IDS都可以抓现行。Webshell总有一个HTTP请求,如果我在网络层监控HTTP,并且检测到有人访问了一个从没反问过得文件,而且返回了200,则很容易定位到webshell,这便是http异常模型检测,就和检测文件变化一样,如果非管理员新增文件,则说明被人入侵了。缺点也很明显,黑客只要利用原文件就很轻易绕过了,并且部署代价高,网站时常更新的话规则也要不断添加。还有一个思路利用函数劫持。回忆一下,我们调试网马的时候,怎么还原它各种稀奇古怪的加密算法呢,简单,把eval改成alert就好了。类似的,所以我们可以在CGI全局重载一些函数(比如ASP.Net的global.asax文件),当有webshell调用的时候就可以发现异常。已js为例(php,asp等语言思路一样的,都是保存原函数,然后从新定义原函数,最后在调用保存的原函数),比如下面就是把eval重载,还可以弹出个危险提示等,吓退一些没经验黑客。

<script type="text/javascript">
<!--
var _eval = eval;
eval = function(s) {
if (confirm("eval被调用\n\n调用函数\n" + eval.caller + "\n\n调用参数\n" + s)) {
_eval(s);
}

还有一种和上面思路有异曲同工之妙,上面直接在代码层hook函数,还可以直接修改内核还防御webshell,其实思路是一样的,以php内核为例子。通过php扩展,在内核态hook一些危险函数system,exec,passthru,eval,assert等,然后重编译php。不过代价也很明显,如果一个个编译,大企业几十万台服务器要编译到什么时候,而且必定会减损php性能,这是否有会对业务造成很大影响呢,都是要考虑的现实问题。

 

0x04 日志检测

使用Webshell一般不会在系统日志中留下记录,但是会在网站的web日志中留下Webshell页面的访问数据和数据提交记录。日志分析检测技术通过大量的日志文件建立请求模型从而检测出异常文件,称之为:HTTP异常请求模型检测。例如:一个平时是GET的请求突然有了POST请求并且返回代码为200、某个页面的访问者IP、访问时间具有规律性等。

webshell的访问特征(主要特征)

  1. 少量ip对其发起访问
  2. 总的访问次数少
  3. 该页面属于孤立页面

当然不是所有的孤立页面都是webshell,以下情况也会造成孤立页面
(1)隐藏管理后台等正常孤立页面的访问
(2)扫描器行为,常见漏洞扫描,PoC扫描,Webshell扫描(日志中经常可以看到常见webshell路径加一句话payload的扫描)——这是最主要的干扰数据,需要剔除
对于情况(1)采用白名单的方式,对于情况(2)扫描器识别
(p.s. 爬虫技术、指纹识别技术、扫描器识别(广义的可衍生到人机识别)可以称为web安全技术的三驾马车,总也绕不过去)

优点:采用了一定数据分析的方式,网站的访问量达到一定量级时这种检测方法的结果具有较大参考价值。

缺点:存在一定误报,对于大量的访问日志,检测工具的处理能力和效率会比较低。

 

0x05 语法检测

语法语义分析形式,是根据php语言扫描编译的实现方式,进行剥离代码、注释,分析变量、函数、字符串、语言结构的分析方式,来实现关键危险函数的捕捉方式。这样可以完美解决漏报的情况。但误报上,仍存在问题。

public function startLexing($code)
{
if (preg_match('/<\?(php)?\s*@Zend;[\r\n|\n]+\d+;/', $code)) {
$this->errMsg = 'Encrypt with Zend optimizer.';
return false;
}
$this->resetErrors();
$this->tokens = token_get_all($code);
$this->code = $code;
$this->pos = -1;
$this->line = 1;
return $this->checkError();
}

误报问题所在,一是被检测文件是否为合法php语法文件,token_get_all函数的实现,是不验证是否问合法php语法文件的,只是对其进行扫描,分析。服务器云判断是一种根据恶意代码串的指纹,根据大量后门数据,做语法、语义分析,做业务逻辑分析,理解这段代码的用途,给出其是否为恶意代码的定位,而其他使用者,直接可以得到该代码片段是否为恶意代码的结果反馈。Pecker Scanner首先是基于语法分析,剥离token、注释、字符串、变量、语言结构,再进行php语法检测,提取恶意代码的扫描工具,来解决漏报问题。同时支持服务器云判断,尽量避免误报问题。

基于语法的pecker检测工具

 

0x06 统计学检测

webshell由于往往经过了编码和加密,会表现出一些特别的统计特征,根据这些特征统计学习。
典型的代表: NeoPI -- https://github.com/Neohapsis/NeoPI

NeoPi使用以下五种检测方法:

  1. 信息熵(Entropy):通过使用ASCII码表来衡量文件的不确定性;
  2. 最长单词(LongestWord):最长的字符串也许潜在的被编码或被混淆;
  3. 重合指数(Indexof Coincidence):低重合指数预示文件代码潜在的被加密或被混效过;
  4. 特征(Signature):在文件中搜索已知的恶意代码字符串片段;
  5. 压缩(Compression):对比文件的压缩比

采用这种检测方法也存在明显的弱点,NeoPi的检测重心在于识别混淆代码,它常常在识别模糊代码或者混淆编排的木马方面表现良好。未经模糊处理的代码对于NeoPi的检测机制较为透明。如果代码整合于系统中的其它脚本之上,这种“正常”的文件极可能无法被NeoPi识别出来。

 

0x07 变形、窃密型webshell检测

变形webshell可以由上面所说的统计学NeoPI工具检测,也可以动态检测。比如,一个正常的程序员如果使用eval、system是不会刻意的转换隐藏的,如果发现某个函数执行了,代码中却找不到这个函数名,我们认为这是一个异常行为。所以变形加密也可以用这种方式查找,在日志中找到某个文件执行system等命令,但在原文件中没找到这个文件代码,说明文件是后门文件。

 

针对窃密型Webshell必须具有操作数据库的能力,可以引申出一种新的检测方法,通过分析正常WEB脚本文件和窃密型Webshell对数据库操作的差异进行分析是本检测方法所重点研究的方向。正常情况下WEB站点进行数据操作的过程应该是重复性且较为复杂的查询过程,这种查询通常精确度非常高,查询过程不会出现类似于“select * from”这种查询语句。正常的WEB脚本在进行数据库操作的过程中也不会出现跨越数据库查询的情况,一旦出现这种现象基本可以判断为非正常的WEB脚本操作过程。

就以上思路设计如下的检测方案:

审计数据操作记录。通过审计数据库操作记录可以单独的为每一个WEB站点甚至WEB站点中的每一个脚步文件建立查询请求模型,通过几天甚至数月的自我学习过程来学习并维护一份查询请求数据库。该数据库的内容包含了每次查询操作的详细信息、请求归类和分析结果。并且建立动态查询请求规则,Agent一旦检测到违反该规则的查询请求后会向Server端传递相关信息,Server端再结合其它的扫描过程综合判断发起请求的文件是否为Webshell,并最终决定是否向管理员报警。

 

0x08 总结

没有最好的检测方法,应该根据实际情况和公司业务合理应用。

 

参考资料:

http://drops.wooyun.org/web/7333

http://www.xfocus.net/articles/200712/963.html

http://security.tencent.com/index.php/blog/msg/19

http://old.sebug.net/paper/pst_WebZine/pst_WebZine_0x05/0x08_WebShell%E6%A3%80%E6%B5%8B%E6%80%9D%E8%B7%AF%E6%B5%85%E8%B0%88.html

http://www.sec-un.org/ideas-like-article-espionage-webshell-method.html

http://www.cnxct.com/pecker-scanner-beta-release-support-cloud-confirmation/

http://www.xker.com/page/e2015/07/205961.html

http://www.cnblogs.com/LittleHann/p/3522990.html