Backdoor в вашем приложении на Java

в 10:52, , рубрики: backdoor, groovy, http server, java, отладка, метки: , , , ,

Я недавно наткнулся на статью, описывающую простейший грувлет, позволяющий исполнить любой код на Groovy у Вас на сервере. Мне это показалось очень удобным для организации отладочного бэкдора.

Проблема в то, что грувлеты — это всё таки сервер, а у нас есть еще толстый клиент на Swing. Для него мне хотелось бы сделать нечто похожее, но встраивание какого нибудь embedded Jetty или Tomcat только для этого в клиент выглядело как то слишком.

По счастью, мне попалась на глаза и другая статья — про наличие в стандартной библиотеке Java простейшего веб сервера. Вот им то я и решил воспользоваться.

Пишем Main:

public class Main {
    public static void main(String[] args) {
        // Порт может задаваться аргументом комадной строки, или как нибудь еще
        HttpBackdoorRunner runner = new HttpBackdoorRunner(18999, true);
        runner.start();
    }
}

Продолжаем писать на груви, так легче :)

import com.sun.net.httpserver.HttpServer
import java.util.concurrent.Executors

/**
* Класс для запуска сервера с нашим хендлером (встроенный сервер - он не сервлет контейнер!)
*/
class HttpBackdoorRunner {

    final int port
    final boolean silent

    HttpBackdoorRunner(int port, boolean silent) {
        this.port = port
        this.silent = silent
    }


    def start() {
        try {
            InetSocketAddress addr = new InetSocketAddress(port);
            HttpServer server = HttpServer.create(addr, 0);

            server.createContext("/", new BackdoorHandler());
            server.setExecutor(Executors.newCachedThreadPool(
            ));
            server.start();
        }
        catch(Exception e) {
            if (silent) {
                // Ignore
            }
            else throw new RuntimeException(e)
        }
    }

}

Теперь сам обработчик HTTP запросов:

/**
 * Этот уровень абстракции мне нужен чтобы его же вызывать и из грувлета - для бэкдора на сервере
 * В грувлете способ получения текста скипта, URI и стрима на вывод будут иные, а обработка скрипта - та же
 */
class BackdoorScriptRunner {

    void runScript(script, responseBody, uri) {
        def scriptOutput = new ByteArrayOutputStream()

        if (script) {
            // Redirect output
            def saveOut = System.out

            def stream = new PrintStream(scriptOutput)
            System.out = stream
            try{
                def result = new GroovyShell().run(script, "dynamic.groovy");
            }
            catch (Throwable e) {
                e.printStackTrace(stream);
            }
            System.out = saveOut

        }
        responseBody.println createHTML(uri, script, scriptOutput)
        responseBody.close();
    }

    String createHTML(uri, script, scriptOutput) {
        """
                   <form action="${uri}" method="post">
                   <h2>BackDoor</h2>
                   Code comes here:   <br>
                   <textarea cols="120" rows="5" name="groovyscript">
                                          ${script ? script : ""}</textarea>
                   <br>
                   <input type="submit" value="Go!" />
                   </form>
                   <br>
                   ${scriptOutput.toString() ? "<h2>Output</h2><pre>${scriptOutput}</pre>" : ""}

                   """
    }

}

Запускаем, работает!

image

Автор: javax

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js