webshell 介绍
webshell 是以常见的编程语言(PHP,JAVA,ASP,ASPX或者cgi)编写的网页文件,最初的目的是为了方便网站管理、服务器管理、权限管理等,使用方法简单,只需写短短几行代码,并且通过网址访问就可进行日常操作,极大的方便了使用者对网站和服务器的管理。因为其方便小巧的特性,如今转变成恶意后门来使用,已达控制网站服务器的目的.
webshell 种类
p牛在19年kcon大会上的议题PHP动态特性的捕捉与逃逸中,把webshell分成了如下几类:

PHP动态特性的捕捉与逃逸
直接型
直接型言简意赅,直接通过http请求传递要执行的代码
回调型
利用回调函数如call_user_func、array_map等,这里就体现了php的灵活,一段不确定功能的代码,变量值的改变可以导致这段代码发生功能上的变化。
变形型
对webshell中的一些变量名、恶意代码,进行混淆、加密、压缩等操作,以达到被查杀的目的。
命令型
也很好理解,直接通过popen和系统进程通信执行命令,常见的如system、shell_exec、反引号等等
包含型
包含型可能是最不容易被查杀的手段,至少静态查杀没有有效的方法,通过包含恶意代码执行的方式将结果带出,日常开发中也有很多地方用到包含的函数如require、include_once等等,从开发的角度看,包含型的webshell没有什么明显的特征,只能从流量侧进行查杀。
技巧型
利用对php的一些特性执行恶意代码,如preg_replace \e 执行任意代码、或者利用php的base64_decode函数的容错性。
针对回调型webshell的检测
针对回调型后门,一般可以用遍历AST Tree、判断回调参数是否是变量、分析FuncCall Node,判断是否调用了含有回调参数的函数。
php是一个很神奇的语言,若检测引擎对函数名进行黑名单检测,大部分编程语言的关键字都是大小写敏感,但php可以对函数进行大小写绕过而不改变函数的用法如
uSoRt($_POST[1],$_POST[2]);
当然大部分检测引擎不会犯这么低级的错误。
别名函数
一些函数在php官方文档搜不到,但实际上是一些函数的别名如 mb_ereg_replace、mb_eregi_replace的别名函数,mbereg_replace 、mbereg_ireplace,他们的作用和preg_replace一样,在/e模式下可以执行任意代码,在PHP7删除了preg_replace的/e模式之后,mb_ereg_replace的/e模式依然能用,因此可以构造含有别名函数的webshell以达到绕过的目的
mbereg_replace(‘.*’, ‘\0’, $_REQUEST[2333], ‘mer’);
不过,mbereg_replace这个别名在PHP7.3被移除了,所以上述代码只能在7.2及以下的PHP中使用。
重命名函数
PHP5.6开始引用函数名的命名空间,可以用
use function A as B
的形式导入A函数,实际写webshell的效果如下:
1 |
|
匿名类与类的继承
类似重命名函数,类的继承也可以理解为一种”重命名”。子类拥有父类的所有方法,也可以做所有父类支持的操作。具体的代码实现如下
1 | class test extends ReflectionFunction {} |
变长参数
变长参数是PHP5.6引入的新特性,即在PHP中可以使用func(...$arr)这样的方式,将$arr数组展开成多个参数传入func函数。配合回调后门可变形如下
1 |
|
请求的时候/test.php?1[]=test&1[]=var_dump($_SERVER);&2=assert即可
控制字符
对于一些PHP的AST解释引擎如PHP-Parser和正常的PHP的引擎有一些区别,正常的PHP引擎会忽略控制字符,正确执行PHP函数,而PHP-Parser无法正确解析包含控制字符的函数。
控制字符范围
1 | [\x00-\x20] |
所有可以构造带有控制字符的webshell可以绕过一些具有语法解析的webshell检测引擎
1 |
|
PHP标签
打CTF的经常遇到,如果过滤了<?php,可以用<script languagt="php">构造webshell上传绕过限制。

技巧型拓展
利用php扩展库
1 |
|
无字母数字的webshell
1 |
|
利用base64_decode特性
前阵子在代码审计星球,P喵呜师傅分享了个trick,php的base64_decode函数的容错性很高,即使在一段标准的base64字符串中乱加内容(一些特殊字符),该函数依然能正确解析,因此可以衍生出包含垃圾字符的webshell
1 |
|
对base64_decode特性的思考
因为打CTF打多了,对base64比较熟悉,突然想到,能否把base64和misc中常见的base64隐写结合起来,把代码隐藏在base64加密的后4位字符中。理论是可行的,但经过实验,发现一些难点,首先,base64隐写容错性太低,一段简单的话,需要生成大量的base64字符串表示,如果像蚁剑一样,每次将要执行的代码经过base64隐写再发送到服务器,数据内容会过于臃肿,若再执行一些上传操作或浏览数据库数据的功能,恐怕服务器后端会处理不了大量数据而将数据包舍弃。