Dentro de un lenguaje de programación, ejecuto un comando de shell simple
cd var; echo > create_a_file_here
con var es una variable que contiene una cadena de (con suerte) un directorio al lugar donde quiero crear el archivo "create_a_file_here". Ahora, si alguien ve esta línea de código, es posible explotarla asignando, por ejemplo:
var = "; rm -rf /"
Las cosas pueden ponerse bastante feas. Una forma de evitar el caso anterior sería quizás buscar en la cadena en var algunos caracteres especiales como ';' antes de ejecutar el comando de shell, pero dudo que esto cubra todos los posibles exploits.
¿Alguien sabe una buena manera de asegurarse de que "cd var" solo cambie un directorio y nada más?
shell-script
shell
ES___
fuente
fuente
var
como argumento. Por ejemplo, llamandosh
con argumentos-c
,'cd "$1"; echo > create_a_file_here'
,'sh'
,var
obras y no necesita ningún cambiovar
. El'sh'
argumento se pasa como$0
.sh
o estás creando tu propio lenguaje de programación con una sintaxis similar pero que se expande envar
lugar de requerir que escribascd "$var"
? ¿O es estobash
conshopt -s cdable_vars
? Oh, creo que quiere decir que algún otro programa bifurca un shell para ejecutar estos comandos. Así que solo citavar
, pero asegúrate de que no incluya un personaje de cita en sí ...s='"'; echo "$s"
impresiones"
.var=untrusted string
en el programa padre, por lo quevar
es una variable de entorno que ya está establecida al invocarsh
. Entonces solo necesita citarlo cada vez que lo expande, lo cual es posible de manera confiable. Ah, veo que esa idea ya es parte de la respuesta de Stéphane>. <Respuestas:
Si entiendo correctamente,
var
es una variable en su lenguaje de programación.Y en su lenguaje de programación, le está pidiendo a un shell que interprete una cadena que es la concatenación de
"cd "
, el contenido de esa variable y"; echo > create_a_file_here"
.Si es así, sí, si el contenido de
var
no está estrictamente controlado, es una vulnerabilidad de inyección de comando.Puede intentar citar correctamente el contenido de la variable¹ en la sintaxis del shell para que se garantice que se pase como un argumento único al
cd
builtin incorporado.Otro enfoque sería pasar el contenido de esa variable de otra manera. Una forma obvia sería pasar eso en una variable de entorno. Por ejemplo, en C:
Esta vez, el código que le pide al intérprete que interprete es fijo, aún necesitamos escribirlo correctamente en la sintaxis del intérprete (aquí se supone que es un intérprete compatible con POSIX):
-P
paracd
hacer un simplechdir()
--
marcar el final de las opciones para evitar problemas alvar
comenzar-
(o+
en algunos shells)CDPATH
la cadena vacía en caso de que esté en el entornoecho
comando sicd
se ha realizado correctamente.Hay (al menos) un problema restante: si
var
es así-
, no entra en el directorio llamado-
sino en el directorio anterior (como está almacenado$OLDPWD
) yOLDPWD=- CDPATH= cd -P -- "$DIR"
no se garantiza que funcione a su alrededor. Entonces necesitarías algo como:¹ Tenga en cuenta que simplemente hacer un no
es el camino a seguir, solo estaría moviendo el problema.system(concat("cd \"", var, "\"; echo..."));
Por ejemplo, a
var = "$(rm -rf /)"
todavía sería un problema.La única forma confiable de citar texto para shells tipo Bourne es usar comillas simples y también cuidar las comillas simples que pueden aparecer en la cadena. Por ejemplo, gire a
char *var = "ab'cd"
achar *escaped_var = "'ab'\\''cd'"
. Es decir, sustituir la totalidad'
de'\''
y envolver todo el interior'...'
.Que todavía asume que esa cadena entre comillas no se utiliza dentro de acentos abiertos, y todavía necesitaríamos el
--
,-P
,&&
,CDPATH=
...fuente
Solución simple: no llame al shell desde su programa. En absoluto.
Su ejemplo aquí es trivial, cambiar el directorio y crear archivos debería ser fácil en cualquier lenguaje de programación. Pero incluso si necesita ejecutar un comando externo, generalmente no es necesario hacerlo a través del shell.
Entonces, por ejemplo, en Python, en lugar de ejecutar
os.system("somecmd " + somearg)
, usesubprocess.run(["somecmd", somearg])
. En C, en lugar desystem()
, usefork()
yexec()
(o busque una biblioteca que lo haga).Si necesita usar el shell, cite los argumentos de la línea de comando o páselos por el entorno, como en la respuesta de Stéphane . Además, si te preocupa el carácter especial, la solución correcta es no tratar de filtrar (lista negra) los caracteres potencialmente peligrosos, sino solo mantener los caracteres que se sabe que son seguros (lista blanca).
Solo permita los personajes cuyas funciones sí conoce, de esa manera hay menos riesgo de perder algo. El resultado final puede ser que solo decidas permitir
[a-zA-Z0-9_]
, pero eso podría ser suficiente para hacer el trabajo. También es posible que desee verificar que su configuración regional y su conjunto de herramientas no incluyan letras acentuadas comoä
yö
en eso. Probablemente no sean considerados especiales por ningún shell, pero de nuevo, es mejor asegurarse de que pasen o no.fuente
[a-zA-Z0-9]
no incluya cosas comoà
cuya codificación también podría ser malinterpretada por algunos shells (comobash
) en algunos entornos locales.Dentro de un lenguaje de programación, debería haber mejores formas de hacer cosas que ejecutar comandos de shell. Por ejemplo, reemplazar
cd var
con el equivalente de su lenguaje de programaciónchdir (var);
debería garantizar que cualquier truco con el valor devar
solo dé como resultado un error de "Directorio no encontrado" en lugar de acciones involuntarias y posiblemente maliciosas.Además, puede usar rutas absolutas en lugar de cambiar directorios. Simplemente concatene el nombre del directorio, la barra diagonal y el nombre de archivo que desea usar.
En C, podría hacer algo como:
¿Seguramente tu lenguaje de programación puede hacer algo similar?
fuente