基于AST的webshell检测

admin 2022年4月25日20:55:42评论10 views字数 5038阅读16分47秒阅读模式
0x01 Webshell介绍

webshell是攻击者使用的恶意脚本,其目的是方便攻击者对已经受到攻击的WEB应用程序进行持久控制。webshell本身不能攻击或利用远程漏洞,因此它始终是攻击产生的结果。

攻击者可以利用常见的漏洞,如SQL注入、远程文件包含(RFI)、FTP、命令执行,甚至使用跨站点脚本(XSS)作为攻击的一部分,以上传webshell。webshell的通用功能包括但不限于shell命令执行、代码执行、数据库枚举和文件管理。

webshell通常包含一个后门,允许攻击者远程访问,并能在任何时候控制服务器。这样攻击者省去了每次访问被攻击服务器需要重新利用漏洞的时间。攻击者也可能选择自己修复漏洞,以确保没有其他人会利用该漏洞。这样,攻击者可以保持低调,避免与管理员进行任何交互。值得一提的是,一些流行的webshell使用密码验证和其他技术来确保只有上传webshell的攻击者才能访问它。这些技术包括将脚本锁定到特定的自定义键值对、HTTP头、特定的cookie值、特定的IP地址或这些技术的组合。

文件格式webshell发展史:Web服务器管理页面——> 大马——>小马拉大马——>一句话木马——>加密一句话木马。

下图为webshell分类:

基于AST的webshell检测

0x02 AST介绍

AST是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构, 它产生于编译过程中语法分析阶段,由词法分析阶段的Token单元组合而来,然后再经过语义分析阶段、中间代码生成阶段转化成目标机器可识别的机器码。

由于编程语言的本质往往是模棱两可的。为了避免这种歧义可通过抽象语法树提高代码可读性,并对代码进行语义分析,赋予其抽象的属性,同时AST中不包含无关紧要的标点符号和分隔符(大括号、分号、圆括号、空格、换行等),当前webshell的混淆手法基本是将恶意代码进行拆解分散到整个文件,通过遍历AST中节点的属性对代码进行相应的处理,当其属性属于定义中混淆手法中种类时,对其进行处理,最终实现解混淆。

基于AST的webshell检测

0x03 AST检测技术的优势
静态检测通过匹配特征码,特征值,危险函数函数来查找webshell的方法。新型加密webshell一句话木马通过混淆对恶意文件特征进行拆解,将恶意文件特征分散到整个文件,导致漏报率会比较高,但是如果规则完善,可以降低误报率,但是漏报率必定会有所提高。
流量特征检测通过对webshell的流量特征进行分析,在流量层进行检测。新型加密webshell可以通过在代码中可插入任意编码解码等加密手段对流量特征进行隐藏,从而避免流量层的特征检测,而且往往特征被发现后对加密手段进行修改即可重新修改特征,从而绕过流量层的特征检测。
基于AST的webshell检测技术通过语义分析对代码进行格式化处理,赋予代码各种属性并对代码进行分类处理,以机器语言的角度拆解代码,针对各种混淆手段进行逆向分析最终将分散在整个文件中的恶意特征重新组合,从而在webshell检测中实现低漏报、低误报,甚至是零误报。
通过AST技术可以有效提高webshell的检测率,同时减少误报率。以Github上某份恶意样本为例,某盾查的检测率为101/134/260(后门/疑似/文件总数),某马查杀的检测率为175/15/260(后门/疑似/文件总数)。

基于AST的webshell检测

使用AST技术进行检测,检测率为215/260(后门/文件总数),相对比前两者,有了明显提高。

基于AST的webshell检测

0x04 AST效果

       首先来看下AST的优势处理场景,能够做到一个什么样的效果。

1、变量替换

# 处理前<?php $a =  'assert';$a($_GET['cmd']);  ?> # 处理后 $a = 'assert';assert($_GET['cmd']);

2、二元运算求解

# 处理前<?php$a = 'a'.'s'.'s'.'e'.'r'.'t';$a($_GET['cmd']);# 处理后$a = 'assert';assert($_GET['cmd']);

3、编码解码

# 处理前<?php$a = 'eval($_GET['cmd']);';$b = base64_encode($a);eval(base64_decode($b));# 处理后$a = 'eval($_GET['cmd']);';$b =  'ZXZhbCgkX0dFVFsnY21kJ10pOw==';eval('eval($_GET['cmd']);');
0x05 AST检测逻辑
下面以变量替换为例进行AST检测逻辑的说明,AST检测逻辑总共分为三步。

1Parser

通过parser方法将php代码转换为语法树结构

基于AST的webshell检测

