Backdoor in your Java application

I recently came across an article describing the simplest groove that allows you to execute any Groovy code on your server. It seemed to me very convenient for organizing a debug backdoor.

The problem is that grooves are still a server, and we still have a thick Swing client. For him, I would like to do something similar, but embedding some embedded Jetty or Tomcat just for this in the client looked like that too.

Fortunately, another article caught my eye - about the presence of a simple web server in the standard Java library . So I decided to use it.

We write Main:

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


We continue to write on grooves, it’s easier :)

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)
        }
    }

}



Now the HTTP request handler itself:

/**
 * Этот уровень абстракции мне нужен чтобы его же вызывать и из грувлета - для бэкдора на сервере
 * В грувлете способ получения текста скипта, 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>" : ""}

                   """
    }

}


We start, it works!

image