2. 识别PHP TAG代码区域
0x1: 需要处理的情况
0x2: Code Example
3. MD5 HASH匹配
和传统的AV杀毒一样,使用MD5 HASH精确匹配会面临免杀、绕过的风险,但是在大规模集群环境下,基于大数据得出的AV HASH库就会发挥出相对较好的效果
0x1: 可持续化运维方式
4. 一句话WEBSHELL匹配
在实际的入侵攻防中我们会发现,由于批量工具以及攻击payload常常呈现变形程度梯度上升的趋势,简单形式的一句话占比较高,即
因此,我们可以在检测流程中,增加对一句话小文件的快速匹配,即
0x1: Code Example
5. 字符串+正则规则匹配
0x1: Rule
0x2: Code Example
6. SSDEEP模糊化HASH匹配大马
对于大马来说,使用特征字符串、ssdeep模糊化hash进行聚类分析,能得到较好的效果,并同时得到当前待检测样本的恶意webshell家族分类
0x1: 匹配方案
0x2: Code Example
Relevant Link:
7. PH7(An Embedded Implementation of PHP (C Library))
PH7 is a in-process software C library which implements a highly-efficient embeddable bytecode compiler and a virtual machine for the PHP programming language. In other words, PH7 is a PHP engine which allow the host application to compile and execute PHP scripts in-process PH7是一个进程中的开发包(SDK),实现了高效的嵌入式的字节码编译器和一个PHP编程语言的虚拟机。换一种说法: PH7是一个轻量级的PHP引擎,可让你的C/C++应用程序直接编译并执行PHP脚本,需要注意的是,PH7并不是一个词法/语法优化器,它并不能对脚本文件进行预处理(拼接、参数传递回溯、函数调研回溯),而是直接进行了编译中间代码,并模拟动态执行PH7 implements most of the constructs introduced by the PHP 5.3 release such as heredoc, nowdoc, gotos, classes, anonymous functions, closures and so on and introduces very powerful extensions to the PHP programming language such as:
As an embedded interpreter, it allows multiple interpreter states to coexist in the same program, without any interference between them. Programmatically, foreign functions in C/C++ can be added and values can be defined in the PHP environment. Being a quite small program, it is easy to comprehend, get to grips with, and use.
0x1: Test Example Code: How To Use PH7
0x2: PH7 Engine
0x3: Compiled PHP program
static sxi32 ProcessScript
PH7_CompileScript(pVm,&(*pScript),iFlags);
static sxi32 PH7_CompilePHP
compile编译完成之后,PHP代码就被PH7编译为了中间代码opcode,这些opcode以字节码的形式保存在内存中
0x4: dynamic execute preparerc = PH7_VmMakeReady(pVm);
0x5: 动态执行
ph7_vm_exec(pVm, 0)
rc = PH7_VmByteCodeExec(&(*pVm));
VmByteCodeExec(&(*pVm),(VmInstr *)SySetBasePtr(pVm->pByteContainer),pVm->aOps,-1,&pVm->sExec,0,FALSE);PHP Opcode是一种类似于汇编的中间语言,每个语句块都由多个"状态"成员组成(汇编特征),PH7根据这些状态进行相应的"跳转",即动态执行opcode
Relevant Link:
8. 基于危险函数Hook的恶意污点数据追踪:WEBSHELL检测
需要注意的是,PHP、Zend和PH7对大小写敏感问题的处理存在差异
需要对PH7的词法解析compile过程做一些hack处理,使之匹配Zend的函数调用大小写不敏感特性
0x1: Hook方案
0x2: 外部参数污点打标
PH7_PRIVATE sxi32 PH7_HashmapCreateSuper(ph7_vm *pVm)这里负责创建$_POST、$_GET等全局变量并插入到$_GLOBAL超全局数组中,我们需要在初始化的同时,往$_POST、$_GET等全局变量中插入魔法键值
0x3: 数组元素取值污点(伪造数据)标记
0x4: eval函数污点分析
从webshell变形执行的本质来看,instructions eval($_Payload)是它的本质形态,在大多数情况下,webshell都需要从外部变量($_POST、$_GET..)中获取指定的键值,即获取Payload或,通过指令管道得以执行,不管eval中的payload经过了怎样的变形,在vm_builtin_eval函数中看到的永远都是最后的原始形态,这也是动态沙箱检测相比于静态特征检测最大的优势基于这种理论,我们对vm_builtin_eval敏感函数进行参数检测,如果在其中找到了魔法数键值,说明当前变量是外部传入的变量,则判定为恶意行为
0x5: 需要解决的变形场景
除了最基本的在eval函数中进行污点标记分析,PHP中还有例如动态执行、preg_replace /e、callback等方式可以作为WEBSHELL构造方式执行代码,接下来逐case分析
1. 已识别
2. 未识别
0x6: 危险函数污点分析
1. assert
assert是一个断言函数,它同时具有代码执行的能力,对于assert这个函数,我们要分情况讨论
code
2. system: PH7不支持此词法3. exec: PH7不支持此词法3. passthru: PH7不支持此词法4. shell_exec: PH7不支持此词法5. proc_open: PH7不支持此词法6. popen: PH7不支持此词法
这些命令执行函数的利用只有两种方式
0x6: 动态函数执行污点分析
PHP的动态函数执行属于极其非常规的编码方式,一旦出现,则可以认为是高危WEBSHELL行为,在WEBSHELL变形中,动态函数执行有以下几种
对于第一种情况,我们需要在PH7的"函数执行"流程中进行Hook,在"case PH7_OP_CALL"中,用于动态执行的函数已经被PH7翻译为了最终的函数名字符串,如果是通过外部参数传入的,则此时就是被污点打标的字符串
0x7: require、require_once、include、include_once文件流引入污点分析(LFI)
WEBSHELL的一种变形方式是使用外部输入文件流作为Payload的输入,即俗称的LFI漏洞,当include的参数来自外部参数,则判定为恶意,需要Hook的点包括
code
0x8: 系统输出缓存污点分析
ob_start()会把自己接收到的字符串当作一个"回调函数callback_func",并将接下来的缓冲区输入,当作这个"回调函数"的参数对于ob_start()、 ob_end_flush()的污点分析,需要分几种情况讨论
针对第二种情况,我们在ob_start进行敏感函数检测
0x9: 通过eval注册的匿名动态函数污点分析
这种情况比较特殊,见下面的例子
整个执行流程大致如下
在这个过程中,lambda匿名函数通过eval注册的过程中,如果传入的函数逻辑是: eval($_POST[1]);,PH7会对$_POST进行污点标记,从而使WEBSHELL暴露出污点特征
0x10: 序列化、反序列化特性污点检测
PHP的内核是基于C/C++实现的,在PHP中声明一个类,本质上是声明了C++的类,它同样遵循继承、多态的原则。需要明白的是,PHP中声明的类,默认都包含有构造函数、析构函数,在调用serialize、unserialize的时候,PHP Zend会自动调用对应的构造/析构函数需要特别注意的是,PH7内核对于json_encode/erialize、json_decode/unserialize采用了相同的函数是实现翻译执行,但是json_encode/json_decode却不能被用于webshell变形,所以我们在进行Hook的时候需要对这种情况进行过滤
0x11: PHP的本地变量注册函数污点检测
PHP支持将字符串(可以是外部传入参数)解析成多个变量,这让WEBSHELL有能力将外部传入的参数转化为本地命名空间中的变量,常见的实现这一目的的方式有
1. parse_str: PH7不支持此语法
2. foreach(..) { $$key = $value; }: PH7不支持此语法
需要注意的是,extract传入的是一整个数组(而不是某个具体的键值),对应于vm_builtin_extract中传入的是一整个hashmap,这样,我们针对键值的污点打标,在vm_builtin_extract中就无法直接看到,而是要等到对hashmap解析完毕后才能看到特征,由于受到解析流程的影响,用于打标的污点字符串受到了裁剪
0x12: 逻辑型WEBSHELL污点分析
沙箱的本质是按照待检测样本的逻辑,模拟Zend进行模拟执行,WEBSHELL为了规避沙箱的检测、并且隐藏自己不被管理员正常访问到,会对恶意WEBSHELL代码进行逻辑化处理(If条件判断)
对于逻辑型后门来说,判断进入哪个流支的控制开关(变量)常常是外部传入的参数,这样黑客才能通过传参控制是否进入WEBSHELL的流支,我们可以通过检测在if、while的条件表达式中,是否检测到污点标记(来自外部参数),以此来判断是否要进入流支的依据
0x13: PHP自定义函数call_user_func回调污点分析
Hook Code
0x14: VFS、网络、数据库等危险API进行stub处理为了防止模拟执行中,PH7执行了危险函数,对本机造成了实际影响(例如写文件、发起数据库连接),需要对PH7中这些敏感函数进行stub处理,当执行到这些危险函数的时候,直接忽略跳过
1. 文件操作
高危操作重放风险
0x15: 客户端沙箱性能控制
可能引起沙箱性能问题的API
如果黑客故意构造如下代码,可能会导致沙箱hang住,从而让其他的webshell都过沙箱检测
为此,需要对sleep进行stub处理,同时检测for循环的次数,当超过一定阈值的时候,强制跳出循环
9. 待解决的问题
0x1: ob_start误报
在实际的业务场景中,ob_start、ob_end_clean被用来做HTML页面缓存,所以会造成误报
0x2: incldue误报
从攻防角度来看,include $GPC变量可以导致LFI WEBSHELL
解决方案是对include的参数进行"全等匹配"(即不能有其他字符串),即只有: include $_POST['op']; 这种形式才可以认定为WEBSHELL
0x3: 外部GPC不可控参数污点误打标
VM沙箱检测的思想是对$_SERVER、$_POST、$_GET、$_REQUEST这些GPC的全部参数进行污点打标,然后在关键执行流进行Hook,检测是否发现污点标记,但是实际上,PHP中有一些GPC参数是外部不可控的,在进行污点打标的时候应该过滤掉这些参数
Relevant Link:
0x4: unserialize hook误报
在wordpress中普遍存在这种反序列化的代码案例,wordpress常常将用户配置信息序列化后保存在Cookie中,再通过客户端表单回传回来,所以如果直接通过检测unserialize调用参数中是否存在污点标记会导致大量误报,解决方案可能可以采取"多条正则匹配"技术,即对同一条规则设置多条正则,必须同时满足所有正则后方可认为命中此规则
0x5: 对运算符支持不全导致漏报
这个webshell同时使用了~和^运算符,但是ph7不支持^运算符的解析,导致检测失败
0x6: extract Hook导致误报
extract()常常在CMS中被用来进行外部参数自动化注册,但是也常常被WEBSHELL用俩进行参数隐藏,即将实际产生攻击的指令和payload都通过外部参数传入并通过extract本地注册,因此extract只是这种webshell触发攻击的一个必要不充分条件
本质上,extract这个函数是不应该加Hook点的
0x7: 借助编码、加密函数隐藏的大马SHELL
对于一句话变形来说,不管攻击者使用了何种变形隐藏方式,最终代码执行流都会到达VM Hook点,但是WEBSHELL对抗还有另一个问题就是大马,这类WEBSHELL并不会调用到一句话木马常用的函数,所以也不会被沙箱检测到
解决这种类型的大马的方案思路如下
0x8: 通过逻辑判断隐藏后门
黑客可以将畸形WEBSHELL放在例如IF条件语句中,如果VM沙箱不能预处理源代码的编译后汇编逻辑,使之进入所有流支,可能会导致漏报,但同时进入所有流支又可能带来性能损耗等原因
0x9: PHP的序列化、反序列化特性布置后门
这种WEBSHELL的检测难点在于误报和检测效果的权衡,引入例如wordpress在内的CMS会将序列化后的数据通过GPC方式传入,这个时候使用VM检测,就会在unserialize这个Hook点检测到污点标记,从而造成误报
0x10: 利用运算符进行编码转换隐藏的WEBSHELL
轻量级沙箱很难完全模仿PHP实现一个全集的运算符集和语法规约,这种WEBSHELL最好的方案是用多正则进行检测
0x11: filter_var、array_xx Hook导致误报
在正常的CMS代码中普遍存在这种接收外部参数,对其进行callback、filter等代码逻辑,解决方案如下