-1

I am trying to fragment my custom applications, while keeping the total design standard.
I have recently learned compiling java applications to native exe files on windows with graalvm.

I am thinking of chaging the design from using many complex web-applications to

  • make only one simple web application to serve as a https site,
  • and having only one servlet having only one task "to push the link to relative native exe files", as sth like below
     /**
     * for example url = "https://www.webpage.com/app-one/someNativeApplicationName?param1=value1&param2=value2...";
     * url params is ascii or base64
     */
    public String callNativeApplication(String url) {//
        //CONSTRUCT nativeApplicationFile
        String someNativeApplicationName = parseNativeApplicationNameFromUrl(url);
        Path nativeApplicationsFolder = Path.of("C:\\nativeApplicationsFolder");
        Path nativeApplicationFile = nativeApplicationsFolder.resolve(someNativeApplicationName);

        //CHECK FOR DIR HACK
        nativeApplicationFile = nativeApplicationFile.toAbsolutePath();
        if(!nativeApplicationFile.startsWith(nativeApplicationsFolder)) {
            throw new RuntimeException("ERROR: DIR HACK");
        }

        //CHECK HIDDEN COMMAND HACK
        if (url.chars().filter(ch -> ch == ' ').count() != 0) {
            throw new RuntimeException("ERROR: HIDDEN COMMAND HACK");
        }

        //CONSTRUCT command
        String command = nativeApplicationFile + " " + url;

        //CHECK HIDDEN CHAR HACK
        if (!Charset.forName("US-ASCII").newEncoder().canEncode(command)){
            throw new RuntimeException("ERROR: HIDDEN CHAR HACK");            
        }

        //EXECUTE
        Process p = java.lang.Runtime.getRuntime().exec(command); 
        String reply = fetchReply(p);
        return reply;
    }

and return the outcome as reply.

Will there be any security risk that i should additionally consider. Is it safe to give a go?

  • 2
    Allowing arbitrary command execution is generally seen as dangerous. The reason is that is an attacker manages to be able to alter one of the possible commands or add one, they can later use that to gain more informations or privileges. You are already aware of that because you included 3 tests to try to mitigate the risk of being hacked that way... When it comes to security, the rule is to think that any defence line could be flawed, the reason why we always use a number of them. And best practices recommend to think twice about the possible outcome of any of them being broken... – Serge Ballesta Aug 10 '23 at 06:05
  • ... Said differently you should balance the gain of that possible architecture against the risk. Only you know the exact context. If you are doing that to improve your skill on a dev machine in a protected network, it is probably fine. If you plan to install it on a production server, you should probably think twice about the increase of the attack surface. – Serge Ballesta Aug 10 '23 at 06:10
  • IMHO this is a step in the wrong direction. The overhead of a Java VM is such that you should put more functionality into each one, rather than spinning up new ones for everything. Sounds like a good way to burn up CPU and memory resources to me. – user207421 Aug 10 '23 at 07:22
  • @user207421 hello world is taking 0,02 seconds. I think there is hope for native. If it will work, all the complexity of web-application, will turn into a simple main function. (i tested it from java, not command prompt https://github.com/tugalsan/com.tugalsan.tst.os/blob/main/src/main/java/com/tugalsan/tst/os/Main.java) – Tugalsan Karabacak Aug 10 '23 at 09:33
  • @user207421 And actually I fragmented one web app to 20+ ones. Although the memory consumption is not an issue for a 2023 server, but it is for a 2003 server. Making native will use less memory then a monolith – Tugalsan Karabacak Aug 10 '23 at 09:42
  • I figured, multiple command can be run without the need of space on command prompt with & char. like "c:\dir&cls" works. So I need to figure out a way to pass input params in more secure way, like base64 conversion or sth else. See "https://techviral.net/run-multiple-commands-in-cmd/". At the same time it need to respect char count. https://stackoverflow.com/questions/3205027/maximum-length-of-command-line-string – Tugalsan Karabacak Aug 10 '23 at 13:29

2 Answers2

0

There are some great remarks in the comments about why letting users execute arbitrary shell code is a bad idea. However, there are some ways you can make it at least a bit safer. For example, you could restrict the endpoint to a hardcoded set of commands, using an enum:

public enum Command {
    ONE("C:/nativeApplicationsFolder/one.exe"),
    TWO("C:/nativeApplicationsFolder/two.exe"),
    ;

    private final String path;

    Command(String path) {
        this.path = path;
    }

    public String getPath() {
        return path;
    }
}

This way, you can easily check that the command is something you know is safe. Be careful, still: If you need the user to pass command line arguments, you now need to be careful again that the user doesn't access files or other applications you don't want them to.

Jorn
  • 20,612
  • 18
  • 79
  • 126
  • I tried to run this code java.lang.Runtime.getRuntime().exec("c:\\nativeApplicationsFolder\\java.exe"); where java.exe is not there but somewhere else accesable from anywere (Environment Variables > Path). But it gave error saying it cannot execute as the file is not that specific location. So I think, it is not needed to make the application names strict. – Tugalsan Karabacak Aug 10 '23 at 09:29
0

I am convinced that executing shell code with url is a bad idea.
There is so many things that can go wrong. Please see here.

Rather than dealing with all security checks for terminal execution, It is probably a better solution:

  • to input the url string to a database row,
  • then call the native exe with row id accordingly.
String command = nativeApplicationFile + " " + 1234;
 /**
     * for example url = "https://www.webpage.com/app-one/someNativeApplicationName?param1=value1&param2=value2...";
     * url params is ascii or base64
     */
    public String callNativeApplication(String url) {//
        //CONSTRUCT nativeApplicationFile
        String someNativeApplicationName = parseNativeApplicationNameFromUrl(url);
        Path nativeApplicationsFolder = Path.of("C:\\nativeApplicationsFolder");
        Path nativeApplicationFile = nativeApplicationsFolder.resolve(someNativeApplicationName);

        //CHECK FOR DIR HACK
        nativeApplicationFile = nativeApplicationFile.toAbsolutePath();
        if(!nativeApplicationFile.startsWith(nativeApplicationsFolder)) {
            throw new RuntimeException("ERROR: DIR HACK");
        }

        //CHECK IF FILE EXISTS
        if(!isFileExists(nativeApplicationFile)) {
            throw new RuntimeException("ERROR: FILE NOT FOUND");
        }

        //CONSTRUCT command
        var rowId = pushUrlToDB(url);
        String command = nativeApplicationFile + " " + rowId;

        //EXECUTE
        Process p = java.lang.Runtime.getRuntime().exec(command); 
        String reply = fetchReply(p);
        return reply;
    }