$stmts的值
array(2) {  [0]=>  object(PhpParserNodeStmtExpression)#1153 (2) {    ["expr"]=>    object(PhpParserNodeExprAssign)#1152 (3) {      ["var"]=>      object(PhpParserNodeExprVariable)#1150 (2) {        ["name"]=>        string(1) "a"        ["attributes":protected]=>        array(2) {          ["startLine"]=>          int(2)          ["endLine"]=>          int(2)        }      }      ["expr"]=>      object(PhpParserNodeScalarString_)#1151 (2) {        ["value"]=>        string(6) "assert"        ["attributes":protected]=>        array(3) {          ["startLine"]=>          int(2)          ["endLine"]=>          int(2)          ["kind"]=>          int(1)        }      }      ["attributes":protected]=>      array(2) {        ["startLine"]=>        int(2)        ["endLine"]=>        int(2)      }    }    ["attributes":protected]=>    array(2) {      ["startLine"]=>      int(2)      ["endLine"]=>      int(2)    }  }  [1]=>  object(PhpParserNodeStmtExpression)#1160 (2) {    ["expr"]=>    object(PhpParserNodeExprFuncCall)#1159 (3) {      ["name"]=>      object(PhpParserNodeExprVariable)#1154 (2) {        ["name"]=>        string(1) "a"        ["attributes":protected]=>        array(2) {          ["startLine"]=>          int(3)          ["endLine"]=>          int(3)        }      }      ["args"]=>      array(1) {        [0]=>        object(PhpParserNodeArg)#1158 (5) {          ["name"]=>          NULL          ["value"]=>          object(PhpParserNodeExprArrayDimFetch)#1157 (3) {            ["var"]=>            object(PhpParserNodeExprVariable)#1155 (2) {              ["name"]=>              string(4) "_GET"              ["attributes":protected]=>              array(2) {                ["startLine"]=>                int(3)                ["endLine"]=>                int(3)              }            }            ["dim"]=>            object(PhpParserNodeScalarString_)#1156 (2) {              ["value"]=>              string(3) "cmd"              ["attributes":protected]=>              array(3) {                ["startLine"]=>                int(3)                ["endLine"]=>                int(3)                ["kind"]=>                int(1)              }            }            ["attributes":protected]=>            array(2) {              ["startLine"]=>              int(3)              ["endLine"]=>              int(3)            }          }          ["byRef"]=>          bool(false)          ["unpack"]=>          bool(false)          ["attributes":protected]=>          array(2) {            ["startLine"]=>            int(3)            ["endLine"]=>            int(3)          }        }      }      ["attributes":protected]=>      array(2) {        ["startLine"]=>        int(3)        ["endLine"]=>        int(3)      }    }    ["attributes":protected]=>    array(2) {      ["startLine"]=>      int(3)      ["endLine"]=>      int(3)    }  }}
于是我们得到了一个数组,每个值都是单独的语句,于是我们可以通过遍历该数组来从上至下遍历每一条语句,通过if判断当object属性在处理范围内时,对抽象语法树进行修改,或者缓存每条语句中出现的变量或者类或者函数。
2Traverse
Traverse是检测的核心:通过遍历每一个节点,对已定义的类型进行处理。

基于AST的webshell检测

跟进PreProcessing,下图为进入节点和离开节点方法。

基于AST的webshell检测

接下来则是对定义的类型进行处理。

基于AST的webshell检测

以下拿几个php程序中主要的语句类型来举例说明

2.1 简单语句

$a = 'assert'; 属于变量赋值,则把变量a和其值存入缓存,当后续出现变量a时用’assert’对变量a进行替换。

基于AST的webshell检测

$a($_GET['cmd']);属于可变函数的表达式,因为$a有定值则需要将其转换为常量assert。

基于AST的webshell检测

于是我们先对可变函数进行处理,进行变量替换,于是其语法上结构由

Expression-FuncCall-variable变成Expression-FuncCall-name。

基于AST的webshell检测

2.2 函数/类方法

对于白名单中的系统函数以及不存在污点变量的函数调用可以直接执行获取函数结果,比如常用的编码混淆函数.

遇到自定义函数和类方法调用时,开启另一个Traverse遍历函数体,开辟另一个作用域空间用于保存函数中的变量用以保护主函数中的变量不受污染, 函数参数作为两个赋值语句被加入到函数体中, 函数体遍历结束,变量空间会切换回到进入函数体之前的作用域.
比如:
function t($a){       eval($a);}t(“111”)

在解析过程中,t函数的函数体在实际解析过程会变成

function t($a){$a = “111”;eval(“111”)}
对于引用传递的参数需要做额外的处理去改变之前作用域空间的变量值。

基于AST的webshell检测

2.3 条件判断

基于AST的webshell检测

2.4 循环语句

该程序基本实现了循环语句的解释器功能,循环语句要小心循环死循环,所以保险起见,对循环次数做了计数

基于AST的webshell检测

3、webshell研判

定义外部参数为污点,当污点进行传递后如果最终进入危险函数的危险位置则判断该文件为webshell,污点传递的定义则根据Traverse部分中定义的处理类型,进行相应处理。

基于AST的webshell检测

如assert为危险函数,其传入点位置为0,也就是当assert的第一个参数为污点时判断为webshell。

基于AST的webshell检测

0x06 总结
遍历抽象语法树的基本操作来自于PHP-Parser提供的NodeTraverser结构体,通过实现enterNode()和leaveNode()方法,在遍历到节点前后实现定制功能,如:遍历每行PHP代码生成的抽象语法树,记录过程中的变量分配操作,将变量保存在内存中的数组中;在下次使用这个变量时将其表达式从数组中取出,实现跟踪变量表达式的效果,发现预先定义的“危险函数”调用时,将函数参数进行检查和替换,如果其参数是以前记录的参数,就将其表达式代入函数参数,如果遇到了一个“安全操作“,比如,编码解码、加密、字符串操作、二元运算等;如果该操作的所有参数都是常量类型(NodeScalar),将其表达式动态求解。
参考链接

https://github.com/nikic/PHP-Parser

基于AST的webshell检测
END
基于AST的webshell检测

基于AST的webshell检测

长按扫描二维码
关注公众号
发送加群
可以一起交流哦

索隐实验室是长沙火线云网络科技有限公司的安全研究团队之一,索隐寓意发现隐秘的攻击。索隐实验室聚焦威胁检测与分析技术,包括入侵检测、溯源分析、自动化应急响应等方向。

原文始发于微信公众号(火线云安全研究团队):基于AST的webshell检测

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月25日20:55:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   基于AST的webshell检测https://cn-sec.com/archives/942722.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息